diff --git a/packages/react-components/src/components/bar-chart/barChart.tsx b/packages/react-components/src/components/bar-chart/barChart.tsx index c031405d4..7b33e357a 100644 --- a/packages/react-components/src/components/bar-chart/barChart.tsx +++ b/packages/react-components/src/components/bar-chart/barChart.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import { StyleSettingsMap, Threshold, @@ -17,12 +17,15 @@ import { DEFAULT_VIEWPORT, ECHARTS_GESTURE, } from '../../common/constants'; -import type { +import { getAlarmQueries, getTimeSeriesQueries } from '../../utils/queries'; +import { AxisSettings, ChartSize, ComponentQuery, } from '../../common/chartTypes'; -import { getTimeSeriesQueries } from '../../utils/queries'; +import { useAlarms } from '../../hooks/useAlarms'; +import { convertAlarmQueryToAlarmRequest } from '../../queries/utils/convertAlarmQueryToAlarmRequest'; +import { transformAlarmsToThreshold } from '../../utils/transformAlarmsToThreshold'; const HOUR_IN_MS = 1000 * 60 * 60; const DAY_IN_MS = HOUR_IN_MS * 24; @@ -56,9 +59,38 @@ export const BarChart = (props: BarChartProps) => { ...rest } = props; + const { viewport, setViewport, group, lastUpdatedBy } = useViewport(); + + // if using echarts then echarts gesture overrides passed in viewport + // else explicitly passed in viewport overrides viewport group + const utilizedViewport = + (lastUpdatedBy === ECHARTS_GESTURE + ? viewport + : passedInViewport || viewport) ?? DEFAULT_VIEWPORT; + + const alarmQueries = getAlarmQueries(queries); + const timeSeriesQueries = getTimeSeriesQueries(queries); + + const mapAlarmQueriesToRequests = alarmQueries.flatMap((query) => + convertAlarmQueryToAlarmRequest(query) + ); + + const transformedAlarms = useAlarms({ + iotSiteWiseClient: alarmQueries.at(0)?.iotSiteWiseClient, + iotEventsClient: alarmQueries.at(0)?.iotEventsClient, + requests: mapAlarmQueriesToRequests, + viewport: utilizedViewport, + settings: { + fetchThresholds: true, + refreshRate: alarmQueries.at(0)?.query.requestSettings?.refreshRate, + }, + transform: transformAlarmsToThreshold, + }); + const filteredAlarms = transformedAlarms.filter((alarm) => !!alarm); + const { dataStreams, thresholds: queryThresholds } = useTimeSeriesData({ viewport: passedInViewport, - queries: getTimeSeriesQueries(queries), + queries: timeSeriesQueries, settings: { fetchFromStartToEnd: true, fetchMostRecentBeforeStart: true, @@ -72,15 +104,15 @@ export const BarChart = (props: BarChartProps) => { }, styles, }); - const { viewport, setViewport, group, lastUpdatedBy } = useViewport(); - const allThresholds = [...queryThresholds, ...thresholds]; - // if using echarts then echarts gesture overrides passed in viewport - // else explicitly passed in viewport overrides viewport group - const utilizedViewport = - (lastUpdatedBy === ECHARTS_GESTURE - ? viewport - : passedInViewport || viewport) ?? DEFAULT_VIEWPORT; + const allThresholds = useMemo( + () => [...queryThresholds, ...thresholds, ...filteredAlarms], + [ + JSON.stringify(queryThresholds), + JSON.stringify(thresholds), + JSON.stringify(filteredAlarms), + ] + ); return ( { + return ( + alarmQuery.query.alarms?.reduce((results, alarm) => { + alarm.alarmComponents.map((component) => { + results.push({ + assetId: alarm.assetId, + assetCompositeModelId: component.assetCompositeModelId, + }); + }); + return results; + }, [] as AlarmCompositeModelRequest[]) ?? [] + ); +}; diff --git a/packages/react-components/src/utils/transformAlarmsToThreshold.ts b/packages/react-components/src/utils/transformAlarmsToThreshold.ts new file mode 100644 index 000000000..5a6485ff4 --- /dev/null +++ b/packages/react-components/src/utils/transformAlarmsToThreshold.ts @@ -0,0 +1,61 @@ +import { Threshold } from '@iot-app-kit/core'; +import { AlarmData } from '../hooks/useAlarms'; +import { IoTEventsToSynchroChartsComparisonOperator } from '@iot-app-kit/source-iotsitewise'; +import { COMPARATOR_MAP, COMPARISON_OPERATOR } from '../common/constants'; + +const createThreshold = ({ + thresholdValue, + severity, + labelText, + comparisonOperator, +}: { + thresholdValue: number; + severity: number | undefined; + labelText: string; + comparisonOperator: COMPARISON_OPERATOR; +}): Threshold => { + return { + color: 'red', + value: thresholdValue, + severity: severity, + showValue: false, + label: { + text: labelText, + show: true, + }, + comparisonOperator: comparisonOperator, + }; +}; + +export const transformAlarmsToThreshold = ( + alarm: AlarmData +): Threshold | undefined => { + const { models, inputProperty, thresholds, status } = alarm; + const modelsFound = models && models.length !== 0; + const thresholdsFound = thresholds && thresholds?.length !== 0; + + if (status.isSuccess) { + if (modelsFound && thresholdsFound) { + const model = models[0]; + const threshold = thresholds[thresholds.length - 1]; + + const thresholdValue = + threshold.value?.doubleValue ?? threshold.value?.integerValue; + const comparisonOperator = + model.alarmRule?.simpleRule?.comparisonOperator; + + if (thresholdValue && comparisonOperator && inputProperty) { + const scComparisonOperator = IoTEventsToSynchroChartsComparisonOperator[ + comparisonOperator + ] as COMPARISON_OPERATOR; + + return createThreshold({ + labelText: `${inputProperty[0].name} ${COMPARATOR_MAP[scComparisonOperator]} ${thresholdValue}`, + thresholdValue: thresholdValue, + severity: model.severity, + comparisonOperator: scComparisonOperator, + }); + } + } + } +}; diff --git a/packages/source-iotsitewise/src/alarms/iotevents/index.ts b/packages/source-iotsitewise/src/alarms/iotevents/index.ts index 5c3f0b2d5..40a1ed447 100644 --- a/packages/source-iotsitewise/src/alarms/iotevents/index.ts +++ b/packages/source-iotsitewise/src/alarms/iotevents/index.ts @@ -2,4 +2,7 @@ export * from './types'; export * from './siteWiseAlarmModule'; export { parseAlarmData } from './util/parseAlarmData'; export { constructAlarmThresholds } from './util/constructAlarmThresholds'; -export { SOURCE } from './constants'; +export { + SOURCE, + IoTEventsToSynchroChartsComparisonOperator, +} from './constants'; diff --git a/packages/source-iotsitewise/src/index.ts b/packages/source-iotsitewise/src/index.ts index 4503db26a..6aa0b5e45 100644 --- a/packages/source-iotsitewise/src/index.ts +++ b/packages/source-iotsitewise/src/index.ts @@ -4,6 +4,7 @@ export * from './__mocks__'; export { initialize } from './initialize'; export { BranchReference } from './asset-modules/sitewise-asset-tree/types'; export { toId, fromId } from './time-series-data/util/dataStreamId'; +export { IoTEventsToSynchroChartsComparisonOperator } from './alarms/iotevents'; export type { SiteWiseDataSourceInitInputs, SiteWiseQuery,