From e09f16570c41ae0f910ef208eb4b00a5b648291e Mon Sep 17 00:00:00 2001 From: Shiva Ahir Date: Fri, 13 Dec 2024 10:34:55 -0800 Subject: [PATCH] =?UTF-8?q?Revert=20"Power=20and=20Thermal=20Specification?= =?UTF-8?q?=20for=20RPE=20-=20Front=20end=20(updated)=20#TODO=20(=E2=80=A6?= =?UTF-8?q?"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 27003736f3750baa99599150eb8c13fd59f39602. --- backend/api/device.py | 1 - src/GlobalStateProvider.js | 74 +--- src/components/Tables/PowerSummaryTable.js | 371 ++++----------------- src/components/style/PowerSummaryTable.css | 187 +---------- src/tests/GlobalStateProvider.test.js | 15 +- 5 files changed, 88 insertions(+), 560 deletions(-) diff --git a/backend/api/device.py b/backend/api/device.py index d949dbbc..4b840231 100644 --- a/backend/api/device.py +++ b/backend/api/device.py @@ -312,7 +312,6 @@ def patch(self, device_id : str): device = device_mgr.get_device(device_id) schema = DeviceSchema() device.update_spec(schema.load(request.json)['specification']) - device.compute_output_power() from submodule.rs_project import RsProjectManager RsProjectManager.get_instance().set_modified(True) return schema.dump(device), 200 diff --git a/src/GlobalStateProvider.js b/src/GlobalStateProvider.js index 71634f95..6746dc57 100644 --- a/src/GlobalStateProvider.js +++ b/src/GlobalStateProvider.js @@ -38,16 +38,6 @@ export function GlobalStateProvider({ children, fetch }) { // TODO temp fix for const [bcpuNames, setBcpuNames] = useState([]); const [connectivityNames, setConnectivityNames] = useState([]); const [dmaNames, setDmaNames] = useState([]); - const [thermalData, setThermalData] = useState({ - ambientTypical: 25, - ambientWorseCase: 50, - thetaJa: 10, - }); - const [powerData, setPowerData] = useState({ - powerBudget: 1.0, - fpgaScaling: 25, - pcScaling: 25, - }); let peripheralsMessages = {}; @@ -138,25 +128,6 @@ export function GlobalStateProvider({ children, fetch }) { // TODO temp fix for updatePeripherals(device, item.href, item.type); }); }); - - server.GET(server.deviceInfo(device), (result) => { - if (result && result.specification) { - const { specification } = result; - setThermalData({ - ambientTypical: specification.thermal?.ambient?.typical || 25, - ambientWorseCase: specification.thermal?.ambient?.worsecase || 50, - thetaJa: specification.thermal?.theta_ja || 10, - }); - setPowerData({ - powerBudget: specification.power?.budget || 1.0, - fpgaScaling: - (specification.power?.typical_dynamic_scaling?.fpga_complex || 0) * 100, - pcScaling: - (specification.power?.typical_dynamic_scaling?.processing_complex || 0) - * 100, - }); - } - }); } else { setClockingState([]); setFleState([]); @@ -165,49 +136,9 @@ export function GlobalStateProvider({ children, fetch }) { // TODO temp fix for setIoState([]); setSocState({}); setPeripherals([]); - setThermalData({ - ambientTypical: 25, - ambientWorseCase: 50, - thetaJa: 10, - }); - setPowerData({ - powerBudget: 1.0, - fpgaScaling: 25, - pcScaling: 25, - }); } } - function updateThermalAndPowerData(device, newThermalData, newPowerData) { - const updatedData = { - specification: { - thermal: { - ambient: { - typical: newThermalData.ambientTypical, - worsecase: newThermalData.ambientWorseCase, - }, - theta_ja: newThermalData.thetaJa, - }, - power: { - budget: newPowerData.powerBudget, - typical_dynamic_scaling: { - fpga_complex: newPowerData.fpgaScaling / 100, - processing_complex: newPowerData.pcScaling / 100, - }, - }, - }, - }; - - server.PATCH(server.deviceInfo(device), updatedData, (response) => { - if (response.ok) { - setThermalData(newThermalData); - setPowerData(newPowerData); - } else { - console.error('Error updating thermal and power data:', response.statusText); - } - }); - } - function GetOptions(id) { const found = attributes.find((elem) => id === elem.id); return (found === undefined) ? [] : found.options; @@ -219,7 +150,6 @@ export function GlobalStateProvider({ children, fetch }) { // TODO temp fix for const values = useMemo(() => ({ updateGlobalState, - updateThermalAndPowerData, clockingState, fleState, bramState, @@ -233,10 +163,8 @@ export function GlobalStateProvider({ children, fetch }) { // TODO temp fix for connectivityNames, dmaNames, fetchAttributes, - thermalData, - powerData, // eslint-disable-next-line react-hooks/exhaustive-deps - }), [bramState, clockingState, dspState, fleState, ioState, socState, thermalData, powerData]); + }), [bramState, clockingState, dspState, fleState, ioState, socState]); return ( diff --git a/src/components/Tables/PowerSummaryTable.js b/src/components/Tables/PowerSummaryTable.js index 304de319..a25d9cbb 100644 --- a/src/components/Tables/PowerSummaryTable.js +++ b/src/components/Tables/PowerSummaryTable.js @@ -1,11 +1,11 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import { IoMdCloseCircleOutline } from 'react-icons/io'; import { Tooltip } from 'antd'; import { PowerCell } from './TableCells'; import { fixed, color } from '../../utils/common'; import { State } from '../ComponentsLib'; -import { GET, deviceInfo } from '../../utils/serverAPI'; + import '../style/PowerSummaryTable.css'; function PowerSummaryTableToolTip({ title, statusColor }) { @@ -17,308 +17,91 @@ function PowerSummaryTableToolTip({ title, statusColor }) { ); } - function PowerSummaryTable({ - title, data = [], total = 0, percent = 0, deviceId = 'MPW1', #TODO + title, data, total, percent, }) { - const [thermalData, setThermalData] = useState({ - ambientTypical: 25, - ambientWorseCase: 50, - thetaJa: 10, - }); - - const [powerData, setPowerData] = useState({ - powerBudget: 1.0, - fpgaScaling: 25, - pcScaling: 25, - }); - - const ambientTypicalRef = useRef(null); - const ambientWorseCaseRef = useRef(null); - const thetaJaRef = useRef(null); - const powerBudgetRef = useRef(null); - const fpgaScalingRef = useRef(null); - const pcScalingRef = useRef(null); - - useEffect(() => { - const fetchData = async () => { - try { - // Update the API call to match the correct endpoint - GET(deviceInfo(deviceId), (result) => { - if (result && result.specification) { - const { specification } = result; - - // Process thermal data - setThermalData({ - ambientTypical: specification.thermal?.ambient?.typical || 25, - ambientWorseCase: specification.thermal?.ambient?.worsecase || 50, - thetaJa: specification.thermal?.theta_ja || 10, - }); - - // Process power data - setPowerData({ - powerBudget: specification.power?.budget || 1.0, - fpgaScaling: (specification.power?.typical_dynamic_scaling?.fpga_complex || 0) * 100, - pcScaling: - (specification.power?.typical_dynamic_scaling?.processing_complex || 0) * 100, - }); - } - }); - } catch (error) { - console.error('Error fetching data:', error); - } - }; - - fetchData(); // Trigger the fetch function - }, [deviceId]); // Re-run effect when deviceId changes - - const updateBackend = async (deviceIdParam, thermalDataParam, powerDataParam) => { - const updatedData = { - specification: { - thermal: { - ambient: { - typical: thermalDataParam.ambientTypical || 0, - worsecase: thermalDataParam.ambientWorseCase || 0, // Matches schema - }, - theta_ja: thermalDataParam.thetaJa || 0, - }, - power: { - budget: powerDataParam.powerBudget || 0, - typical_dynamic_scaling: { - fpga_complex: powerDataParam.fpgaScaling || 0, - processing_complex: powerDataParam.pcScaling || 0, - }, - }, - }, - }; - - console.log('PATCH Payload:', JSON.stringify(updatedData, null, 2)); - - try { - const response = await fetch(`http://127.0.0.1:5000/devices/${deviceIdParam}`, { - method: 'PATCH', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(updatedData), - }); - - if (!response.ok) { - throw new Error(`PATCH request failed: ${response.status} ${response.statusText}`); - } - - const result = await response.json(); - console.log('PATCH Response:', result); - } catch (error) { - console.error('Error during PATCH request:', error); - } - }; - - const handleFieldUpdate = (field, value) => { - const updatedThermalData = { ...thermalData }; - const updatedPowerData = { ...powerData }; - - if (field in thermalData) { - updatedThermalData[field] = Number.isNaN(parseFloat(value)) ? 0 : parseFloat(value); - } else { - updatedPowerData[field] = Number.isNaN(parseFloat(value)) ? 0 : parseFloat(value); - } - - setThermalData(updatedThermalData); - setPowerData(updatedPowerData); - - updateBackend(deviceId, updatedThermalData, updatedPowerData); - }; - - const enforceNumericInput = (e) => { - const { value } = e.target; - const valid = /^-?\d*\.?\d*%?$/.test(value); - if (!valid) { - e.target.value = value.slice(0, -1); + function getErrors(messages) { + if (messages === undefined) return []; + const errors = messages.filter((item) => item.filter((inner) => inner.type === 'error').length > 0); + return errors; + } + function getWarning(messages) { + if (messages === undefined) return []; + const warnings = messages.filter((item) => item.filter((inner) => inner.type === 'warn').length > 0); + return warnings; + } + function buildMessage(messages) { + return messages.reduce((sum, item, currentIndex) => { + item.forEach((i, index) => sum.push( + // eslint-disable-next-line react/no-array-index-key + + {i.text} +
+
, + )); + return sum; + }, []); + } + function message(messages) { + const errors = getErrors(messages); + if (errors.length > 0) { + return buildMessage(errors); } - }; - - const handleKeyDown = (e, nextFieldRef) => { - if (e.key === 'Enter' && nextFieldRef && nextFieldRef.current) { - nextFieldRef.current.focus(); + const warnings = getWarning(messages); + if (warnings.length > 0) { + return buildMessage(warnings); } - }; - - const getErrors = (messages) => messages?.filter((item) => item.some((inner) => inner.type === 'error')) || []; - const getWarnings = (messages) => messages?.filter((item) => item.some((inner) => inner.type === 'warn')) || []; - - const buildMessage = (messages) => messages.reduce((acc, item) => { // Removed `currentIndex` - item.forEach((i) => acc.push( - - {' '} - {/* Replace with the unique property */} - {i.text} -
-
, - )); - return acc; - }, []); - - const message = (messages) => { - const errors = getErrors(messages); - return errors.length > 0 ? buildMessage(errors) : buildMessage(getWarnings(messages)); - }; - - const statusColor = (messages) => color( - getErrors(messages).length > 0, - getWarnings(messages).length > 0, - ); - + return ''; + } + + function isError(messages) { return getErrors(messages).length > 0; } + function isWarning(messages) { return getWarning(messages).length > 0; } + function statusColor(messages) { + return color(isError(messages), isWarning(messages)); + } return (
- {title === 'FPGA Complex and Core Power' && ( -
-
Thermal Specification
- - - - - - - - - - - - - - - - - -
- TypicalWorse-Case
Ambient - handleFieldUpdate('ambientTypical', e.target.value)} - onInput={enforceNumericInput} - ref={ambientTypicalRef} - onKeyDown={(e) => handleKeyDown(e, ambientWorseCaseRef)} - /> - {' '} - °C - - handleFieldUpdate('ambientWorseCase', e.target.value)} - onInput={enforceNumericInput} - ref={ambientWorseCaseRef} - onKeyDown={(e) => handleKeyDown(e, thetaJaRef)} - /> - {' '} - °C -
- ΘJA: - handleFieldUpdate('thetaJa', e.target.value)} - onInput={enforceNumericInput} - ref={thetaJaRef} - onKeyDown={(e) => handleKeyDown(e, powerBudgetRef)} - /> - {' '} - °C/W -
- -
Power Specification
- - - - - - - - - - - - -
Power Budget - handleFieldUpdate('powerBudget', e.target.value)} - onInput={enforceNumericInput} - ref={powerBudgetRef} - onKeyDown={(e) => handleKeyDown(e, fpgaScalingRef)} - /> - {' '} - W -
Typical Dynamic Scaling % - FPGA: - handleFieldUpdate('fpgaScaling', e.target.value)} - onInput={enforceNumericInput} - ref={fpgaScalingRef} - onKeyDown={(e) => handleKeyDown(e, pcScalingRef)} - /> - {' '} - % - - PC: - handleFieldUpdate('pcScaling', e.target.value)} - onInput={enforceNumericInput} - ref={pcScalingRef} - /> - {' '} - % -
-
- )} - -
{title || 'FPGA Complex and Core Power'}
+
{title}
- {data.map((item) => ( - - {' '} - {/* Use a unique property like `id` */} - - - - - - - ))} + { + data.map((item, index) => ( + // eslint-disable-next-line react/no-array-index-key + + + + + + + + )) + }
- - {item.text || 'N/A'} - {`${fixed(item.percent || 0, 0)} %`} - - {(getErrors(item.messages).length > 0 - || getWarnings(item.messages).length > 0) && ( - - )} -
{item.text} + {`${fixed(item.percent, 0)} %`} + + { + (isError(item.messages) || isWarning(item.messages)) && ( + + ) + } +
-
- - + +
Total - {` ${fixed(total || 0)} W`} + {` ${fixed(total)} W`}
@@ -327,21 +110,11 @@ function PowerSummaryTable({ PowerSummaryTable.propTypes = { title: PropTypes.string.isRequired, - data: PropTypes.arrayOf( - PropTypes.shape({ - text: PropTypes.string, // Example property - power: PropTypes.number, // Example property - messages: PropTypes.arrayOf( - PropTypes.shape({ - type: PropTypes.string.isRequired, - content: PropTypes.string, - }), - ), // Nested array of objects - }), - ).isRequired, + data: PropTypes.oneOfType([ + PropTypes.array, + ]).isRequired, total: PropTypes.number.isRequired, percent: PropTypes.number.isRequired, - deviceId: PropTypes.string.isRequired, }; export default PowerSummaryTable; diff --git a/src/components/style/PowerSummaryTable.css b/src/components/style/PowerSummaryTable.css index 88a4881c..c98c0c5e 100644 --- a/src/components/style/PowerSummaryTable.css +++ b/src/components/style/PowerSummaryTable.css @@ -1,180 +1,36 @@ -/* Main container for the entire table layout */ .pst-container { - padding: 4px; + padding: 8px; display: flex; flex-direction: column; - row-gap: 2px; + row-gap: 5px; height: 100%; - width: 100%; - box-sizing: border-box; -} - -/* Styling for the Thermal and Power Specification section */ -.thermal-power-specification { - padding: 4px; - background-color: #f0f7f5; - border: 1px solid #d1d1d1; - border-radius: 6px; - margin-bottom: 4px; - display: flex; - flex-direction: column; - row-gap: 4px; - width: 100%; - margin-left: auto; - margin-right: auto; - box-sizing: border-box; -} - -/* Header styling for the Thermal and Power Specification */ -.spec-header { - font-weight: bold; - font-size: 11px; - text-align: center; - color: #333; - background-color: #e1e1e1; - padding: 4px; - border: 1px solid #c0c0c0; - border-radius: 4px; -} - -/* Table styling for the specification sections */ -.spec-table { - width: 100%; - border-collapse: collapse; - margin-bottom: 4px; -} - -.spec-table th, .spec-table td { - padding: 3px; - text-align: center; - border: 1px solid #d1d1d1; - font-size: 10px; -} - -/* Styling for headers in the Typical and Worst-Case columns */ -.spec-table .typical-header, .spec-table .worst-header { - font-weight: bold; - background-color: #f0f0f0; - border-bottom: 1px solid #c0c0c0; -} - -/* Special handling for ΘJA row that spans across two columns */ -.spec-table .theta-row td { - text-align: center; - font-weight: bold; - color: #444; - padding: 3px; - border-right: 1px solid #d1d1d1; - border-left: 1px solid #d1d1d1; -} - -/* Input field styling */ -.spec-table td input { - width: 45px; - padding: 2px; - font-size: 10px; - text-align: center; -} - -/* Bottom section for Power Specification */ -.power-spec-section { - padding: 4px; - background-color: #f0f7f5; - border: 1px solid #d1d1d1; - border-radius: 6px; - margin-bottom: 4px; - width: 100%; - margin-left: auto; - margin-right: auto; -} - -/* Table for Power Specification */ -.power-spec-table { - width: 100%; - border-collapse: collapse; -} - -.power-spec-table th, .power-spec-table td { - padding: 3px; - text-align: center; - border: 1px solid #d1d1d1; - font-size: 10px; -} - -/* Styling for power budget and dynamic scaling */ -.power-spec-table .scaling-cell { - font-weight: bold; - color: #444; } -/* Input fields in Power Specification */ -.power-spec-table td input { - width: 45px; - padding: 2px; - text-align: center; - font-size: 10px; -} - -/* Header styling for both Thermal and Power sections */ -.bold-text-title { - font-weight: bold; - font-size: 11px; - color: #333; - text-align: left; -} - -/* FPGA Complex and Core Power table */ .pst-table { width: 100%; border-collapse: collapse; - box-sizing: border-box; - height: auto; /* Changed height to auto to fit content */ - display: table; - table-layout: fixed; /* Ensure equal column widths */ - margin-bottom: 0; /* Removed extra margin for symmetrical alignment */ } .pst-table td { - padding: 0.20em 0.99em; /* Adjusted padding for consistent spacing */ - border-bottom: 1px solid #e1e1e1; - text-align: left; /* Align content to the left */ - font-size: 10px; - width: 100%; + padding-top: 0.5em; + padding-bottom: 0.5em; } -/* Processing Complex (SOC) Power table */ -.pst-table-soc { - width: 100%; - border-collapse: collapse; - box-sizing: border-box; - height: auto; /* Changed height to auto to fit content */ - display: table; - table-layout: fixed; - margin-bottom: 0; /* Ensures symmetrical gap with the FPGA table */ -} - -.pst-table-soc td { - padding: 0.80em 0.99em; /* Same padding adjustments for consistency */ +.pst-table td { border-bottom: 1px solid #e1e1e1; - text-align: left; - font-size: 20px; - width: 100%; } -.pst-table tbody>tr:last-child>td, -.pst-table-soc tbody>tr:last-child>td { +.pst-table tbody>tr:last-child>td { border-bottom: 0; } -/* Bottom section */ .pst-bottom { display: flex; flex-direction: row; - justify-content: space-between; border-top: 1px solid #e1e1e1; - margin-top: 0; - padding-top: 2px; - padding-bottom: 2px; + margin-top: 10px; + padding-top: 3px; + padding-bottom: 3px; align-items: flex-end; } @@ -184,40 +40,23 @@ .pst-bottom-progress { text-align: left; - width: 50%; } .pst-bottom-total { text-align: right; - width: 50%; + width: 100%; color: #7c7c7c; - font-size: 10px; + font-size: 17px; } -/* Styling for dot icons */ .dot-td { text-align: center; } .dot { - width: 8px; - height: 8px; + width: 10px; + height: 10px; border-radius: 50%; display: inline-block; vertical-align: middle; } - -/* Remove unnecessary bottom space */ -.pst-container, -.pst-table, -.pst-table-soc { - margin-bottom: 0; - height: 100%; -} - -/* Ensure table fills the entire container */ -.pst-table, .pst-table-soc { - display: flex; - flex-direction: column; - justify-content: space-between; -} diff --git a/src/tests/GlobalStateProvider.test.js b/src/tests/GlobalStateProvider.test.js index be412656..8a4f5f43 100644 --- a/src/tests/GlobalStateProvider.test.js +++ b/src/tests/GlobalStateProvider.test.js @@ -6,7 +6,6 @@ import * as server from '../utils/serverAPI'; jest.mock('../utils/serverAPI', () => ({ GET: jest.fn(), - PATCH: jest.fn(), api: { fetch: jest.fn((elem, device) => `/mock-api/${elem}/${device}`), }, @@ -20,25 +19,17 @@ jest.mock('../utils/serverAPI', () => ({ }, peripheralPath: jest.fn((device, path) => `/mock-api/peripheral/${device}/${path}`), attributes: jest.fn(() => '/mock-api/attributes'), - deviceInfo: jest.fn((device) => `/mock-api/device-info/${device}`), })); const TestComponent = () => { - const { - updateGlobalState, - clockingState, - peripherals, - acpuNames, - fetchAttributes, - GetOptions, - } = useGlobalState(); + const { updateGlobalState, clockingState, peripherals, acpuNames, fetchAttributes, GetOptions } = useGlobalState(); const options = GetOptions('mock-attribute'); return (
{clockingState.join(', ')}
{peripherals.length}
-
{acpuNames.map((acpu) => acpu.text).join(', ')}
+
{acpuNames.map(acpu => acpu.text).join(', ')}
{options.join(', ')}
@@ -69,8 +60,6 @@ describe('GlobalStateProvider', () => { callback([{ href: '/mock-peripheral', type: 'DMA' }]); } else if (url.includes('mock-peripheral')) { callback({ consumption: { messages: 'DMA Message' }, targets: 8 }); - } else if (url.includes('device-info')) { - callback({ specification: { thermal: {}, power: {} } }); } });