diff --git a/packages/react-components/src/components/bar-chart/barChart.tsx b/packages/react-components/src/components/bar-chart/barChart.tsx index c031405d4..e7319b059 100644 --- a/packages/react-components/src/components/bar-chart/barChart.tsx +++ b/packages/react-components/src/components/bar-chart/barChart.tsx @@ -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 { transformAlarmsToSynchroChartsThreshold } from '../../utils/transformAlarmThresholdToSynchroChartsThreshold'; const HOUR_IN_MS = 1000 * 60 * 60; const DAY_IN_MS = HOUR_IN_MS * 24; @@ -56,9 +59,33 @@ export const BarChart = (props: BarChartProps) => { ...rest } = props; + const { + viewport: injectedViewport, + setViewport, + group, + lastUpdatedBy, + } = useViewport(); + const viewport = passedInViewport || injectedViewport || DEFAULT_VIEWPORT; + + const alarmQueries = getAlarmQueries(queries); + const timeSeriesQueries = getTimeSeriesQueries(queries); + + const mapAlarmQueriesToRequests = alarmQueries.flatMap((query) => + convertAlarmQueryToAlarmRequest(query) + ); + + const convertedAlarms = useAlarms({ + iotSiteWiseClient: alarmQueries[0]?.iotSiteWiseClient, + iotEventsClient: alarmQueries[0]?.iotEventsClient, + requests: mapAlarmQueriesToRequests, + viewport, + settings: { fetchThresholds: true }, + transform: transformAlarmsToSynchroChartsThreshold, + }); + const { dataStreams, thresholds: queryThresholds } = useTimeSeriesData({ viewport: passedInViewport, - queries: getTimeSeriesQueries(queries), + queries: timeSeriesQueries, settings: { fetchFromStartToEnd: true, fetchMostRecentBeforeStart: true, @@ -72,8 +99,12 @@ export const BarChart = (props: BarChartProps) => { }, styles, }); - const { viewport, setViewport, group, lastUpdatedBy } = useViewport(); - const allThresholds = [...queryThresholds, ...thresholds]; + + const allThresholds = [ + ...queryThresholds, + ...thresholds, + ...convertedAlarms.filter((alarm) => !!alarm), + ]; // if using echarts then echarts gesture overrides passed in viewport // else explicitly passed in viewport overrides viewport group diff --git a/packages/react-components/src/queries/utils/convertAlarmQueryToAlarmRequest.ts b/packages/react-components/src/queries/utils/convertAlarmQueryToAlarmRequest.ts new file mode 100644 index 000000000..211c25c84 --- /dev/null +++ b/packages/react-components/src/queries/utils/convertAlarmQueryToAlarmRequest.ts @@ -0,0 +1,18 @@ +import { AlarmDataQuery } from '@iot-app-kit/source-iotsitewise'; +import { AlarmCompositeModelRequest } from '../../hooks/useAlarms'; + +export const convertAlarmQueryToAlarmRequest = ( + alarmQuery: AlarmDataQuery +): AlarmCompositeModelRequest[] => { + 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/transformAlarmThresholdToSynchroChartsThreshold.ts b/packages/react-components/src/utils/transformAlarmThresholdToSynchroChartsThreshold.ts new file mode 100644 index 000000000..7ee6a65ec --- /dev/null +++ b/packages/react-components/src/utils/transformAlarmThresholdToSynchroChartsThreshold.ts @@ -0,0 +1,39 @@ +import { YAnnotation } 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'; + +export const transformAlarmsToSynchroChartsThreshold = ( + alarm: AlarmData +): YAnnotation | undefined => { + const { models, inputProperty, thresholds, status } = alarm; + + if (!status.isSuccess) return undefined; + + if (models && models.length !== 0 && thresholds && thresholds?.length !== 0) { + const model = models[0]; + const thresholdValue = + thresholds[0].value?.doubleValue ?? thresholds[0].value?.integerValue; + const comparisonOperator = model.alarmRule?.simpleRule?.comparisonOperator; + + if (thresholdValue && comparisonOperator && inputProperty) { + const scComparisonOperator = IoTEventsToSynchroChartsComparisonOperator[ + comparisonOperator + ] as COMPARISON_OPERATOR; + + return { + color: 'red', + value: thresholdValue, + severity: model.severity, + showValue: true, + label: { + text: `${inputProperty[0].name} ${COMPARATOR_MAP[scComparisonOperator]} ${thresholdValue}`, + show: true, + }, + comparisonOperator: scComparisonOperator, + }; + } + } + + return undefined; +}; 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,