From b07a19344af31090f9398b9e9d1b812a40775736 Mon Sep 17 00:00:00 2001 From: Brian Diehr Date: Thu, 20 Jan 2022 12:31:03 -0800 Subject: [PATCH] feat: add in styles overrides and refId in query --- packages/components/src/components.d.ts | 22 +++++++- .../iot-bar-chart/iot-bar-chart.tsx | 6 +-- .../bindStylesToDataStreams.spec.ts | 53 +++++++++++++++++++ .../iot-connector/bindStylesToDataStreams.ts | 18 +++++++ .../iot-connector/iot-connector.spec.ts | 33 ++++++++++++ .../iot-connector/iot-connector.tsx | 8 ++- .../src/components/iot-kpi/iot-kpi.tsx | 6 +-- .../iot-line-chart/iot-line-chart.tsx | 6 ++- .../iot-scatter-chart/iot-scatter-chart.tsx | 6 +-- .../iot-status-grid/iot-status-grid.tsx | 6 +-- .../iot-status-timeline.tsx | 6 +-- .../src/components/iot-table/iot-table.tsx | 6 +-- packages/components/src/components/types.d.ts | 8 --- .../src/testing/createMockSource.ts | 19 ++++++- .../src/testing/mockWidgetProperties.ts | 2 +- .../components/src/testing/renderChart.tsx | 13 +++-- packages/core/src/common/getDataPoints.ts | 3 +- packages/core/src/common/predicates.spec.ts | 3 +- packages/core/src/common/predicates.ts | 4 +- .../data-module/IotAppKitDataModule.spec.ts | 47 ++++++++++++++-- .../src/data-module/data-cache/dataActions.ts | 3 +- .../data-cache/dataCacheWrapped.ts | 3 +- .../data-cache/dataReducer.spec.ts | 3 +- .../data-module/data-cache/requestTypes.ts | 7 +-- .../data-cache/toDataStreams.spec.ts | 10 ++++ .../data-module/data-cache/toDataStreams.ts | 5 +- .../data-source-store/dataSourceStore.ts | 2 +- packages/core/src/data-module/types.d.ts | 20 +++++-- .../site-wise-legacy/data-source.ts | 8 +-- .../site-wise/data-source.spec.ts | 32 +++++++++++ .../src/data-sources/site-wise/data-source.ts | 3 +- .../site-wise/dataStreamFromSiteWise.ts | 3 +- 32 files changed, 312 insertions(+), 62 deletions(-) create mode 100644 packages/components/src/components/iot-connector/bindStylesToDataStreams.spec.ts create mode 100644 packages/components/src/components/iot-connector/bindStylesToDataStreams.ts delete mode 100644 packages/components/src/components/types.d.ts diff --git a/packages/components/src/components.d.ts b/packages/components/src/components.d.ts index 587961168..0aaf82076 100644 --- a/packages/components/src/components.d.ts +++ b/packages/components/src/components.d.ts @@ -5,8 +5,8 @@ * It contains typing information for all components that exist in this project. */ import { HTMLStencilElement, JSXBase } from "@stencil/core/internal"; -import { AnyDataStreamQuery, AssetSummaryQuery, AssetTreeSubscription, DataModule, SiteWiseAssetTreeQuery, TimeSeriesDataRequest, TimeSeriesDataRequestSettings } from "@iot-app-kit/core"; -import { DataStream, MinimalViewPortConfig } from "@synchro-charts/core"; +import { AnyDataStreamQuery, AssetSummaryQuery, AssetTreeSubscription, DataModule, DataStream, SiteWiseAssetTreeQuery, StyleSettingsMap, TimeSeriesDataRequest, TimeSeriesDataRequestSettings } from "@iot-app-kit/core"; +import { MinimalViewPortConfig } from "@synchro-charts/core"; import { ColumnDefinition, FilterTexts, ResourceExplorerQuery, SitewiseAssetResource } from "./components/iot-resource-explorer/types"; import { TableProps } from "@awsui/components-react/table"; import { EmptyStateProps, ITreeNode, UseTreeCollection } from "@iot-app-kit/related-table"; @@ -24,6 +24,7 @@ export namespace Components { "isEditing": boolean | undefined; "queries": AnyDataStreamQuery[]; "settings": TimeSeriesDataRequestSettings | undefined; + "styleSettings": StyleSettingsMap | undefined; "viewport": MinimalViewPortConfig; "widgetId": string; } @@ -32,12 +33,14 @@ export namespace Components { "queries": AnyDataStreamQuery[]; "renderFunc": ({ dataStreams }: { dataStreams: DataStream[] }) => unknown; "request": TimeSeriesDataRequest; + "styleSettings": StyleSettingsMap | undefined; } interface IotKpi { "appKit": DataModule; "isEditing": boolean | undefined; "queries": AnyDataStreamQuery[]; "settings": TimeSeriesDataRequestSettings | undefined; + "styleSettings": StyleSettingsMap | undefined; "viewport": MinimalViewPortConfig; "widgetId": string; } @@ -46,6 +49,8 @@ export namespace Components { "isEditing": boolean | undefined; "queries": AnyDataStreamQuery[]; "settings": TimeSeriesDataRequestSettings | undefined; + "styleSettings": StyleSettingsMap | undefined; + "styles": StyleSettingsMap | undefined; "viewport": MinimalViewPortConfig; "widgetId": string; } @@ -70,6 +75,7 @@ export namespace Components { "isEditing": boolean | undefined; "queries": AnyDataStreamQuery[]; "settings": TimeSeriesDataRequestSettings | undefined; + "styleSettings": StyleSettingsMap | undefined; "viewport": MinimalViewPortConfig; "widgetId": string; } @@ -78,6 +84,7 @@ export namespace Components { "isEditing": boolean | undefined; "queries": AnyDataStreamQuery[]; "settings": TimeSeriesDataRequestSettings | undefined; + "styleSettings": StyleSettingsMap | undefined; "viewport": MinimalViewPortConfig; "widgetId": string; } @@ -86,6 +93,7 @@ export namespace Components { "isEditing": boolean | undefined; "queries": AnyDataStreamQuery[]; "settings": TimeSeriesDataRequestSettings | undefined; + "styleSettings": StyleSettingsMap | undefined; "viewport": MinimalViewPortConfig; "widgetId": string; } @@ -93,6 +101,7 @@ export namespace Components { "appKit": DataModule; "queries": AnyDataStreamQuery[]; "settings": TimeSeriesDataRequestSettings | undefined; + "styleSettings": StyleSettingsMap | undefined; "viewport": MinimalViewPortConfig; "widgetId": string; } @@ -270,6 +279,7 @@ declare namespace LocalJSX { "isEditing"?: boolean | undefined; "queries"?: AnyDataStreamQuery[]; "settings"?: TimeSeriesDataRequestSettings | undefined; + "styleSettings"?: StyleSettingsMap | undefined; "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } @@ -278,12 +288,14 @@ declare namespace LocalJSX { "queries"?: AnyDataStreamQuery[]; "renderFunc"?: ({ dataStreams }: { dataStreams: DataStream[] }) => unknown; "request"?: TimeSeriesDataRequest; + "styleSettings"?: StyleSettingsMap | undefined; } interface IotKpi { "appKit"?: DataModule; "isEditing"?: boolean | undefined; "queries"?: AnyDataStreamQuery[]; "settings"?: TimeSeriesDataRequestSettings | undefined; + "styleSettings"?: StyleSettingsMap | undefined; "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } @@ -292,6 +304,8 @@ declare namespace LocalJSX { "isEditing"?: boolean | undefined; "queries"?: AnyDataStreamQuery[]; "settings"?: TimeSeriesDataRequestSettings | undefined; + "styleSettings"?: StyleSettingsMap | undefined; + "styles"?: StyleSettingsMap | undefined; "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } @@ -316,6 +330,7 @@ declare namespace LocalJSX { "isEditing"?: boolean | undefined; "queries"?: AnyDataStreamQuery[]; "settings"?: TimeSeriesDataRequestSettings | undefined; + "styleSettings"?: StyleSettingsMap | undefined; "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } @@ -324,6 +339,7 @@ declare namespace LocalJSX { "isEditing"?: boolean | undefined; "queries"?: AnyDataStreamQuery[]; "settings"?: TimeSeriesDataRequestSettings | undefined; + "styleSettings"?: StyleSettingsMap | undefined; "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } @@ -332,6 +348,7 @@ declare namespace LocalJSX { "isEditing"?: boolean | undefined; "queries"?: AnyDataStreamQuery[]; "settings"?: TimeSeriesDataRequestSettings | undefined; + "styleSettings"?: StyleSettingsMap | undefined; "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } @@ -339,6 +356,7 @@ declare namespace LocalJSX { "appKit"?: DataModule; "queries"?: AnyDataStreamQuery[]; "settings"?: TimeSeriesDataRequestSettings | undefined; + "styleSettings"?: StyleSettingsMap | undefined; "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } diff --git a/packages/components/src/components/iot-bar-chart/iot-bar-chart.tsx b/packages/components/src/components/iot-bar-chart/iot-bar-chart.tsx index b9e15f2e5..d4098e8a9 100644 --- a/packages/components/src/components/iot-bar-chart/iot-bar-chart.tsx +++ b/packages/components/src/components/iot-bar-chart/iot-bar-chart.tsx @@ -1,7 +1,6 @@ import { Component, Prop, h } from '@stencil/core'; import { MinimalViewPortConfig } from '@synchro-charts/core'; -import { AnyDataStreamQuery, DataModule, TimeSeriesDataRequestSettings } from '@iot-app-kit/core'; -import { StyleSettingsMap } from '../types'; +import { AnyDataStreamQuery, DataModule, TimeSeriesDataRequestSettings, StyleSettingsMap } from '@iot-app-kit/core'; const DEFAULT_VIEWPORT = { duration: 10 * 1000 * 60 }; @@ -22,7 +21,7 @@ export class IotBarChart { @Prop() settings: TimeSeriesDataRequestSettings | undefined; - @Prop() styles: StyleSettingsMap | undefined; + @Prop() styleSettings: StyleSettingsMap | undefined; getSettings(): TimeSeriesDataRequestSettings { return { @@ -37,6 +36,7 @@ export class IotBarChart { { + expect( + bindStylesToDataStreams({ + dataStreams: [], + styleSettings: { someStyle: { color: 'red' } }, + }) + ).toEqual([]); +}); + +it('returns data streams when no matching styles', () => { + expect( + bindStylesToDataStreams({ + dataStreams: [DATA_STREAM], + styleSettings: { someStyle: { color: 'red' } }, + }) + ).toEqual([DATA_STREAM]); +}); + +it('associates styles to corresponding data stream', () => { + expect( + bindStylesToDataStreams({ + dataStreams: [{ ...DATA_STREAM, refId: 'someStyle' }], + styleSettings: { someStyle: { color: 'red' } }, + }) + ).toEqual([{ ...DATA_STREAM, refId: 'someStyle', color: 'red' }]); +}); + +it('associates styles to corresponding data stream for multiple data streams', () => { + expect( + bindStylesToDataStreams({ + dataStreams: [ + { ...DATA_STREAM, refId: 'someStyle' }, + { ...DATA_STREAM_2, refId: 'someStyle2' }, + ], + styleSettings: { someStyle: { color: 'red' }, someStyle2: { color: 'blue' } }, + }) + ).toEqual([ + { ...DATA_STREAM, refId: 'someStyle', color: 'red' }, + { ...DATA_STREAM_2, refId: 'someStyle2', color: 'blue' }, + ]); +}); + +it('returns data stream when no matching refId', () => { + expect( + bindStylesToDataStreams({ + dataStreams: [{ ...DATA_STREAM, refId: 'someStyle100' }], + styleSettings: { someStyle: { color: 'red' } }, + }) + ).toEqual([{ ...DATA_STREAM, refId: 'someStyle100' }]); +}); diff --git a/packages/components/src/components/iot-connector/bindStylesToDataStreams.ts b/packages/components/src/components/iot-connector/bindStylesToDataStreams.ts new file mode 100644 index 000000000..5315e649a --- /dev/null +++ b/packages/components/src/components/iot-connector/bindStylesToDataStreams.ts @@ -0,0 +1,18 @@ +import { StyleSettingsMap, DataStream } from '@iot-app-kit/core'; + +// If the data stream has a reference id with associated styles, append those styles to the data stream. +export const bindStylesToDataStreams = ({ + dataStreams, + styleSettings, +}: { + dataStreams: DataStream[]; + styleSettings?: StyleSettingsMap; +}): DataStream[] => + dataStreams.map((dataStream) => + styleSettings == null || dataStream.refId == null + ? dataStream + : { + ...dataStream, + ...styleSettings[dataStream.refId], + } + ); diff --git a/packages/components/src/components/iot-connector/iot-connector.spec.ts b/packages/components/src/components/iot-connector/iot-connector.spec.ts index a8d450e7c..998b5e37e 100644 --- a/packages/components/src/components/iot-connector/iot-connector.spec.ts +++ b/packages/components/src/components/iot-connector/iot-connector.spec.ts @@ -126,3 +126,36 @@ it('updates with new queries', async () => { ], }); }); + +it('binds styles to data streams', async () => { + const renderFunc = jest.fn(); + const { assetId, propertyId } = toSiteWiseAssetProperty(DATA_STREAM.id); + const REF_ID = 'some-ref-id'; + + await connectorSpecPage({ + renderFunc, + styleSettings: { + [REF_ID]: { + color: 'red', + name: 'my-name', + }, + }, + queries: [ + { + source: 'test-mock', + assets: [{ assetId, properties: [{ propertyId, refId: REF_ID }] }], + } as SiteWiseDataStreamQuery, + ], + }); + + expect(renderFunc).lastCalledWith({ + dataStreams: [ + expect.objectContaining({ + id: DATA_STREAM.id, + refId: REF_ID, + color: 'red', + name: 'my-name', + }), + ], + }); +}); diff --git a/packages/components/src/components/iot-connector/iot-connector.tsx b/packages/components/src/components/iot-connector/iot-connector.tsx index 7471132cf..2b93bb4b4 100644 --- a/packages/components/src/components/iot-connector/iot-connector.tsx +++ b/packages/components/src/components/iot-connector/iot-connector.tsx @@ -1,13 +1,15 @@ import { Component, Listen, Prop, State, Watch } from '@stencil/core'; -import { DataStream } from '@synchro-charts/core'; import isEqual from 'lodash.isequal'; import { AnyDataStreamQuery, SubscriptionUpdate, subscribeToDataStreams, DataModule, + DataStream, TimeSeriesDataRequest, + StyleSettingsMap, } from '@iot-app-kit/core'; +import { bindStylesToDataStreams } from './bindStylesToDataStreams'; @Component({ tag: 'iot-connector', @@ -22,6 +24,8 @@ export class IotConnector { @Prop() renderFunc: ({ dataStreams }: { dataStreams: DataStream[] }) => unknown; + @Prop() styleSettings: StyleSettingsMap | undefined; + @State() dataStreams: DataStream[] = []; private update: (subscriptionUpdate: SubscriptionUpdate) => void; @@ -37,7 +41,7 @@ export class IotConnector { request: this.request, }, (dataStreams: DataStream[]) => { - this.dataStreams = dataStreams; + this.dataStreams = bindStylesToDataStreams({ dataStreams, styleSettings: this.styleSettings }); } ); diff --git a/packages/components/src/components/iot-kpi/iot-kpi.tsx b/packages/components/src/components/iot-kpi/iot-kpi.tsx index d0be610f6..59373e25f 100644 --- a/packages/components/src/components/iot-kpi/iot-kpi.tsx +++ b/packages/components/src/components/iot-kpi/iot-kpi.tsx @@ -1,7 +1,6 @@ import { Component, Prop, h } from '@stencil/core'; import { MinimalViewPortConfig } from '@synchro-charts/core'; -import { AnyDataStreamQuery, DataModule, TimeSeriesDataRequestSettings } from '@iot-app-kit/core'; -import { StyleSettingsMap } from '../types'; +import { AnyDataStreamQuery, DataModule, TimeSeriesDataRequestSettings, StyleSettingsMap } from '@iot-app-kit/core'; const DEFAULT_VIEWPORT = { duration: 10 * 1000 }; @@ -22,7 +21,7 @@ export class IotKpi { @Prop() settings: TimeSeriesDataRequestSettings | undefined; - @Prop() styles: StyleSettingsMap | undefined; + @Prop() styleSettings: StyleSettingsMap | undefined; getSettings(): TimeSeriesDataRequestSettings { return { @@ -37,6 +36,7 @@ export class IotKpi { query.assets .map(({ assetId, properties }) => properties.map(({ propertyId }) => toDataStreamId({ assetId, propertyId }))) .flat(); +const associatedProperty = (query: SiteWiseDataStreamQuery, dataStreamId: string) => { + const { assetId, propertyId } = toSiteWiseAssetProperty(dataStreamId); + const asset = query.assets.find((asset) => asset.assetId === assetId); + return asset?.properties.find((property) => property.propertyId === propertyId); +}; + export const createMockSource = (dataStreams: DataStream[]): DataSource => ({ name: 'test-mock', initiateRequest: ({ onSuccess }: DataSourceRequest) => onSuccess(dataStreams), getRequestsFromQuery: ({ query }) => dataStreams .filter(({ id }) => dataStreamIds(query).includes(id)) - .map(({ data, aggregates, ...dataStreamInfo }) => dataStreamInfo), + .map(({ data, aggregates, ...dataStreamInfo }) => ({ + ...dataStreamInfo, + })) + .map((dataStream) => { + const property = associatedProperty(query, dataStream.id); + return { + ...dataStream, + refId: property?.refId, + }; + }), }); diff --git a/packages/components/src/testing/mockWidgetProperties.ts b/packages/components/src/testing/mockWidgetProperties.ts index 2c9fa2431..ffd8b06f2 100755 --- a/packages/components/src/testing/mockWidgetProperties.ts +++ b/packages/components/src/testing/mockWidgetProperties.ts @@ -1,6 +1,5 @@ import { COMPARISON_OPERATOR, - DataStream, DataStreamInfo, DataType, StatusIcon, @@ -8,6 +7,7 @@ import { Threshold, ViewPort, } from '@synchro-charts/core'; +import { DataStream } from '@iot-app-kit/core'; import { toDataStreamId } from './dataStreamId'; const DAY_IN_MS = 1000 * 60 * 60 * 24; diff --git a/packages/components/src/testing/renderChart.tsx b/packages/components/src/testing/renderChart.tsx index 6d9ef92cc..dce00381f 100644 --- a/packages/components/src/testing/renderChart.tsx +++ b/packages/components/src/testing/renderChart.tsx @@ -1,6 +1,12 @@ import { mount } from '@cypress/vue'; import { h } from 'vue'; -import { DataModule, SiteWiseDataStreamQuery, TimeSeriesDataRequestSettings } from '@iot-app-kit/core'; +import { + DataModule, + DataStream, + SiteWiseDataStreamQuery, + TimeSeriesDataRequestSettings, + StyleSettingsMap, +} from '@iot-app-kit/core'; import { MinimalViewPortConfig } from '@synchro-charts/core'; const { applyPolyfills, defineCustomElements } = require('@iot-app-kit/components/loader'); import { DATA_STREAM } from '@iot-app-kit/components/src/testing/mockWidgetProperties'; @@ -9,7 +15,6 @@ import { SECOND_IN_MS, MINUTE_IN_MS, HOUR_IN_MS } from '@iot-app-kit/core/src/co import { DataSource, DataSourceRequest } from '@iot-app-kit/core/src/data-module/types'; import { toDataStreamId } from '@iot-app-kit/core/src/data-sources/site-wise/util/dataStreamId'; import { IotAppKitDataModule } from '@iot-app-kit/core/src/data-module/IotAppKitDataModule'; -import { DataStream } from '@synchro-charts/core'; import '@synchro-charts/core/dist/synchro-charts/synchro-charts.css'; applyPolyfills().then(() => defineCustomElements()); @@ -138,12 +143,14 @@ export const renderChart = ( queries = defaultQueries, settings = defaultSettings, viewport = defaultViewport, + styleSettings, }: { chartType?: string; appKit?: DataModule; queries?: SiteWiseDataStreamQuery[]; settings?: TimeSeriesDataRequestSettings; viewport?: MinimalViewPortConfig; + styleSettings?: StyleSettingsMap; } = { chartType: defaultChartType, appKit: defaultAppKit, @@ -160,7 +167,7 @@ export const renderChart = ( }, render: function () { const containerProps = { class: testChartContainerClassName, style: { width: '400px', height: '500px' } }; - const chartProps: any = { appKit, queries, settings, viewport }; + const chartProps: any = { appKit, queries, settings, viewport, styleSettings }; return (
diff --git a/packages/core/src/common/getDataPoints.ts b/packages/core/src/common/getDataPoints.ts index 726f1d6ba..031927ea8 100644 --- a/packages/core/src/common/getDataPoints.ts +++ b/packages/core/src/common/getDataPoints.ts @@ -1,4 +1,5 @@ -import { DataPoint, DataStream, Primitive, Resolution } from '@synchro-charts/core'; +import { DataPoint, Primitive, Resolution } from '@synchro-charts/core'; +import { DataStream } from '../data-module/types.d'; /** * Get the points for a given resolution from a data stream diff --git a/packages/core/src/common/predicates.spec.ts b/packages/core/src/common/predicates.spec.ts index e5ba3c9c0..840a4f94e 100644 --- a/packages/core/src/common/predicates.spec.ts +++ b/packages/core/src/common/predicates.spec.ts @@ -1,4 +1,4 @@ -import { DataStream, DataStreamInfo, DataType, MinimalLiveViewport, MinimalStaticViewport } from '@synchro-charts/core'; +import { DataStreamInfo, DataType, MinimalLiveViewport, MinimalStaticViewport } from '@synchro-charts/core'; import { isNumber, isDefined, @@ -7,6 +7,7 @@ import { isValid, isMinimalStaticViewport, } from './predicates'; +import { DataStream } from '../data-module/types'; describe('isDefined', () => { it('returns false when passed null', () => { diff --git a/packages/core/src/common/predicates.ts b/packages/core/src/common/predicates.ts index 672e43a15..2c2a20901 100644 --- a/packages/core/src/common/predicates.ts +++ b/packages/core/src/common/predicates.ts @@ -1,3 +1,6 @@ +import { DataType, MinimalStaticViewport, MinimalViewPortConfig } from '@synchro-charts/core'; +import { DataStream } from '../data-module/types'; + /** * Predicate Utilities * @@ -25,7 +28,6 @@ * type guards. * */ -import { DataStream, DataType, MinimalStaticViewport, MinimalViewPortConfig } from '@synchro-charts/core'; export const isDefined = (value: T | null | undefined): value is T => value != null; diff --git a/packages/core/src/data-module/IotAppKitDataModule.spec.ts b/packages/core/src/data-module/IotAppKitDataModule.spec.ts index ad5598468..f5d26a614 100644 --- a/packages/core/src/data-module/IotAppKitDataModule.spec.ts +++ b/packages/core/src/data-module/IotAppKitDataModule.spec.ts @@ -1,7 +1,7 @@ import flushPromises from 'flush-promises'; import { DATA_STREAM, DATA_STREAM_INFO, STRING_INFO_1 } from '../testing/__mocks__/mockWidgetProperties'; -import { DataSource, DataSourceRequest, DataStreamQuery } from './types.d'; -import { DataPoint, DataStream, DataStreamInfo } from '@synchro-charts/core'; +import { DataSource, DataSourceRequest, DataStreamQuery, DataStream } from './types.d'; +import { DataPoint, DataStreamInfo } from '@synchro-charts/core'; import { TimeSeriesDataRequest, TimeSeriesDataRequestSettings } from './data-cache/requestTypes'; import { DataStreamsStore, DataStreamStore } from './data-cache/types'; import * as caching from './data-cache/caching/caching'; @@ -40,8 +40,9 @@ const createMockSiteWiseDataSource = ( getRequestsFromQuery: ({ query }) => query.assets .map(({ assetId, properties }) => - properties.map(({ propertyId }) => ({ + properties.map(({ propertyId, refId }) => ({ id: toDataStreamId({ assetId, propertyId }), + refId, resolution, })) ) @@ -162,6 +163,46 @@ describe('initial request', () => { expect(dataSource.initiateRequest).not.toBeCalled(); }); + it('passes back associated refId', () => { + const REF_ID = 'ref-id'; + const query: SiteWiseDataStreamQuery = { + source: 'site-wise', + assets: [ + { + assetId: ASSET_ID, + properties: [{ propertyId: PROPERTY_ID, refId: REF_ID }], + }, + ], + }; + + const START = new Date(2000, 0, 0); + const END = new Date(); + + const dataModule = new IotAppKitDataModule(); + const dataSource: DataSource = { + ...createMockSiteWiseDataSource([DATA_STREAM]), + initiateRequest: jest.fn(), + }; + + dataModule.registerDataSource(dataSource); + + const dataStreamCallback = jest.fn(); + + dataModule.subscribeToDataStreams( + { + queries: [query], + request: { viewport: { start: START, end: END }, settings: { fetchFromStartToEnd: true } }, + }, + dataStreamCallback + ); + expect(dataStreamCallback).toBeCalledWith([ + expect.objectContaining({ + id: DATA_STREAM.id, + refId: REF_ID, + }), + ]); + }); + it('initiates a request for a data stream', () => { const START = new Date(2000, 0, 0); const END = new Date(); diff --git a/packages/core/src/data-module/data-cache/dataActions.ts b/packages/core/src/data-module/data-cache/dataActions.ts index b29df0c55..a4f2c462f 100755 --- a/packages/core/src/data-module/data-cache/dataActions.ts +++ b/packages/core/src/data-module/data-cache/dataActions.ts @@ -1,5 +1,6 @@ import { Action, Dispatch } from 'redux'; -import { DataStream, DataStreamId, Resolution } from '@synchro-charts/core'; +import { DataStreamId, Resolution } from '@synchro-charts/core'; +import { DataStream } from '../types.d'; /** * diff --git a/packages/core/src/data-module/data-cache/dataCacheWrapped.ts b/packages/core/src/data-module/data-cache/dataCacheWrapped.ts index 8e0213c6b..10829dd5d 100644 --- a/packages/core/src/data-module/data-cache/dataCacheWrapped.ts +++ b/packages/core/src/data-module/data-cache/dataCacheWrapped.ts @@ -1,5 +1,5 @@ import { Store } from 'redux'; -import { DataStream, Resolution } from '@synchro-charts/core'; +import { Resolution } from '@synchro-charts/core'; import { DataStreamsStore } from './types'; import { configureStore } from './createStore'; import { TimeSeriesDataRequest } from './requestTypes'; @@ -10,6 +10,7 @@ import { Observable, map, startWith, pairwise, from } from 'rxjs'; import { filter } from 'rxjs/operators'; import { DataStreamCallback, RequestInformation } from '../types'; import { toDataStreams } from './toDataStreams'; +import { DataStream } from '../types'; type StoreChange = { prevDataCache: DataStreamsStore; currDataCache: DataStreamsStore }; diff --git a/packages/core/src/data-module/data-cache/dataReducer.spec.ts b/packages/core/src/data-module/data-cache/dataReducer.spec.ts index 49fba7195..89d317b95 100755 --- a/packages/core/src/data-module/data-cache/dataReducer.spec.ts +++ b/packages/core/src/data-module/data-cache/dataReducer.spec.ts @@ -1,10 +1,11 @@ -import { DataPoint, DataStream, DataType } from '@synchro-charts/core'; +import { DataPoint, DataType } from '@synchro-charts/core'; import { dataReducer } from './dataReducer'; import { onErrorAction, onRequestAction, onSuccessAction } from './dataActions'; import { DataStreamsStore } from './types'; import { getDataStreamStore } from './getDataStreamStore'; import { EMPTY_CACHE } from './caching/caching'; import { DAY_IN_MS, SECOND_IN_MS } from '../../common/time'; +import { DataStream } from '../types'; const FIRST_DATE = new Date(2000, 0, 0); const LAST_DATE = new Date(2001, 0, 0); diff --git a/packages/core/src/data-module/data-cache/requestTypes.ts b/packages/core/src/data-module/data-cache/requestTypes.ts index 68d8bb4c2..bbee21292 100755 --- a/packages/core/src/data-module/data-cache/requestTypes.ts +++ b/packages/core/src/data-module/data-cache/requestTypes.ts @@ -1,4 +1,5 @@ -import { DataStream, DataStreamId, MinimalViewPortConfig, Resolution } from '@synchro-charts/core'; +import { DataStreamId, MinimalViewPortConfig, Resolution } from '@synchro-charts/core'; +import { DataStream } from '../types.d'; export type DateInterval = { start: Date; end: Date }; @@ -36,8 +37,8 @@ export interface TimeSeriesDataRequestSettings { export type OnRequestData = (opts: { request: TimeSeriesDataRequest; resolution: number; // milliseconds, 0 for raw data - onError: (id: DataStreamId, resolution: Resolution, error: string) => void; - onSuccess: (id: DataStreamId, data: DataStream, first: Date, last: Date) => void; + onError: (dataStreamId: DataStreamId, resolution: Resolution, error: string) => void; + onSuccess: (dataStreamId: DataStreamId, dataStream: DataStream, first: Date, last: Date) => void; dataStreamId: string; }) => void; diff --git a/packages/core/src/data-module/data-cache/toDataStreams.spec.ts b/packages/core/src/data-module/data-cache/toDataStreams.spec.ts index 5f4e191ea..5e5ef52e8 100755 --- a/packages/core/src/data-module/data-cache/toDataStreams.spec.ts +++ b/packages/core/src/data-module/data-cache/toDataStreams.spec.ts @@ -62,3 +62,13 @@ it('returns a single data stream containing all the available resolutions', () = expect(stream.data).toEqual(ALARM_STREAM.data); expect(stream.aggregates![MINUTE_IN_MS]).toEqual(NUMBER_STREAM_1.data); }); + +it('appends the refId from the request information', () => { + const REF_ID = 'some-ref-id'; + const [stream] = toDataStreams({ + requestInformations: [{ ...ALARM_STREAM_INFO, refId: REF_ID }], + dataStreamsStores: STORE_WITH_NUMBERS_ONLY, + }); + + expect(stream.refId).toEqual(REF_ID); +}); diff --git a/packages/core/src/data-module/data-cache/toDataStreams.ts b/packages/core/src/data-module/data-cache/toDataStreams.ts index b28459a14..2e55c01cd 100755 --- a/packages/core/src/data-module/data-cache/toDataStreams.ts +++ b/packages/core/src/data-module/data-cache/toDataStreams.ts @@ -1,7 +1,7 @@ -import { DataPoint, DataStream, DataType } from '@synchro-charts/core'; +import { DataPoint, DataType } from '@synchro-charts/core'; import { DataStreamsStore } from './types'; import { isDefined } from '../../common/predicates'; -import { RequestInformation } from '../types.d'; +import { DataStream, RequestInformation } from '../types.d'; /** * To Data Streams @@ -37,6 +37,7 @@ export const toDataStreams = ({ // Create new data stream for the corresponding info return { id: info.id, + refId: info.refId, resolution: info.resolution, isLoading: activeStore ? activeStore.isLoading : false, isRefreshing: activeStore ? activeStore.isRefreshing : false, diff --git a/packages/core/src/data-module/data-source-store/dataSourceStore.ts b/packages/core/src/data-module/data-source-store/dataSourceStore.ts index 78884f16d..ed3890a4f 100644 --- a/packages/core/src/data-module/data-source-store/dataSourceStore.ts +++ b/packages/core/src/data-module/data-source-store/dataSourceStore.ts @@ -14,7 +14,7 @@ import { TimeSeriesDataRequest } from '../data-cache/requestTypes'; * Data sources enable queries to be made to return data streams for use throughout. */ export default class DataSourceStore { - // Currently there are no data sources provided by default, but we will add defaults here as they are produced. + // Currently, there are no data sources provided by default, but we will add defaults here as they are produced. private dataSources: { [name: string]: DataSource } = {}; private getDataSource = (source: DataSourceName): DataSource => { diff --git a/packages/core/src/data-module/types.d.ts b/packages/core/src/data-module/types.d.ts index 003cbae1a..0f9529fa1 100644 --- a/packages/core/src/data-module/types.d.ts +++ b/packages/core/src/data-module/types.d.ts @@ -1,6 +1,5 @@ -import { DataStream, DataStreamId, Resolution } from '@synchro-charts/core'; +import { DataStream as SynchroChartsDataStream, DataStreamId, Primitive, Resolution } from '@synchro-charts/core'; import { TimeSeriesDataRequest } from './data-cache/requestTypes'; -import { Request } from './data-cache/requestTypes'; import { DescribeAssetCommandInput, DescribeAssetCommandOutput, @@ -13,12 +12,17 @@ import { ListAssociatedAssetsCommandInput, ListAssociatedAssetsCommandOutput, } from '@aws-sdk/client-iotsitewise'; +import { RefId } from '../data-sources/site-wise/types'; -export type RequestInformation = { id: DataStreamId; resolution: Resolution }; +export type RequestInformation = { id: DataStreamId; resolution: Resolution; refId?: RefId }; export type RequestInformationAndRange = RequestInformation & { start: Date; end: Date }; export type DataSourceName = string; +export type DataStream = SynchroChartsDataStream & { + refId?: RefId; +}; + export type DataSource = { // An identifier for the name of the source, i.e. 'site-wise', 'roci', etc.. name: DataSourceName; // this is unique @@ -132,3 +136,13 @@ export interface DataModule { registerDataSource: RegisterDataSourcePrivate; subscribeToDataStreams: SubscribeToDataStreamsPrivate; } + +export type StyleSettingsMap = { [refId: string]: BaseStyleSettings }; + +// Style settings sharable by all components +export type BaseStyleSettings = { + name?: string; + detailedName?: string; + color?: string; // CSS color string, i.e. 'red' or '#ffffff' + unit?: string; +}; diff --git a/packages/core/src/data-sources/site-wise-legacy/data-source.ts b/packages/core/src/data-sources/site-wise-legacy/data-source.ts index 72d5b9351..f005ff834 100644 --- a/packages/core/src/data-sources/site-wise-legacy/data-source.ts +++ b/packages/core/src/data-sources/site-wise-legacy/data-source.ts @@ -1,5 +1,5 @@ -import { DataStream, DataStreamId } from '@synchro-charts/core'; -import { DataSource, RequestInformation } from '../../data-module/types.d'; +import { DataStreamId } from '@synchro-charts/core'; +import { DataSource, DataStream, RequestInformation } from '../../data-module/types.d'; import { OnRequestData } from '../../data-module/data-cache/requestTypes'; import { SiteWiseLegacyDataStreamQuery } from './types.d'; @@ -22,8 +22,8 @@ export const createSiteWiseLegacyDataSource = ( request, resolution: info.resolution, onError: () => {}, - onSuccess: (id: DataStreamId, data: DataStream) => { - onSuccess([data]); + onSuccess: (id: DataStreamId, dataStream: DataStream) => { + onSuccess([dataStream]); }, dataStreamId: info.id, }); diff --git a/packages/core/src/data-sources/site-wise/data-source.spec.ts b/packages/core/src/data-sources/site-wise/data-source.spec.ts index 9e2b0b9ab..54b7a3616 100644 --- a/packages/core/src/data-sources/site-wise/data-source.spec.ts +++ b/packages/core/src/data-sources/site-wise/data-source.spec.ts @@ -760,3 +760,35 @@ describe('aggregated data', () => { expect(onSuccess).not.toBeCalled(); }); }); + +describe('gets requests from query', () => { + it("appends refId's to the requests from the query", () => { + const mockSDK = createSiteWiseSDK({}); + + const dataSource = createDataSource(mockSDK); + const REF_ID = 'some-ref'; + + const query: SiteWiseDataStreamQuery = { + source: SITEWISE_DATA_SOURCE, + assets: [ + { + assetId: 'asset', + properties: [ + { + propertyId: 'some-property', + refId: REF_ID, + }, + ], + }, + ], + }; + + const request = { + viewport: { + duration: '1d', + }, + }; + + expect(dataSource.getRequestsFromQuery({ query, request })).toEqual([expect.objectContaining({ refId: REF_ID })]); + }); +}); diff --git a/packages/core/src/data-sources/site-wise/data-source.ts b/packages/core/src/data-sources/site-wise/data-source.ts index 6ff903f0d..6b5b0defc 100644 --- a/packages/core/src/data-sources/site-wise/data-source.ts +++ b/packages/core/src/data-sources/site-wise/data-source.ts @@ -211,8 +211,9 @@ export const createDataSource = (siteWise: IoTSiteWiseClient): DataSource - properties.map(({ propertyId, resolution: resolutionOverride }) => ({ + properties.map(({ propertyId, resolution: resolutionOverride, refId }) => ({ id: toDataStreamId({ assetId, propertyId }), + refId, resolution: RESOLUTION_TO_MS_MAPPING[resolutionOverride || resolution], })) ); diff --git a/packages/core/src/data-sources/site-wise/dataStreamFromSiteWise.ts b/packages/core/src/data-sources/site-wise/dataStreamFromSiteWise.ts index e7b1f97bd..dea3c9565 100644 --- a/packages/core/src/data-sources/site-wise/dataStreamFromSiteWise.ts +++ b/packages/core/src/data-sources/site-wise/dataStreamFromSiteWise.ts @@ -1,6 +1,7 @@ -import { DataPoint, DataStream, DataType } from '@synchro-charts/core'; +import { DataPoint, DataType } from '@synchro-charts/core'; import { AssetId, AssetPropertyId } from './types'; import { toDataStreamId } from './util/dataStreamId'; +import { DataStream } from '../../data-module/types.d'; export const dataStreamFromSiteWise = ({ assetId,