diff --git a/packages/components/src/components.d.ts b/packages/components/src/components.d.ts index 9f7103e5c..aa34a05be 100644 --- a/packages/components/src/components.d.ts +++ b/packages/components/src/components.d.ts @@ -5,12 +5,12 @@ * It contains typing information for all components that exist in this project. */ import { HTMLStencilElement, JSXBase } from "@stencil/core/internal"; -import { AnyDataStreamQuery, AssetSummaryQuery, AssetTreeSubscription, DataStream, IoTAppKitSession, SiteWiseAssetTreeQuery, StyleSettingsMap, TimeSeriesDataRequest, TimeSeriesDataRequestSettings } from "@iot-app-kit/core"; -import { MinimalViewPortConfig } from "@synchro-charts/core"; +import { AssetSummaryQuery, AssetTreeSubscription, IoTAppKit, Provider, SiteWiseAssetTreeQuery, SiteWiseTimeSeriesDataProvider, StyleSettingsMap, TimeSeriesData, TimeSeriesQuery } from "@iot-app-kit/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"; import { NonCancelableCustomEvent } from "@awsui/components-react"; +import { MinimalViewPortConfig } from "@synchro-charts/core"; export namespace Components { interface IotAssetDetails { "query": AssetSummaryQuery; @@ -20,42 +20,28 @@ export namespace Components { "subscription": AssetTreeSubscription; } interface IotBarChart { - "appKitSession": IoTAppKitSession; + "appKit": IoTAppKit; "isEditing": boolean | undefined; - "queries": AnyDataStreamQuery[]; - "settings": TimeSeriesDataRequestSettings | undefined; + "query": TimeSeriesQuery; "styleSettings": StyleSettingsMap | undefined; - "viewport": MinimalViewPortConfig; "widgetId": string; } - interface IotConnector { - "appKitSession": IoTAppKitSession; - "queries": AnyDataStreamQuery[]; - "renderFunc": ({ dataStreams }: { dataStreams: DataStream[] }) => unknown; - "request": TimeSeriesDataRequest; - "styleSettings": StyleSettingsMap | undefined; - } interface IotKpi { - "appKitSession": IoTAppKitSession; + "appKit": IoTAppKit; "isEditing": boolean | undefined; - "queries": AnyDataStreamQuery[]; - "settings": TimeSeriesDataRequestSettings | undefined; + "query": TimeSeriesQuery; "styleSettings": StyleSettingsMap | undefined; - "viewport": MinimalViewPortConfig; "widgetId": string; } interface IotLineChart { - "appKitSession": IoTAppKitSession; + "appKit": IoTAppKit; "isEditing": boolean | undefined; - "queries": AnyDataStreamQuery[]; - "settings": TimeSeriesDataRequestSettings | undefined; + "query": TimeSeriesQuery; "styleSettings": StyleSettingsMap | undefined; - "styles": StyleSettingsMap | undefined; - "viewport": MinimalViewPortConfig; "widgetId": string; } interface IotResourceExplorer { - "appKitSession": IoTAppKitSession; + "appKit": IoTAppKit; "columnDefinitions"?: ColumnDefinition[]; "empty"?: EmptyStateProps; "filterEnabled": boolean; @@ -71,42 +57,40 @@ export namespace Components { interface IotResourceExplorerDemo { } interface IotScatterChart { - "appKitSession": IoTAppKitSession; + "appKit": IoTAppKit; "isEditing": boolean | undefined; - "queries": AnyDataStreamQuery[]; - "settings": TimeSeriesDataRequestSettings | undefined; + "query": TimeSeriesQuery; "styleSettings": StyleSettingsMap | undefined; - "viewport": MinimalViewPortConfig; "widgetId": string; } interface IotStatusGrid { - "appKitSession": IoTAppKitSession; + "appKit": IoTAppKit; "isEditing": boolean | undefined; - "queries": AnyDataStreamQuery[]; - "settings": TimeSeriesDataRequestSettings | undefined; + "query": TimeSeriesQuery; "styleSettings": StyleSettingsMap | undefined; - "viewport": MinimalViewPortConfig; "widgetId": string; } interface IotStatusTimeline { - "appKitSession": IoTAppKitSession; + "appKit": IoTAppKit; "isEditing": boolean | undefined; - "queries": AnyDataStreamQuery[]; - "settings": TimeSeriesDataRequestSettings | undefined; + "query": TimeSeriesQuery; "styleSettings": StyleSettingsMap | undefined; - "viewport": MinimalViewPortConfig; "widgetId": string; } interface IotTable { - "appKitSession": IoTAppKitSession; - "queries": AnyDataStreamQuery[]; - "settings": TimeSeriesDataRequestSettings | undefined; + "appKit": IoTAppKit; + "query": TimeSeriesQuery; "styleSettings": StyleSettingsMap | undefined; - "viewport": MinimalViewPortConfig; "widgetId": string; } interface IotTestRoutes { } + interface IotTimeSeriesConnector { + "initialViewport": MinimalViewPortConfig; + "provider": Provider; + "renderFunc": (data: TimeSeriesData) => void; + "styleSettings": StyleSettingsMap | undefined; + } interface IotTreeTable { "ariaLabels": TableProps.AriaLabels; "collectionOptions": UseTreeCollection; @@ -128,7 +112,7 @@ export namespace Components { interface IotTreeTableDemo { } interface SitewiseResourceExplorer { - "appKitSession": IoTAppKitSession; + "appKit": IoTAppKit; "columnDefinitions": ColumnDefinition[]; "empty"?: EmptyStateProps; "filterEnabled": boolean; @@ -163,12 +147,6 @@ declare global { prototype: HTMLIotBarChartElement; new (): HTMLIotBarChartElement; }; - interface HTMLIotConnectorElement extends Components.IotConnector, HTMLStencilElement { - } - var HTMLIotConnectorElement: { - prototype: HTMLIotConnectorElement; - new (): HTMLIotConnectorElement; - }; interface HTMLIotKpiElement extends Components.IotKpi, HTMLStencilElement { } var HTMLIotKpiElement: { @@ -223,6 +201,12 @@ declare global { prototype: HTMLIotTestRoutesElement; new (): HTMLIotTestRoutesElement; }; + interface HTMLIotTimeSeriesConnectorElement extends Components.IotTimeSeriesConnector, HTMLStencilElement { + } + var HTMLIotTimeSeriesConnectorElement: { + prototype: HTMLIotTimeSeriesConnectorElement; + new (): HTMLIotTimeSeriesConnectorElement; + }; interface HTMLIotTreeTableElement extends Components.IotTreeTable, HTMLStencilElement { } var HTMLIotTreeTableElement: { @@ -251,7 +235,6 @@ declare global { "iot-asset-details": HTMLIotAssetDetailsElement; "iot-asset-tree-demo": HTMLIotAssetTreeDemoElement; "iot-bar-chart": HTMLIotBarChartElement; - "iot-connector": HTMLIotConnectorElement; "iot-kpi": HTMLIotKpiElement; "iot-line-chart": HTMLIotLineChartElement; "iot-resource-explorer": HTMLIotResourceExplorerElement; @@ -261,6 +244,7 @@ declare global { "iot-status-timeline": HTMLIotStatusTimelineElement; "iot-table": HTMLIotTableElement; "iot-test-routes": HTMLIotTestRoutesElement; + "iot-time-series-connector": HTMLIotTimeSeriesConnectorElement; "iot-tree-table": HTMLIotTreeTableElement; "iot-tree-table-demo": HTMLIotTreeTableDemoElement; "sitewise-resource-explorer": HTMLSitewiseResourceExplorerElement; @@ -276,42 +260,28 @@ declare namespace LocalJSX { "subscription"?: AssetTreeSubscription; } interface IotBarChart { - "appKitSession"?: IoTAppKitSession; + "appKit"?: IoTAppKit; "isEditing"?: boolean | undefined; - "queries"?: AnyDataStreamQuery[]; - "settings"?: TimeSeriesDataRequestSettings | undefined; + "query"?: TimeSeriesQuery; "styleSettings"?: StyleSettingsMap | undefined; - "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } - interface IotConnector { - "appKitSession"?: IoTAppKitSession; - "queries"?: AnyDataStreamQuery[]; - "renderFunc"?: ({ dataStreams }: { dataStreams: DataStream[] }) => unknown; - "request"?: TimeSeriesDataRequest; - "styleSettings"?: StyleSettingsMap | undefined; - } interface IotKpi { - "appKitSession"?: IoTAppKitSession; + "appKit"?: IoTAppKit; "isEditing"?: boolean | undefined; - "queries"?: AnyDataStreamQuery[]; - "settings"?: TimeSeriesDataRequestSettings | undefined; + "query"?: TimeSeriesQuery; "styleSettings"?: StyleSettingsMap | undefined; - "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } interface IotLineChart { - "appKitSession"?: IoTAppKitSession; + "appKit"?: IoTAppKit; "isEditing"?: boolean | undefined; - "queries"?: AnyDataStreamQuery[]; - "settings"?: TimeSeriesDataRequestSettings | undefined; + "query"?: TimeSeriesQuery; "styleSettings"?: StyleSettingsMap | undefined; - "styles"?: StyleSettingsMap | undefined; - "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } interface IotResourceExplorer { - "appKitSession"?: IoTAppKitSession; + "appKit"?: IoTAppKit; "columnDefinitions"?: ColumnDefinition[]; "empty"?: EmptyStateProps; "filterEnabled"?: boolean; @@ -327,42 +297,40 @@ declare namespace LocalJSX { interface IotResourceExplorerDemo { } interface IotScatterChart { - "appKitSession"?: IoTAppKitSession; + "appKit"?: IoTAppKit; "isEditing"?: boolean | undefined; - "queries"?: AnyDataStreamQuery[]; - "settings"?: TimeSeriesDataRequestSettings | undefined; + "query"?: TimeSeriesQuery; "styleSettings"?: StyleSettingsMap | undefined; - "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } interface IotStatusGrid { - "appKitSession"?: IoTAppKitSession; + "appKit"?: IoTAppKit; "isEditing"?: boolean | undefined; - "queries"?: AnyDataStreamQuery[]; - "settings"?: TimeSeriesDataRequestSettings | undefined; + "query"?: TimeSeriesQuery; "styleSettings"?: StyleSettingsMap | undefined; - "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } interface IotStatusTimeline { - "appKitSession"?: IoTAppKitSession; + "appKit"?: IoTAppKit; "isEditing"?: boolean | undefined; - "queries"?: AnyDataStreamQuery[]; - "settings"?: TimeSeriesDataRequestSettings | undefined; + "query"?: TimeSeriesQuery; "styleSettings"?: StyleSettingsMap | undefined; - "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } interface IotTable { - "appKitSession"?: IoTAppKitSession; - "queries"?: AnyDataStreamQuery[]; - "settings"?: TimeSeriesDataRequestSettings | undefined; + "appKit"?: IoTAppKit; + "query"?: TimeSeriesQuery; "styleSettings"?: StyleSettingsMap | undefined; - "viewport"?: MinimalViewPortConfig; "widgetId"?: string; } interface IotTestRoutes { } + interface IotTimeSeriesConnector { + "initialViewport"?: MinimalViewPortConfig; + "provider"?: Provider; + "renderFunc"?: (data: TimeSeriesData) => void; + "styleSettings"?: StyleSettingsMap | undefined; + } interface IotTreeTable { "ariaLabels"?: TableProps.AriaLabels; "collectionOptions": UseTreeCollection; @@ -384,7 +352,7 @@ declare namespace LocalJSX { interface IotTreeTableDemo { } interface SitewiseResourceExplorer { - "appKitSession"?: IoTAppKitSession; + "appKit"?: IoTAppKit; "columnDefinitions"?: ColumnDefinition[]; "empty"?: EmptyStateProps; "filterEnabled"?: boolean; @@ -403,7 +371,6 @@ declare namespace LocalJSX { "iot-asset-details": IotAssetDetails; "iot-asset-tree-demo": IotAssetTreeDemo; "iot-bar-chart": IotBarChart; - "iot-connector": IotConnector; "iot-kpi": IotKpi; "iot-line-chart": IotLineChart; "iot-resource-explorer": IotResourceExplorer; @@ -413,6 +380,7 @@ declare namespace LocalJSX { "iot-status-timeline": IotStatusTimeline; "iot-table": IotTable; "iot-test-routes": IotTestRoutes; + "iot-time-series-connector": IotTimeSeriesConnector; "iot-tree-table": IotTreeTable; "iot-tree-table-demo": IotTreeTableDemo; "sitewise-resource-explorer": SitewiseResourceExplorer; @@ -426,7 +394,6 @@ declare module "@stencil/core" { "iot-asset-details": LocalJSX.IotAssetDetails & JSXBase.HTMLAttributes; "iot-asset-tree-demo": LocalJSX.IotAssetTreeDemo & JSXBase.HTMLAttributes; "iot-bar-chart": LocalJSX.IotBarChart & JSXBase.HTMLAttributes; - "iot-connector": LocalJSX.IotConnector & JSXBase.HTMLAttributes; "iot-kpi": LocalJSX.IotKpi & JSXBase.HTMLAttributes; "iot-line-chart": LocalJSX.IotLineChart & JSXBase.HTMLAttributes; "iot-resource-explorer": LocalJSX.IotResourceExplorer & JSXBase.HTMLAttributes; @@ -436,6 +403,7 @@ declare module "@stencil/core" { "iot-status-timeline": LocalJSX.IotStatusTimeline & JSXBase.HTMLAttributes; "iot-table": LocalJSX.IotTable & JSXBase.HTMLAttributes; "iot-test-routes": LocalJSX.IotTestRoutes & JSXBase.HTMLAttributes; + "iot-time-series-connector": LocalJSX.IotTimeSeriesConnector & JSXBase.HTMLAttributes; "iot-tree-table": LocalJSX.IotTreeTable & JSXBase.HTMLAttributes; "iot-tree-table-demo": LocalJSX.IotTreeTableDemo & JSXBase.HTMLAttributes; "sitewise-resource-explorer": LocalJSX.SitewiseResourceExplorer & JSXBase.HTMLAttributes; diff --git a/packages/components/src/components/iot-connector/bindStylesToDataStreams.spec.ts b/packages/components/src/components/common/bindStylesToDataStreams.spec.ts similarity index 100% rename from packages/components/src/components/iot-connector/bindStylesToDataStreams.spec.ts rename to packages/components/src/components/common/bindStylesToDataStreams.spec.ts diff --git a/packages/components/src/components/iot-connector/bindStylesToDataStreams.ts b/packages/components/src/components/common/bindStylesToDataStreams.ts similarity index 100% rename from packages/components/src/components/iot-connector/bindStylesToDataStreams.ts rename to packages/components/src/components/common/bindStylesToDataStreams.ts diff --git a/packages/components/src/components/iot-asset-details/iot-asset-details.tsx b/packages/components/src/components/iot-asset-details/iot-asset-details.tsx index c4d8c088f..222add48d 100644 --- a/packages/components/src/components/iot-asset-details/iot-asset-details.tsx +++ b/packages/components/src/components/iot-asset-details/iot-asset-details.tsx @@ -7,7 +7,6 @@ import { AssetPropertyValueQuery, } from '@iot-app-kit/core'; import { AssetPropertyValue, AssetSummary, DescribeAssetModelResponse } from '@aws-sdk/client-iotsitewise'; -import { AssetModelProperty } from '@aws-sdk/client-iotsitewise/dist-types/models/models_0'; @Component({ tag: 'iot-asset-details', diff --git a/packages/components/src/components/iot-bar-chart/iot-bar-chart.spec.ts b/packages/components/src/components/iot-bar-chart/iot-bar-chart.spec.ts index 343c2112e..2d62c11b1 100644 --- a/packages/components/src/components/iot-bar-chart/iot-bar-chart.spec.ts +++ b/packages/components/src/components/iot-bar-chart/iot-bar-chart.spec.ts @@ -2,10 +2,10 @@ import { newSpecPage } from '@stencil/core/testing'; import { MinimalLiveViewport } from '@synchro-charts/core'; import { IotBarChart } from './iot-bar-chart'; import { Components } from '../../components.d'; -import { initialize, SiteWiseDataStreamQuery } from '@iot-app-kit/core'; +import { initialize, query, SiteWiseDataStreamQuery } from '@iot-app-kit/core'; import { createMockSource } from '../../testing/createMockSource'; import { DATA_STREAM } from '../../testing/mockWidgetProperties'; -import { IotConnector } from '../iot-connector/iot-connector'; +import { IotTimeSeriesConnector } from '../iot-time-series-connector.ts/iot-time-series-connector'; import { CustomHTMLElement } from '../../testing/types'; import { update } from '../../testing/update'; @@ -14,26 +14,34 @@ const viewport: MinimalLiveViewport = { }; const barChartSpecPage = async (propOverrides: Partial = {}) => { - const appKitSession = initialize({ registerDataSources: false }).session(); - appKitSession.registerDataSource(createMockSource([DATA_STREAM])); + const appKit = initialize({ + registerDataSources: false, + awsCredentials: { accessKeyId: 'test', secretAccessKey: 'test' }, + awsRegion: 'test', + }); + appKit.registerTimeSeriesDataSource(createMockSource([DATA_STREAM])); const page = await newSpecPage({ - components: [IotBarChart, IotConnector], + components: [IotBarChart, IotTimeSeriesConnector], html: '
', supportsShadowDom: false, }); const barChart = page.doc.createElement('iot-bar-chart') as CustomHTMLElement; const props: Partial = { - appKitSession, + appKit, widgetId: 'test-bar-chart-widget', isEditing: false, - queries: [ - { - source: 'test-mock', - assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], - } as SiteWiseDataStreamQuery, - ], - viewport, + query: query.iotsitewise.timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], + } as SiteWiseDataStreamQuery, + ], + request: { + viewport, + }, + }), ...propOverrides, }; update(barChart, props); 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 4193e693f..c48d6b7c5 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,55 +1,57 @@ -import { Component, Prop, h } from '@stencil/core'; -import { MinimalViewPortConfig, DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; +import { Component, Prop, h, Listen, State, Watch } from '@stencil/core'; +import { DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; import { - AnyDataStreamQuery, TimeSeriesDataRequestSettings, StyleSettingsMap, - IoTAppKitSession, + SiteWiseTimeSeriesDataProvider, + IoTAppKit, + TimeSeriesQuery, } from '@iot-app-kit/core'; -const DEFAULT_VIEWPORT = { duration: 10 * 1000 * 60 }; - @Component({ tag: 'iot-bar-chart', shadow: false, }) export class IotBarChart { - @Prop() appKitSession: IoTAppKitSession; - - @Prop() queries: AnyDataStreamQuery[]; + @Prop() appKit: IoTAppKit; - @Prop() viewport: MinimalViewPortConfig = DEFAULT_VIEWPORT; + @Prop() query: TimeSeriesQuery; @Prop() widgetId: string; @Prop() isEditing: boolean | undefined; - @Prop() settings: TimeSeriesDataRequestSettings | undefined; - @Prop() styleSettings: StyleSettingsMap | undefined; - getSettings(): TimeSeriesDataRequestSettings { - return { - ...this.settings, - fetchFromStartToEnd: true, - }; + @State() provider: SiteWiseTimeSeriesDataProvider; + + private defaultSettings: TimeSeriesDataRequestSettings = { + fetchFromStartToEnd: true, + }; + + componentWillLoad() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Watch('query') + private onQueryUpdate() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Listen('dateRangeChange') + private handleDateRangeChange({ detail: [start, end, lastUpdatedBy] }: { detail: [Date, Date, string | undefined] }) { + this.provider.updateViewport({ start, end, lastUpdatedBy }); } render() { - const settings = this.getSettings(); return ( - ( diff --git a/packages/components/src/components/iot-connector/iot-connector.spec.ts b/packages/components/src/components/iot-connector/iot-connector.spec.ts deleted file mode 100644 index 6217c618b..000000000 --- a/packages/components/src/components/iot-connector/iot-connector.spec.ts +++ /dev/null @@ -1,299 +0,0 @@ -import { newSpecPage } from '@stencil/core/testing'; -import { MinimalLiveViewport } from '@synchro-charts/core'; -import flushPromises from 'flush-promises'; -import { initialize, SiteWiseDataStreamQuery, IoTAppKitInitInputs, createMockSiteWiseSDK } from '@iot-app-kit/core'; -import { IotConnector } from './iot-connector'; -import { createMockSource } from '../../testing/createMockSource'; -import { update } from '../../testing/update'; -import { CustomHTMLElement } from '../../testing/types'; -import { DATA_STREAM, DATA_STREAM_2 } from '../../testing/mockWidgetProperties'; -import { toSiteWiseAssetProperty } from '../../testing/dataStreamId'; -import { Components } from '../../components'; -import { DescribeAssetResponse, DescribeAssetModelResponse } from '@aws-sdk/client-iotsitewise'; - -const createAssetResponse = ({ - assetId, - assetModelId, -}: { - assetId: string; - assetModelId: string; -}): DescribeAssetResponse => ({ - assetId: assetId, - assetName: `${assetId}-name`, - assetModelId, - assetCreationDate: undefined, - assetLastUpdateDate: undefined, - assetStatus: undefined, - assetHierarchies: [], - assetProperties: [], - assetArn: undefined, -}); - -const createAssetModelResponse = ({ - propertyId, - assetModelId, -}: { - propertyId: string; - assetModelId: string; -}): DescribeAssetModelResponse => ({ - assetModelId, - assetModelName: `${assetModelId}-name`, - assetModelDescription: undefined, - assetModelProperties: [ - { - id: propertyId, - dataType: 'DOUBLE', - name: 'property-name', - unit: 'm/s', - type: undefined, - }, - ], - assetModelStatus: undefined, - assetModelCompositeModels: [], - assetModelHierarchies: [], - assetModelCreationDate: undefined, - assetModelLastUpdateDate: undefined, - assetModelArn: undefined, -}); - -const viewport: MinimalLiveViewport = { - duration: 1000, -}; - -const connectorSpecPage = async ( - propOverrides: Partial = {}, - appKitInitOverrides: Partial = {} -) => { - /** Initialize data source and register mock data source */ - const appKitSession = initialize({ registerDataSources: false, ...appKitInitOverrides }).session(); - appKitSession.registerDataSource(createMockSource([DATA_STREAM, DATA_STREAM_2])); - - const page = await newSpecPage({ - components: [IotConnector], - html: '
', - supportsShadowDom: false, - }); - const connector = page.doc.createElement('iot-connector') as CustomHTMLElement; - const props: Partial = { - appKitSession, - queries: [ - { - source: 'test-mock', - assets: [], - } as SiteWiseDataStreamQuery, - ], // static casting because of legacy sw - request: { viewport, settings: { fetchMostRecentBeforeEnd: true } }, - ...propOverrides, - }; - update(connector, props); - page.body.appendChild(connector); - - await page.waitForChanges(); - - return { page, connector }; -}; - -it('renders', async () => { - const renderFunc = jest.fn(); - await connectorSpecPage({ renderFunc }); - await flushPromises(); - expect(renderFunc).toBeCalledTimes(1); - expect(renderFunc).toBeCalledWith({ dataStreams: [] }); -}); - -it('provides data streams', async () => { - const renderFunc = jest.fn(); - const { assetId: assetId_1, propertyId: propertyId_1 } = toSiteWiseAssetProperty(DATA_STREAM.id); - const { assetId: assetId_2, propertyId: propertyId_2 } = toSiteWiseAssetProperty(DATA_STREAM_2.id); - - await connectorSpecPage({ - renderFunc, - queries: [ - { - source: 'test-mock', - assets: [{ assetId: assetId_1, properties: [{ propertyId: propertyId_1 }] }], - } as SiteWiseDataStreamQuery, - { - source: 'test-mock', - assets: [{ assetId: assetId_2, properties: [{ propertyId: propertyId_2 }] }], - } as SiteWiseDataStreamQuery, - ], - }); - - await flushPromises(); - - expect(renderFunc).lastCalledWith({ - dataStreams: [ - expect.objectContaining({ - id: DATA_STREAM.id, - }), - expect.objectContaining({ - id: DATA_STREAM_2.id, - }), - ], - }); -}); - -it('populates the name, unit, and data type from the asset model information from SiteWise', async () => { - const renderFunc = jest.fn(); - const { assetId: assetId_1, propertyId: propertyId_1 } = toSiteWiseAssetProperty(DATA_STREAM.id); - const assetModelId = `${assetId_1}-asset-model`; - - await connectorSpecPage( - { - renderFunc, - queries: [ - { - source: 'test-mock', - assets: [{ assetId: assetId_1, properties: [{ propertyId: propertyId_1 }] }], - } as SiteWiseDataStreamQuery, - ], - }, - { - iotSiteWiseClient: createMockSiteWiseSDK({ - describeAsset: ({ assetId }) => - Promise.resolve(createAssetResponse({ assetId: assetId as string, assetModelId })), - describeAssetModel: ({ assetModelId }) => - Promise.resolve(createAssetModelResponse({ assetModelId: assetModelId as string, propertyId: propertyId_1 })), - }), - } - ); - - await flushPromises(); - - expect(renderFunc).lastCalledWith({ - dataStreams: [ - expect.objectContaining({ - id: DATA_STREAM.id, - name: 'property-name', - unit: 'm/s', - dataType: 'NUMBER', - }), - ], - }); -}); - -// TODO: Implement updating behavior to make this test pass. -it.skip('populates the name, unit, and data type from the asset model information from SiteWise when updating the connector', async () => { - const renderFunc = jest.fn(); - const { assetId: assetId_1, propertyId: propertyId_1 } = toSiteWiseAssetProperty(DATA_STREAM.id); - const assetModelId = `${assetId_1}-asset-model`; - - const { connector, page } = await connectorSpecPage( - { - renderFunc, - queries: [ - { - source: 'test-mock', - assets: [], - } as SiteWiseDataStreamQuery, - ], - }, - { - iotSiteWiseClient: createMockSiteWiseSDK({ - describeAsset: ({ assetId }) => - Promise.resolve(createAssetResponse({ assetId: assetId as string, assetModelId })), - describeAssetModel: ({ assetModelId }) => - Promise.resolve(createAssetModelResponse({ assetModelId: assetModelId as string, propertyId: propertyId_1 })), - }), - } - ); - - await flushPromises(); - - connector.queries = [ - { - source: 'test-mock', - assets: [{ assetId: assetId_1, properties: [{ propertyId: propertyId_1 }] }], - } as SiteWiseDataStreamQuery, - ]; - - await page.waitForChanges(); - await flushPromises(); - - expect(renderFunc).lastCalledWith({ - dataStreams: [ - expect.objectContaining({ - id: DATA_STREAM.id, - name: 'property-name', - unit: 'm/s', - dataType: 'NUMBER', - }), - ], - }); -}); - -it('updates with new queries', async () => { - const { assetId: assetId_1, propertyId: propertyId_1 } = toSiteWiseAssetProperty(DATA_STREAM.id); - const { assetId: assetId_2, propertyId: propertyId_2 } = toSiteWiseAssetProperty(DATA_STREAM_2.id); - - const renderFunc = jest.fn(); - const { connector, page } = await connectorSpecPage({ - renderFunc, - queries: [ - { - source: 'test-mock', - assets: [], - } as SiteWiseDataStreamQuery, - ], - }); - await flushPromises(); - - connector.queries = [ - { - source: 'test-mock', - assets: [{ assetId: assetId_1, properties: [{ propertyId: propertyId_1 }] }], - } as SiteWiseDataStreamQuery, - { - source: 'test-mock', - assets: [{ assetId: assetId_2, properties: [{ propertyId: propertyId_2 }] }], - } as SiteWiseDataStreamQuery, - ]; - - await page.waitForChanges(); - await flushPromises(); - - expect(renderFunc).lastCalledWith({ - dataStreams: [ - expect.objectContaining({ - id: DATA_STREAM.id, - }), - expect.objectContaining({ - id: DATA_STREAM_2.id, - }), - ], - }); -}); - -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 deleted file mode 100644 index a7f70740d..000000000 --- a/packages/components/src/components/iot-connector/iot-connector.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { Component, Listen, Prop, State, Watch } from '@stencil/core'; -import isEqual from 'lodash.isequal'; -import { - AnyDataStreamQuery, - SubscriptionUpdate, - DataStream, - TimeSeriesDataRequest, - StyleSettingsMap, - IoTAppKitSession, -} from '@iot-app-kit/core'; -import { bindStylesToDataStreams } from './bindStylesToDataStreams'; - -@Component({ - tag: 'iot-connector', - shadow: false, -}) -export class IotConnector { - @Prop() appKitSession: IoTAppKitSession; - - @Prop() queries: AnyDataStreamQuery[]; - - @Prop() request: TimeSeriesDataRequest; - - @Prop() renderFunc: ({ dataStreams }: { dataStreams: DataStream[] }) => unknown; - - @Prop() styleSettings: StyleSettingsMap | undefined; - - @State() dataStreams: DataStream[] = []; - - private update: (subscriptionUpdate: SubscriptionUpdate) => void; - - private unsubscribe: () => void; - - componentWillLoad() { - // Subscribe to data module for the requested `query` - const { update, unsubscribe } = this.appKitSession.subscribeToTimeSeriesData( - { - queries: this.queries, - request: this.request, - }, - ({ dataStreams }) => { - this.dataStreams = bindStylesToDataStreams({ dataStreams, styleSettings: this.styleSettings }); - } - ); - - // Store references to lifecycle methods - this.update = update; - this.unsubscribe = unsubscribe; - } - - componentDidUnmount() { - this.unsubscribe(); - } - - /** - * Sync subscription to change in queried data - */ - @Watch('request') - @Watch('queries') - onUpdateProp(newProp: unknown, oldProp: unknown) { - if (!isEqual(newProp, oldProp) && this.update != null) { - this.update({ - queries: this.queries, - request: this.request, - }); - } - } - - @Listen('dateRangeChange') - private handleDateRangeChange({ detail: [start, end, lastUpdatedBy] }: { detail: [Date, Date, string | undefined] }) { - if (this.update != null) { - this.update({ - request: { - ...this.request, - viewport: { start, end, lastUpdatedBy }, - }, - }); - } - } - - render() { - const { dataStreams } = this; - - return this.renderFunc({ dataStreams }); - } -} diff --git a/packages/components/src/components/iot-kpi/iot-kpi.spec.ts b/packages/components/src/components/iot-kpi/iot-kpi.spec.ts index 379656863..b68239b3d 100644 --- a/packages/components/src/components/iot-kpi/iot-kpi.spec.ts +++ b/packages/components/src/components/iot-kpi/iot-kpi.spec.ts @@ -1,10 +1,10 @@ import { newSpecPage } from '@stencil/core/testing'; -import { SiteWiseDataStreamQuery, initialize } from '@iot-app-kit/core'; +import { SiteWiseDataStreamQuery, initialize, query } from '@iot-app-kit/core'; import { MinimalLiveViewport } from '@synchro-charts/core'; import { IotKpi } from './iot-kpi'; import { Components } from '../../components.d'; import { createMockSource } from '../../testing/createMockSource'; -import { IotConnector } from '../iot-connector/iot-connector'; +import { IotTimeSeriesConnector } from '../iot-time-series-connector.ts/iot-time-series-connector'; import { CustomHTMLElement } from '../../testing/types'; import { update } from '../../testing/update'; import { DATA_STREAM } from '../../testing/mockWidgetProperties'; @@ -14,26 +14,34 @@ const viewport: MinimalLiveViewport = { }; const kpiSpecPage = async (propOverrides: Partial = {}) => { - const appKitSession = initialize({ registerDataSources: false }).session(); - appKitSession.registerDataSource(createMockSource([DATA_STREAM])); + const appKit = initialize({ + registerDataSources: false, + awsCredentials: { accessKeyId: 'test', secretAccessKey: 'test' }, + awsRegion: 'test', + }); + appKit.registerTimeSeriesDataSource(createMockSource([DATA_STREAM])); const page = await newSpecPage({ - components: [IotKpi, IotConnector], + components: [IotKpi, IotTimeSeriesConnector], html: '
', supportsShadowDom: false, }); const kpi = page.doc.createElement('iot-kpi') as CustomHTMLElement; const props: Partial = { - appKitSession, + appKit, widgetId: 'test-kpi-widget', isEditing: false, - queries: [ - { - source: 'test-mock', - assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], - } as SiteWiseDataStreamQuery, - ], // static casting because of legacy sw - viewport, + query: query.iotsitewise.timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], + } as SiteWiseDataStreamQuery, + ], + request: { + viewport, + }, + }), ...propOverrides, }; update(kpi, props); diff --git a/packages/components/src/components/iot-kpi/iot-kpi.tsx b/packages/components/src/components/iot-kpi/iot-kpi.tsx index bbbf16756..21a8daf91 100644 --- a/packages/components/src/components/iot-kpi/iot-kpi.tsx +++ b/packages/components/src/components/iot-kpi/iot-kpi.tsx @@ -1,55 +1,57 @@ -import { Component, Prop, h } from '@stencil/core'; -import { MinimalViewPortConfig, DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; +import { Component, Prop, h, State, Listen, Watch } from '@stencil/core'; +import { DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; import { - AnyDataStreamQuery, - TimeSeriesDataRequestSettings, StyleSettingsMap, - IoTAppKitSession, + SiteWiseTimeSeriesDataProvider, + IoTAppKit, + TimeSeriesQuery, + TimeSeriesDataRequestSettings, } from '@iot-app-kit/core'; -const DEFAULT_VIEWPORT = { duration: 10 * 1000 }; - @Component({ tag: 'iot-kpi', shadow: false, }) export class IotKpi { - @Prop() appKitSession: IoTAppKitSession; + @Prop() appKit: IoTAppKit; - @Prop() queries: AnyDataStreamQuery[]; - - @Prop() viewport: MinimalViewPortConfig = DEFAULT_VIEWPORT; + @Prop() query: TimeSeriesQuery; @Prop() widgetId: string; @Prop() isEditing: boolean | undefined; - @Prop() settings: TimeSeriesDataRequestSettings | undefined; - @Prop() styleSettings: StyleSettingsMap | undefined; - getSettings(): TimeSeriesDataRequestSettings { - return { - ...this.settings, - fetchMostRecentBeforeEnd: true, - }; + @State() provider: SiteWiseTimeSeriesDataProvider; + + private defaultSettings: TimeSeriesDataRequestSettings = { + fetchMostRecentBeforeEnd: true, + }; + + componentWillLoad() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Watch('query') + private onQueryUpdate() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Listen('dateRangeChange') + private handleDateRangeChange({ detail: [start, end, lastUpdatedBy] }: { detail: [Date, Date, string | undefined] }) { + this.provider.updateViewport({ start, end, lastUpdatedBy }); } render() { - const settings = this.getSettings(); return ( - ( diff --git a/packages/components/src/components/iot-line-chart/iot-line-chart.spec.ts b/packages/components/src/components/iot-line-chart/iot-line-chart.spec.ts index 5ef710cb7..8018b3fbd 100644 --- a/packages/components/src/components/iot-line-chart/iot-line-chart.spec.ts +++ b/packages/components/src/components/iot-line-chart/iot-line-chart.spec.ts @@ -5,8 +5,8 @@ import { Components } from '../../components.d'; import { createMockSource } from '../../testing/createMockSource'; import { DATA_STREAM } from '../../testing/mockWidgetProperties'; import { CustomHTMLElement } from '../../testing/types'; -import { initialize, SiteWiseDataStreamQuery } from '@iot-app-kit/core'; -import { IotConnector } from '../iot-connector/iot-connector'; +import { initialize, query, SiteWiseDataStreamQuery } from '@iot-app-kit/core'; +import { IotTimeSeriesConnector } from '../iot-time-series-connector.ts/iot-time-series-connector'; import { update } from '../../testing/update'; const viewport: MinimalLiveViewport = { @@ -14,26 +14,34 @@ const viewport: MinimalLiveViewport = { }; const lineChartSpecPage = async (propOverrides: Partial = {}) => { - const appKitSession = initialize({ registerDataSources: false }).session(); - appKitSession.registerDataSource(createMockSource([DATA_STREAM])); + const appKit = initialize({ + registerDataSources: false, + awsCredentials: { accessKeyId: 'test', secretAccessKey: 'test' }, + awsRegion: 'test', + }); + appKit.registerTimeSeriesDataSource(createMockSource([DATA_STREAM])); const page = await newSpecPage({ - components: [IotLineChart, IotConnector], + components: [IotLineChart, IotTimeSeriesConnector], html: '
', supportsShadowDom: false, }); const lineChart = page.doc.createElement('iot-line-chart') as CustomHTMLElement; const props: Partial = { - appKitSession, + appKit, widgetId: 'test-line-chart-widget', isEditing: false, - queries: [ - { - source: 'test-mock', - assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], - } as SiteWiseDataStreamQuery, - ], // static casting because of legacy sw - viewport, + query: query.iotsitewise.timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], + } as SiteWiseDataStreamQuery, + ], + request: { + viewport, + }, + }), ...propOverrides, }; update(lineChart, props); diff --git a/packages/components/src/components/iot-line-chart/iot-line-chart.tsx b/packages/components/src/components/iot-line-chart/iot-line-chart.tsx index bd19b57ec..adb89b585 100644 --- a/packages/components/src/components/iot-line-chart/iot-line-chart.tsx +++ b/packages/components/src/components/iot-line-chart/iot-line-chart.tsx @@ -1,61 +1,59 @@ -import { Component, Prop, h } from '@stencil/core'; -import { MinimalViewPortConfig, DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; +import { Component, Prop, h, Listen, State, Watch } from '@stencil/core'; +import { DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; import { - AnyDataStreamQuery, - DataModule, - TimeSeriesDataRequestSettings, StyleSettingsMap, - IoTAppKitSession, + IoTAppKit, + SiteWiseTimeSeriesDataProvider, + TimeSeriesQuery, + TimeSeriesDataRequestSettings, } from '@iot-app-kit/core'; -const DEFAULT_VIEWPORT = { duration: 10 * 1000 * 60 }; - @Component({ tag: 'iot-line-chart', shadow: false, }) export class IotLineChart { - @Prop() appKitSession: IoTAppKitSession; + @Prop() appKit: IoTAppKit; - @Prop() queries: AnyDataStreamQuery[]; - - @Prop() viewport: MinimalViewPortConfig = DEFAULT_VIEWPORT; + @Prop() query: TimeSeriesQuery; @Prop() widgetId: string; @Prop() isEditing: boolean | undefined; - @Prop() settings: TimeSeriesDataRequestSettings | undefined; + @Prop() styleSettings: StyleSettingsMap | undefined; - @Prop() styles: StyleSettingsMap | undefined; + @State() provider: SiteWiseTimeSeriesDataProvider; - @Prop() styleSettings: StyleSettingsMap | undefined; + private defaultSettings: TimeSeriesDataRequestSettings = { + fetchFromStartToEnd: true, + fetchMostRecentBeforeStart: true, + }; - getSettings(): TimeSeriesDataRequestSettings { - return { - ...this.settings, - fetchFromStartToEnd: true, - // Required to be able to draw line from last point visible, to first point before the viewport. - fetchMostRecentBeforeStart: true, - }; + componentWillLoad() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Watch('query') + private onQueryUpdate() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Listen('dateRangeChange') + private handleDateRangeChange({ detail: [start, end, lastUpdatedBy] }: { detail: [Date, Date, string | undefined] }) { + this.provider.updateViewport({ start, end, lastUpdatedBy }); } render() { - const settings = this.getSettings(); return ( - { return ( diff --git a/packages/components/src/components/iot-resource-explorer/iot-resource-explorer.spec.ts b/packages/components/src/components/iot-resource-explorer/iot-resource-explorer.spec.ts index ac6616e38..f0c496c02 100644 --- a/packages/components/src/components/iot-resource-explorer/iot-resource-explorer.spec.ts +++ b/packages/components/src/components/iot-resource-explorer/iot-resource-explorer.spec.ts @@ -12,8 +12,12 @@ const resourceExplorerSpec = async ( propOverrides: Partial, appKitInitOverrides: Partial = {} ) => { - const appKitSession = initialize({ registerDataSources: false, ...appKitInitOverrides }).session(); - + const appKit = initialize({ + registerDataSources: false, + awsCredentials: { accessKeyId: 'test', secretAccessKey: 'test' }, + awsRegion: 'test', + ...appKitInitOverrides, + }); const page = await newSpecPage({ components: [IotResourceExplorer], html: '
', @@ -24,7 +28,7 @@ const resourceExplorerSpec = async ( 'iot-resource-explorer' ) as CustomHTMLElement; const props: Partial = { - appKitSession, + appKit, query, ...propOverrides, }; diff --git a/packages/components/src/components/iot-resource-explorer/iot-resource-explorer.tsx b/packages/components/src/components/iot-resource-explorer/iot-resource-explorer.tsx index 353b10304..5cd2eb9ef 100644 --- a/packages/components/src/components/iot-resource-explorer/iot-resource-explorer.tsx +++ b/packages/components/src/components/iot-resource-explorer/iot-resource-explorer.tsx @@ -1,5 +1,5 @@ import { Component, h, Prop } from '@stencil/core'; -import { IoTAppKitSession, SiteWiseAssetTreeQuery } from '@iot-app-kit/core'; +import { IoTAppKit } from '@iot-app-kit/core'; import { ColumnDefinition, SitewiseAssetResource } from './types'; import { EmptyStateProps } from '@iot-app-kit/related-table'; import { isSiteWiseQuery } from './utils'; @@ -11,7 +11,7 @@ import { NonCancelableCustomEvent } from '@awsui/components-react'; tag: 'iot-resource-explorer', }) export class IotResourceExplorer { - @Prop() appKitSession: IoTAppKitSession; + @Prop() appKit: IoTAppKit; @Prop() query: ResourceExplorerQuery; @Prop() columnDefinitions?: ColumnDefinition[]; @Prop() filterTexts?: FilterTexts; @@ -56,7 +56,7 @@ export class IotResourceExplorer { if (isSiteWiseQuery(this.query)) { return ( , appKitInitOverrides: Partial = {} ) => { - const appKitSession = initialize({ registerDataSources: false, ...appKitInitOverrides }).session(); + const appKit = initialize({ + registerDataSources: false, + awsCredentials: { accessKeyId: 'test', secretAccessKey: 'test' }, + awsRegion: 'test', + ...appKitInitOverrides, + }); const page = await newSpecPage({ components: [SitewiseResourceExplorer], @@ -34,7 +39,7 @@ const sitewiseResourceExplorerSpec = async ( 'sitewise-resource-explorer' ) as CustomHTMLElement; const props: Partial = { - appKitSession, + appKit, query, columnDefinitions, ...propOverrides, diff --git a/packages/components/src/components/iot-resource-explorer/sitewise-resource-explorer.tsx b/packages/components/src/components/iot-resource-explorer/sitewise-resource-explorer.tsx index f2bbbe258..ad98ea846 100644 --- a/packages/components/src/components/iot-resource-explorer/sitewise-resource-explorer.tsx +++ b/packages/components/src/components/iot-resource-explorer/sitewise-resource-explorer.tsx @@ -2,7 +2,7 @@ import { Component, h, Prop, State } from '@stencil/core'; import { AssetTreeSubscription, BranchReference, - IoTAppKitSession, + IoTAppKit, SiteWiseAssetTreeNode, SiteWiseAssetTreeQuery, } from '@iot-app-kit/core'; @@ -17,7 +17,7 @@ import { NonCancelableCustomEvent } from '@awsui/components-react'; tag: 'sitewise-resource-explorer', }) export class SitewiseResourceExplorer { - @Prop() appKitSession: IoTAppKitSession; + @Prop() appKit: IoTAppKit; @Prop() query: SiteWiseAssetTreeQuery; @Prop() columnDefinitions: ColumnDefinition[]; @Prop() filterTexts?: FilterTexts; @@ -50,12 +50,9 @@ export class SitewiseResourceExplorer { subscription: AssetTreeSubscription; componentWillLoad() { - this.subscription = this.appKitSession.iotsitewise.subscribeToAssetTree( - this.query, - (newTree: SiteWiseAssetTreeNode[]) => { - this.items = parseSitewiseAssetTree(newTree); - } - ); + this.subscription = this.appKit.subscribeToAssetTree(this.query, (newTree: SiteWiseAssetTreeNode[]) => { + this.items = parseSitewiseAssetTree(newTree); + }); } componentWillUnmount() { diff --git a/packages/components/src/components/iot-scatter-chart/iot-scatter-chart.spec.ts b/packages/components/src/components/iot-scatter-chart/iot-scatter-chart.spec.ts index f8bd55eba..cd58fd6fb 100644 --- a/packages/components/src/components/iot-scatter-chart/iot-scatter-chart.spec.ts +++ b/packages/components/src/components/iot-scatter-chart/iot-scatter-chart.spec.ts @@ -2,9 +2,9 @@ import { newSpecPage } from '@stencil/core/testing'; import { MinimalLiveViewport } from '@synchro-charts/core'; import { IotScatterChart } from './iot-scatter-chart'; import { Components } from '../../components.d'; -import { initialize, SiteWiseDataStreamQuery } from '@iot-app-kit/core'; +import { initialize, query, SiteWiseDataStreamQuery } from '@iot-app-kit/core'; import { createMockSource } from '../../testing/createMockSource'; -import { IotConnector } from '../iot-connector/iot-connector'; +import { IotTimeSeriesConnector } from '../iot-time-series-connector.ts/iot-time-series-connector'; import { CustomHTMLElement } from '../../testing/types'; import { DATA_STREAM } from '../../testing/mockWidgetProperties'; import { update } from '../../testing/update'; @@ -14,26 +14,34 @@ const viewport: MinimalLiveViewport = { }; const scatterChartSpecPage = async (propOverrides: Partial = {}) => { - const appKitSession = initialize({ registerDataSources: false }).session(); - appKitSession.registerDataSource(createMockSource([DATA_STREAM])); + const appKit = initialize({ + registerDataSources: false, + awsCredentials: { accessKeyId: 'test', secretAccessKey: 'test' }, + awsRegion: 'test', + }); + appKit.registerTimeSeriesDataSource(createMockSource([DATA_STREAM])); const page = await newSpecPage({ - components: [IotScatterChart, IotConnector], + components: [IotScatterChart, IotTimeSeriesConnector], html: '
', supportsShadowDom: false, }); const scatterChart = page.doc.createElement('iot-scatter-chart') as CustomHTMLElement; const props: Partial = { - appKitSession, + appKit, widgetId: 'test-scatter-chart-widget', isEditing: false, - queries: [ - { - source: 'test-mock', - assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], - } as SiteWiseDataStreamQuery, - ], // static casting because of legacy sw - viewport, + query: query.iotsitewise.timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], + } as SiteWiseDataStreamQuery, + ], + request: { + viewport, + }, + }), ...propOverrides, }; update(scatterChart, props); diff --git a/packages/components/src/components/iot-scatter-chart/iot-scatter-chart.tsx b/packages/components/src/components/iot-scatter-chart/iot-scatter-chart.tsx index b5931ca53..6c8ea5631 100644 --- a/packages/components/src/components/iot-scatter-chart/iot-scatter-chart.tsx +++ b/packages/components/src/components/iot-scatter-chart/iot-scatter-chart.tsx @@ -1,56 +1,57 @@ -import { Component, Prop, h } from '@stencil/core'; -import { MinimalViewPortConfig, DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; +import { Component, Prop, h, Listen, State, Watch } from '@stencil/core'; +import { DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; import { - AnyDataStreamQuery, - DataModule, - TimeSeriesDataRequestSettings, StyleSettingsMap, - IoTAppKitSession, + SiteWiseTimeSeriesDataProvider, + IoTAppKit, + TimeSeriesQuery, + TimeSeriesDataRequestSettings, } from '@iot-app-kit/core'; -const DEFAULT_VIEWPORT = { duration: 10 * 1000 * 60 }; - @Component({ tag: 'iot-scatter-chart', shadow: false, }) export class IotScatterChart { - @Prop() appKitSession: IoTAppKitSession; + @Prop() appKit: IoTAppKit; - @Prop() queries: AnyDataStreamQuery[]; - - @Prop() viewport: MinimalViewPortConfig = DEFAULT_VIEWPORT; + @Prop() query: TimeSeriesQuery; @Prop() widgetId: string; @Prop() isEditing: boolean | undefined; - @Prop() settings: TimeSeriesDataRequestSettings | undefined; - @Prop() styleSettings: StyleSettingsMap | undefined; - getSettings(): TimeSeriesDataRequestSettings { - return { - ...this.settings, - fetchFromStartToEnd: true, - }; + @State() provider: SiteWiseTimeSeriesDataProvider; + + private defaultSettings: TimeSeriesDataRequestSettings = { + fetchFromStartToEnd: true, + }; + + componentWillLoad() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Watch('query') + private onQueryUpdate() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Listen('dateRangeChange') + private handleDateRangeChange({ detail: [start, end, lastUpdatedBy] }: { detail: [Date, Date, string | undefined] }) { + this.provider.updateViewport({ start, end, lastUpdatedBy }); } render() { - const settings = this.getSettings(); return ( - ( diff --git a/packages/components/src/components/iot-status-grid/iot-status-grid.spec.ts b/packages/components/src/components/iot-status-grid/iot-status-grid.spec.ts index ba1c0d3c3..45aee331d 100644 --- a/packages/components/src/components/iot-status-grid/iot-status-grid.spec.ts +++ b/packages/components/src/components/iot-status-grid/iot-status-grid.spec.ts @@ -2,10 +2,10 @@ import { newSpecPage } from '@stencil/core/testing'; import { MinimalLiveViewport } from '@synchro-charts/core'; import { IotStatusGrid } from './iot-status-grid'; import { Components } from '../../components.d'; -import { initialize, SiteWiseDataStreamQuery } from '@iot-app-kit/core'; +import { initialize, query, SiteWiseDataStreamQuery } from '@iot-app-kit/core'; import { createMockSource } from '../../testing/createMockSource'; import { DATA_STREAM } from '../../testing/mockWidgetProperties'; -import { IotConnector } from '../iot-connector/iot-connector'; +import { IotTimeSeriesConnector } from '../iot-time-series-connector.ts/iot-time-series-connector'; import { CustomHTMLElement } from '../../testing/types'; import { update } from '../../testing/update'; @@ -14,26 +14,34 @@ const viewport: MinimalLiveViewport = { }; const statusGridSpecPage = async (propOverrides: Partial = {}) => { - const appKitSession = initialize({ registerDataSources: false }).session(); - appKitSession.registerDataSource(createMockSource([DATA_STREAM])); + const appKit = initialize({ + registerDataSources: false, + awsCredentials: { accessKeyId: 'test', secretAccessKey: 'test' }, + awsRegion: 'test', + }); + appKit.registerTimeSeriesDataSource(createMockSource([DATA_STREAM])); const page = await newSpecPage({ - components: [IotStatusGrid, IotConnector], + components: [IotStatusGrid, IotTimeSeriesConnector], html: '
', supportsShadowDom: false, }); const statusGrid = page.doc.createElement('iot-status-grid') as CustomHTMLElement; const props: Partial = { - appKitSession, + appKit, widgetId: 'test-status-grid-widget', isEditing: false, - queries: [ - { - source: 'test-mock', - assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], - } as SiteWiseDataStreamQuery, - ], // static casting because of legacy sw - viewport, + query: query.iotsitewise.timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], + } as SiteWiseDataStreamQuery, + ], + request: { + viewport, + }, + }), ...propOverrides, }; update(statusGrid, props); diff --git a/packages/components/src/components/iot-status-grid/iot-status-grid.tsx b/packages/components/src/components/iot-status-grid/iot-status-grid.tsx index 1c370e521..c87fef6fe 100644 --- a/packages/components/src/components/iot-status-grid/iot-status-grid.tsx +++ b/packages/components/src/components/iot-status-grid/iot-status-grid.tsx @@ -1,55 +1,57 @@ -import { Component, Prop, h } from '@stencil/core'; -import { MinimalViewPortConfig, DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; +import { Component, Prop, h, State, Listen, Watch } from '@stencil/core'; +import { DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; import { - AnyDataStreamQuery, - TimeSeriesDataRequestSettings, StyleSettingsMap, - IoTAppKitSession, + IoTAppKit, + SiteWiseTimeSeriesDataProvider, + TimeSeriesQuery, + TimeSeriesDataRequestSettings, } from '@iot-app-kit/core'; -const DEFAULT_VIEWPORT = { duration: 10 * 1000 * 60 }; - @Component({ tag: 'iot-status-grid', shadow: false, }) export class IotStatusGrid { - @Prop() appKitSession: IoTAppKitSession; + @Prop() appKit: IoTAppKit; - @Prop() queries: AnyDataStreamQuery[]; - - @Prop() viewport: MinimalViewPortConfig = DEFAULT_VIEWPORT; + @Prop() query: TimeSeriesQuery; @Prop() widgetId: string; @Prop() isEditing: boolean | undefined; - @Prop() settings: TimeSeriesDataRequestSettings | undefined; - @Prop() styleSettings: StyleSettingsMap | undefined; - getSettings(): TimeSeriesDataRequestSettings { - return { - ...this.settings, - fetchMostRecentBeforeEnd: true, - }; + @State() provider: SiteWiseTimeSeriesDataProvider; + + private defaultSettings: TimeSeriesDataRequestSettings = { + fetchMostRecentBeforeEnd: true, + }; + + componentWillLoad() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Watch('query') + private onQueryUpdate() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Listen('dateRangeChange') + private handleDateRangeChange({ detail: [start, end, lastUpdatedBy] }: { detail: [Date, Date, string | undefined] }) { + this.provider.updateViewport({ start, end, lastUpdatedBy }); } render() { - const settings = this.getSettings(); return ( - ( diff --git a/packages/components/src/components/iot-status-timeline/iot-status-timeline.spec.ts b/packages/components/src/components/iot-status-timeline/iot-status-timeline.spec.ts index 21b885336..733c62418 100644 --- a/packages/components/src/components/iot-status-timeline/iot-status-timeline.spec.ts +++ b/packages/components/src/components/iot-status-timeline/iot-status-timeline.spec.ts @@ -2,10 +2,10 @@ import { newSpecPage } from '@stencil/core/testing'; import { MinimalLiveViewport } from '@synchro-charts/core'; import { IotStatusTimeline } from './iot-status-timeline'; import { Components } from '../../components.d'; -import { registerDataSource, initialize, SiteWiseDataStreamQuery } from '@iot-app-kit/core'; +import { initialize, query, SiteWiseDataStreamQuery } from '@iot-app-kit/core'; import { createMockSource } from '../../testing/createMockSource'; import { DATA_STREAM } from '../../testing/mockWidgetProperties'; -import { IotConnector } from '../iot-connector/iot-connector'; +import { IotTimeSeriesConnector } from '../iot-time-series-connector.ts/iot-time-series-connector'; import { CustomHTMLElement } from '../../testing/types'; import { update } from '../../testing/update'; @@ -14,11 +14,15 @@ const viewport: MinimalLiveViewport = { }; const statusTimelineSpecPage = async (propOverrides: Partial = {}) => { - const appKitSession = initialize({ registerDataSources: false }).session(); - appKitSession.registerDataSource(createMockSource([DATA_STREAM])); + const appKit = initialize({ + registerDataSources: false, + awsCredentials: { accessKeyId: 'test', secretAccessKey: 'test' }, + awsRegion: 'test', + }); + appKit.registerTimeSeriesDataSource(createMockSource([DATA_STREAM])); const page = await newSpecPage({ - components: [IotStatusTimeline, IotConnector], + components: [IotStatusTimeline, IotTimeSeriesConnector], html: '
', supportsShadowDom: false, }); @@ -26,16 +30,20 @@ const statusTimelineSpecPage = async (propOverrides: Partial; const props: Partial = { - appKitSession, + appKit, widgetId: 'test-status-timeline-chart-widget', isEditing: false, - queries: [ - { - source: 'test-mock', - assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], - } as SiteWiseDataStreamQuery, - ], // static casting because of legacy sw - viewport, + query: query.iotsitewise.timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], + } as SiteWiseDataStreamQuery, + ], + request: { + viewport, + }, + }), ...propOverrides, }; update(statusTimeline, props); diff --git a/packages/components/src/components/iot-status-timeline/iot-status-timeline.tsx b/packages/components/src/components/iot-status-timeline/iot-status-timeline.tsx index 771d56a47..6b3c0ff1b 100644 --- a/packages/components/src/components/iot-status-timeline/iot-status-timeline.tsx +++ b/packages/components/src/components/iot-status-timeline/iot-status-timeline.tsx @@ -1,56 +1,58 @@ -import { Component, Prop, h } from '@stencil/core'; -import { MinimalViewPortConfig, DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; +import { Component, Prop, h, Listen, State, Watch } from '@stencil/core'; +import { DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; import { - AnyDataStreamQuery, - TimeSeriesDataRequestSettings, StyleSettingsMap, - IoTAppKitSession, + SiteWiseTimeSeriesDataProvider, + IoTAppKit, + TimeSeriesQuery, + TimeSeriesDataRequestSettings, } from '@iot-app-kit/core'; -const DEFAULT_VIEWPORT = { duration: 10 * 1000 * 60 }; - @Component({ tag: 'iot-status-timeline', shadow: false, }) export class IotStatusTimeline { - @Prop() appKitSession: IoTAppKitSession; + @Prop() appKit: IoTAppKit; - @Prop() queries: AnyDataStreamQuery[]; - - @Prop() viewport: MinimalViewPortConfig = DEFAULT_VIEWPORT; + @Prop() query: TimeSeriesQuery; @Prop() widgetId: string; @Prop() isEditing: boolean | undefined; - @Prop() settings: TimeSeriesDataRequestSettings | undefined; - @Prop() styleSettings: StyleSettingsMap | undefined; - getSettings(): TimeSeriesDataRequestSettings { - return { - ...this.settings, - fetchMostRecentBeforeStart: true, - fetchFromStartToEnd: true, - }; + @State() provider: SiteWiseTimeSeriesDataProvider; + + private defaultSettings: TimeSeriesDataRequestSettings = { + fetchMostRecentBeforeStart: true, + fetchFromStartToEnd: true, + }; + + componentWillLoad() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Watch('query') + private onQueryUpdate() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Listen('dateRangeChange') + private handleDateRangeChange({ detail: [start, end, lastUpdatedBy] }: { detail: [Date, Date, string | undefined] }) { + this.provider.updateViewport({ start, end, lastUpdatedBy }); } render() { - const settings = this.getSettings(); return ( - ( diff --git a/packages/components/src/components/iot-table/iot-table.spec.ts b/packages/components/src/components/iot-table/iot-table.spec.ts index 40525da25..2f548b7ab 100644 --- a/packages/components/src/components/iot-table/iot-table.spec.ts +++ b/packages/components/src/components/iot-table/iot-table.spec.ts @@ -2,10 +2,10 @@ import { newSpecPage } from '@stencil/core/testing'; import { MinimalLiveViewport } from '@synchro-charts/core'; import { IotTable } from './iot-table'; import { Components } from '../../components.d'; -import { initialize, SiteWiseDataStreamQuery } from '@iot-app-kit/core'; +import { initialize, query, SiteWiseDataStreamQuery } from '@iot-app-kit/core'; import { createMockSource } from '../../testing/createMockSource'; import { DATA_STREAM } from '../../testing/mockWidgetProperties'; -import { IotConnector } from '../iot-connector/iot-connector'; +import { IotTimeSeriesConnector } from '../iot-time-series-connector.ts/iot-time-series-connector'; import { CustomHTMLElement } from '../../testing/types'; import { update } from '../../testing/update'; @@ -14,26 +14,34 @@ const viewport: MinimalLiveViewport = { }; const tableSpecPage = async (propOverrides: Partial = {}) => { - const appKitSession = initialize({ registerDataSources: false }).session(); - appKitSession.registerDataSource(createMockSource([DATA_STREAM])); + const appKit = initialize({ + registerDataSources: false, + awsCredentials: { accessKeyId: 'test', secretAccessKey: 'test' }, + awsRegion: 'test', + }); + appKit.registerTimeSeriesDataSource(createMockSource([DATA_STREAM])); const page = await newSpecPage({ - components: [IotTable, IotConnector], + components: [IotTable, IotTimeSeriesConnector], html: '
', supportsShadowDom: false, }); const table = page.doc.createElement('iot-table') as CustomHTMLElement; const props: Partial = { - appKitSession, + appKit, widgetId: 'test-table-widget', isEditing: false, - queries: [ - { - source: 'test-mock', - assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], - } as SiteWiseDataStreamQuery, - ], // static casting because of legacy sw - viewport, + query: query.iotsitewise.timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [{ assetId: 'some-asset-id', properties: [{ propertyId: 'some-property-id' }] }], + } as SiteWiseDataStreamQuery, + ], + request: { + viewport, + }, + }), ...propOverrides, }; diff --git a/packages/components/src/components/iot-table/iot-table.tsx b/packages/components/src/components/iot-table/iot-table.tsx index e310a8d4f..b890484fc 100644 --- a/packages/components/src/components/iot-table/iot-table.tsx +++ b/packages/components/src/components/iot-table/iot-table.tsx @@ -1,53 +1,55 @@ -import { Component, Prop, h } from '@stencil/core'; -import { MinimalViewPortConfig, DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; +import { Component, Prop, h, State, Listen, Watch } from '@stencil/core'; +import { DataStream as SynchroChartsDataStream } from '@synchro-charts/core'; import { - AnyDataStreamQuery, - TimeSeriesDataRequestSettings, StyleSettingsMap, - IoTAppKitSession, + SiteWiseTimeSeriesDataProvider, + IoTAppKit, + TimeSeriesQuery, + TimeSeriesDataRequestSettings, } from '@iot-app-kit/core'; -const DEFAULT_VIEWPORT = { duration: 10 * 1000 * 60 }; - @Component({ tag: 'iot-table', shadow: false, }) export class IotTable { - @Prop() appKitSession: IoTAppKitSession; + @Prop() appKit: IoTAppKit; - @Prop() queries: AnyDataStreamQuery[]; - - @Prop() viewport: MinimalViewPortConfig = DEFAULT_VIEWPORT; + @Prop() query: TimeSeriesQuery; @Prop() widgetId: string; - @Prop() settings: TimeSeriesDataRequestSettings | undefined; - @Prop() styleSettings: StyleSettingsMap | undefined; - getSettings(): TimeSeriesDataRequestSettings { - return { - ...this.settings, - fetchMostRecentBeforeEnd: true, - }; + @State() provider: SiteWiseTimeSeriesDataProvider; + + private defaultSettings: TimeSeriesDataRequestSettings = { + fetchMostRecentBeforeEnd: true, + }; + + componentWillLoad() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Watch('query') + private onQueryUpdate() { + this.provider = this.query.build(this.appKit.session(this.widgetId), this.defaultSettings); + } + + @Listen('dateRangeChange') + private handleDateRangeChange({ detail: [start, end, lastUpdatedBy] }: { detail: [Date, Date, string | undefined] }) { + this.provider.updateViewport({ start, end, lastUpdatedBy }); } render() { - const settings = this.getSettings(); return ( - ( )} diff --git a/packages/components/src/components/iot-time-series-connector.ts/iot-time-series-connector.spec.ts b/packages/components/src/components/iot-time-series-connector.ts/iot-time-series-connector.spec.ts new file mode 100644 index 000000000..5ee86c1cc --- /dev/null +++ b/packages/components/src/components/iot-time-series-connector.ts/iot-time-series-connector.spec.ts @@ -0,0 +1,371 @@ +import { newSpecPage } from '@stencil/core/testing'; +import { MinimalLiveViewport } from '@synchro-charts/core'; +import flushPromises from 'flush-promises'; +import { + initialize, + SiteWiseDataStreamQuery, + IoTAppKitInitInputs, + createMockSiteWiseSDK, + query, +} from '@iot-app-kit/core'; +import { IotTimeSeriesConnector } from './iot-time-series-connector'; +import { createMockSource } from '../../testing/createMockSource'; +import { update } from '../../testing/update'; +import { CustomHTMLElement } from '../../testing/types'; +import { DATA_STREAM, DATA_STREAM_2 } from '../../testing/mockWidgetProperties'; +import { toSiteWiseAssetProperty } from '../../testing/dataStreamId'; +import { Components } from '../../components'; +import { DescribeAssetResponse, DescribeAssetModelResponse } from '@aws-sdk/client-iotsitewise'; + +const createAssetResponse = ({ + assetId, + assetModelId, +}: { + assetId: string; + assetModelId: string; +}): DescribeAssetResponse => ({ + assetId: assetId, + assetName: `${assetId}-name`, + assetModelId, + assetCreationDate: undefined, + assetLastUpdateDate: undefined, + assetStatus: undefined, + assetHierarchies: [], + assetProperties: [], + assetArn: undefined, +}); + +const createAssetModelResponse = ({ + propertyId, + assetModelId, +}: { + propertyId: string; + assetModelId: string; +}): DescribeAssetModelResponse => ({ + assetModelId, + assetModelName: `${assetModelId}-name`, + assetModelDescription: undefined, + assetModelProperties: [ + { + id: propertyId, + dataType: 'DOUBLE', + name: 'property-name', + unit: 'm/s', + type: undefined, + }, + ], + assetModelStatus: undefined, + assetModelCompositeModels: [], + assetModelHierarchies: [], + assetModelCreationDate: undefined, + assetModelLastUpdateDate: undefined, + assetModelArn: undefined, +}); + +const viewport: MinimalLiveViewport = { + duration: 1000, +}; + +const initializeAppKit = (appKitInitOverrides?: Partial) => { + const appKit = initialize({ + registerDataSources: false, + awsCredentials: { accessKeyId: 'test', secretAccessKey: 'test' }, + awsRegion: 'test', + ...appKitInitOverrides, + }); + + appKit.registerTimeSeriesDataSource(createMockSource([DATA_STREAM, DATA_STREAM_2])); + + return appKit; +}; + +const connectorSpecPage = async (props: Partial) => { + const page = await newSpecPage({ + components: [IotTimeSeriesConnector], + html: '
', + supportsShadowDom: false, + }); + const connector = page.doc.createElement( + 'iot-time-series-connector' + ) as CustomHTMLElement; + + update(connector, props); + + page.body.appendChild(connector); + + await page.waitForChanges(); + + return { page, connector }; +}; + +it('renders', async () => { + const renderFunc = jest.fn(); + + const appKit = initializeAppKit(); + + await connectorSpecPage({ + renderFunc, + provider: query.iotsitewise + .timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [], + } as SiteWiseDataStreamQuery, + ], + request: { viewport, settings: { fetchMostRecentBeforeEnd: true } }, + }) + .build(appKit.session('widgetId')), + }); + + await flushPromises(); + + expect(renderFunc).toBeCalledTimes(1); + expect(renderFunc).toBeCalledWith({ dataStreams: [], viewport: { duration: 10 * 1000 * 60 } }); +}); + +it('provides data streams', async () => { + const renderFunc = jest.fn(); + + const { assetId: assetId_1, propertyId: propertyId_1 } = toSiteWiseAssetProperty(DATA_STREAM.id); + const { assetId: assetId_2, propertyId: propertyId_2 } = toSiteWiseAssetProperty(DATA_STREAM_2.id); + + const appKit = initializeAppKit(); + + await connectorSpecPage({ + renderFunc, + provider: query.iotsitewise + .timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [{ assetId: assetId_1, properties: [{ propertyId: propertyId_1 }] }], + } as SiteWiseDataStreamQuery, + { + source: 'test-mock', + assets: [{ assetId: assetId_2, properties: [{ propertyId: propertyId_2 }] }], + } as SiteWiseDataStreamQuery, + ], + request: { viewport, settings: { fetchMostRecentBeforeEnd: true } }, + }) + .build(appKit.session('widgetId')), + }); + + await flushPromises(); + + expect(renderFunc).lastCalledWith({ + dataStreams: [ + expect.objectContaining({ + id: DATA_STREAM.id, + }), + expect.objectContaining({ + id: DATA_STREAM_2.id, + }), + ], + viewport, + }); +}); + +it('populates the name, unit, and data type from the asset model information from SiteWise', async () => { + const renderFunc = jest.fn(); + + const { assetId: assetId_1, propertyId: propertyId_1 } = toSiteWiseAssetProperty(DATA_STREAM.id); + const assetModelId = `${assetId_1}-asset-model`; + + const appKit = initializeAppKit({ + iotSiteWiseClient: createMockSiteWiseSDK({ + describeAsset: ({ assetId }) => + Promise.resolve(createAssetResponse({ assetId: assetId as string, assetModelId })), + describeAssetModel: ({ assetModelId }) => + Promise.resolve(createAssetModelResponse({ assetModelId: assetModelId as string, propertyId: propertyId_1 })), + }), + }); + + await connectorSpecPage({ + renderFunc, + provider: query.iotsitewise + .timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [{ assetId: assetId_1, properties: [{ propertyId: propertyId_1 }] }], + } as SiteWiseDataStreamQuery, + ], + request: { viewport, settings: { fetchMostRecentBeforeEnd: true } }, + }) + .build(appKit.session('widgetId')), + }); + + await flushPromises(); + + expect(renderFunc).lastCalledWith({ + dataStreams: [ + expect.objectContaining({ + id: DATA_STREAM.id, + name: 'property-name', + unit: 'm/s', + dataType: 'NUMBER', + }), + ], + viewport, + }); +}); + +it('populates the name, unit, and data type from the asset model information from SiteWise when updating the connector', async () => { + const renderFunc = jest.fn(); + + const { assetId: assetId_1, propertyId: propertyId_1 } = toSiteWiseAssetProperty(DATA_STREAM.id); + const assetModelId = `${assetId_1}-asset-model`; + + const appKit = initializeAppKit({ + iotSiteWiseClient: createMockSiteWiseSDK({ + describeAsset: ({ assetId }) => + Promise.resolve(createAssetResponse({ assetId: assetId as string, assetModelId })), + describeAssetModel: ({ assetModelId }) => + Promise.resolve(createAssetModelResponse({ assetModelId: assetModelId as string, propertyId: propertyId_1 })), + }), + }); + + const { connector, page } = await connectorSpecPage({ + renderFunc, + provider: query.iotsitewise + .timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [], + } as SiteWiseDataStreamQuery, + ], + request: { viewport, settings: { fetchMostRecentBeforeEnd: true } }, + }) + .build(appKit.session('widgetId')), + }); + + await flushPromises(); + + connector.provider = query.iotsitewise + .timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [{ assetId: assetId_1, properties: [{ propertyId: propertyId_1 }] }], + } as SiteWiseDataStreamQuery, + ], + request: { viewport, settings: { fetchMostRecentBeforeEnd: true } }, + }) + .build(appKit.session('widgetId')); + + await page.waitForChanges(); + await flushPromises(); + + expect(renderFunc).lastCalledWith({ + dataStreams: [ + expect.objectContaining({ + id: DATA_STREAM.id, + name: 'property-name', + unit: 'm/s', + dataType: 'NUMBER', + }), + ], + viewport, + }); +}); + +it('updates with new queries', async () => { + const { assetId: assetId_1, propertyId: propertyId_1 } = toSiteWiseAssetProperty(DATA_STREAM.id); + const { assetId: assetId_2, propertyId: propertyId_2 } = toSiteWiseAssetProperty(DATA_STREAM_2.id); + + const renderFunc = jest.fn(); + + const appKit = initializeAppKit(); + + const { connector, page } = await connectorSpecPage({ + renderFunc, + provider: query.iotsitewise + .timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [], + } as SiteWiseDataStreamQuery, + ], + request: { viewport, settings: { fetchMostRecentBeforeEnd: true } }, + }) + .build(appKit.session('widgetId')), + }); + + await flushPromises(); + + connector.provider = query.iotsitewise + .timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [{ assetId: assetId_1, properties: [{ propertyId: propertyId_1 }] }], + } as SiteWiseDataStreamQuery, + { + source: 'test-mock', + assets: [{ assetId: assetId_2, properties: [{ propertyId: propertyId_2 }] }], + } as SiteWiseDataStreamQuery, + ], + request: { viewport, settings: { fetchMostRecentBeforeEnd: true } }, + }) + .build(appKit.session('widgetId')); + + await page.waitForChanges(); + + await flushPromises(); + + expect(renderFunc).lastCalledWith({ + dataStreams: [ + expect.objectContaining({ + id: DATA_STREAM.id, + }), + expect.objectContaining({ + id: DATA_STREAM_2.id, + }), + ], + viewport, + }); +}); + +it('binds styles to data streams', async () => { + const renderFunc = jest.fn(); + const { assetId, propertyId } = toSiteWiseAssetProperty(DATA_STREAM.id); + const REF_ID = 'some-ref-id'; + + const appKit = initializeAppKit(); + + await connectorSpecPage({ + renderFunc, + provider: query.iotsitewise + .timeSeriesData({ + queries: [ + { + source: 'test-mock', + assets: [{ assetId, properties: [{ propertyId, refId: REF_ID }] }], + } as SiteWiseDataStreamQuery, + ], + request: { viewport, settings: { fetchMostRecentBeforeEnd: true } }, + }) + .build(appKit.session('widgetId')), + styleSettings: { + [REF_ID]: { + color: 'red', + name: 'my-name', + }, + }, + }); + + expect(renderFunc).lastCalledWith({ + dataStreams: [ + expect.objectContaining({ + id: DATA_STREAM.id, + refId: REF_ID, + color: 'red', + name: 'my-name', + }), + ], + viewport, + }); +}); diff --git a/packages/components/src/components/iot-time-series-connector.ts/iot-time-series-connector.tsx b/packages/components/src/components/iot-time-series-connector.ts/iot-time-series-connector.tsx new file mode 100644 index 000000000..9d9e37e5c --- /dev/null +++ b/packages/components/src/components/iot-time-series-connector.ts/iot-time-series-connector.tsx @@ -0,0 +1,54 @@ +import { Component, Prop, State, Watch } from '@stencil/core'; +import { Provider, StyleSettingsMap, TimeSeriesData } from '@iot-app-kit/core'; +import { MinimalViewPortConfig } from '@synchro-charts/core'; +import { bindStylesToDataStreams } from '../common/bindStylesToDataStreams'; + +const DEFAULT_VIEWPORT = { duration: 10 * 1000 * 60 }; + +@Component({ + tag: 'iot-time-series-connector', + shadow: false, +}) +export class IotTimeSeriesConnector { + @Prop() provider: Provider; + + @Prop() renderFunc: (data: TimeSeriesData) => void; + + @Prop() initialViewport: MinimalViewPortConfig; + + @Prop() styleSettings: StyleSettingsMap | undefined; + + @State() data: TimeSeriesData = { + dataStreams: [], + viewport: DEFAULT_VIEWPORT, + }; + + componentWillLoad() { + this.provider.subscribe((data: TimeSeriesData) => { + this.data = data; + }); + } + + @Watch('provider') + private onProviderUpdate() { + this.provider.unsubscribe(); + + this.provider.subscribe((data: TimeSeriesData) => { + this.data = data; + }); + } + + componentDidUnmount() { + this.provider.unsubscribe(); + } + + render() { + const { data } = this; + const { dataStreams, viewport } = data; + + return this.renderFunc({ + dataStreams: bindStylesToDataStreams({ dataStreams, styleSettings: this.styleSettings }), + viewport, + }); + } +} diff --git a/packages/components/src/integration/iot-resource-explorer/setup.tsx b/packages/components/src/integration/iot-resource-explorer/setup.tsx index 51883c09e..d9ed63106 100644 --- a/packages/components/src/integration/iot-resource-explorer/setup.tsx +++ b/packages/components/src/integration/iot-resource-explorer/setup.tsx @@ -15,15 +15,15 @@ export const renderComponent = () => { }; }, render: function () { - const newDefaultAppKitSession = initialize({ + const newDefaultAppKit = initialize({ awsCredentials: { accessKeyId: 'accessKeyId', secretAccessKey: 'secretAccessKey', }, awsRegion: 'us-east-1', - }).session(); + }); const containerProps = { class: testContainerClassName }; - const compProps: any = { appKitSession: newDefaultAppKitSession, query: this.query }; + const compProps: any = { appKit: newDefaultAppKit, query: this.query }; return (
diff --git a/packages/components/src/testing/renderChart.tsx b/packages/components/src/testing/renderChart.tsx index 596fb34c2..fa634f6e8 100644 --- a/packages/components/src/testing/renderChart.tsx +++ b/packages/components/src/testing/renderChart.tsx @@ -1,13 +1,13 @@ import { mount } from '@cypress/vue'; import { h } from 'vue'; import { - SiteWiseDataStreamQuery, - TimeSeriesDataRequestSettings, StyleSettingsMap, initialize, - IoTAppKitSession, + IoTAppKit, + query, + TimeSeriesQuery, + SiteWiseTimeSeriesDataProvider, } from '@iot-app-kit/core'; -import { MinimalViewPortConfig } from '@synchro-charts/core'; import { MINUTE_IN_MS } from '@iot-app-kit/core/src/common/time'; const { applyPolyfills, defineCustomElements } = require('@iot-app-kit/components/loader'); import '@synchro-charts/core/dist/synchro-charts/synchro-charts.css'; @@ -18,28 +18,16 @@ export const testChartContainerClassName = 'test-chart-container'; export const testChartContainerClassNameSelector = `.${testChartContainerClassName}`; -const newDefaultAppKitSession = initialize({ +const newDefaultAppKit = initialize({ awsCredentials: { accessKeyId: 'accessKeyId', secretAccessKey: 'secretAccessKey', }, awsRegion: 'us-east-1', -}).session(); +}); const defaultChartType = 'iot-line-chart'; -const defaultQueries = [ - { - source: 'site-wise', - assets: [ - { - assetId: 'some-asset-id', - properties: [{ propertyId: 'some-property-id' }], - }, - ], - }, -]; - const defaultSettings = { resolution: { [3 * MINUTE_IN_MS]: '1m', @@ -52,27 +40,39 @@ const end = new Date(start.getTime() + 5 * MINUTE_IN_MS); const defaultViewport = { start, end }; +const defaultQuery = query.iotsitewise.timeSeriesData({ + queries: [ + { + source: 'site-wise', + assets: [ + { + assetId: 'some-asset-id', + properties: [{ propertyId: 'some-property-id' }], + }, + ], + }, + ], + request: { + viewport: defaultViewport, + settings: defaultSettings, + }, +}); + export const renderChart = ( { chartType = defaultChartType, - appKitSession = newDefaultAppKitSession, - queries = defaultQueries, - settings = defaultSettings, - viewport = defaultViewport, + appKit = newDefaultAppKit, + query = defaultQuery, styleSettings, }: { chartType?: string; - appKitSession?: IoTAppKitSession; - queries?: SiteWiseDataStreamQuery[]; - settings?: TimeSeriesDataRequestSettings; - viewport?: MinimalViewPortConfig; + appKit?: IoTAppKit; + query?: TimeSeriesQuery; styleSettings?: StyleSettingsMap; } = { chartType: defaultChartType, - appKitSession: newDefaultAppKitSession, - queries: defaultQueries, - settings: defaultSettings, - viewport: defaultViewport, + appKit: newDefaultAppKit, + query: defaultQuery, } ) => { mount({ @@ -83,7 +83,7 @@ export const renderChart = ( }, render: function () { const containerProps = { class: testChartContainerClassName, style: { width: '400px', height: '500px' } }; - const chartProps: any = { appKitSession, queries, settings, viewport, styleSettings }; + const chartProps: any = { appKit, query, styleSettings }; return (
diff --git a/packages/components/src/testing/resource-explorer/iot-resource-explorer-demo.tsx b/packages/components/src/testing/resource-explorer/iot-resource-explorer-demo.tsx index 80f6a82db..584dc6a1c 100644 --- a/packages/components/src/testing/resource-explorer/iot-resource-explorer-demo.tsx +++ b/packages/components/src/testing/resource-explorer/iot-resource-explorer-demo.tsx @@ -1,5 +1,5 @@ -import { Component, h, State } from '@stencil/core'; -import { initialize, IoTAppKitSession, SiteWiseAssetTreeQuery } from '@iot-app-kit/core'; +import { Component, h } from '@stencil/core'; +import { initialize, IoTAppKit, SiteWiseAssetTreeQuery } from '@iot-app-kit/core'; import { getEnvCredentials } from '../testing-ground/getEnvCredentials'; import { ResourceExplorerQuery } from '../../components/iot-resource-explorer/types'; @@ -8,15 +8,15 @@ import { ResourceExplorerQuery } from '../../components/iot-resource-explorer/ty styleUrl: '../../styles/awsui.css', }) export class IotResourceExplorerDemo { - private appKitSession: IoTAppKitSession; + private appKit: IoTAppKit; componentWillLoad() { - this.appKitSession = initialize({ awsCredentials: getEnvCredentials(), awsRegion: 'us-east-1' }).session(); + this.appKit = initialize({ awsCredentials: getEnvCredentials(), awsRegion: 'us-east-1' }); } query: ResourceExplorerQuery & SiteWiseAssetTreeQuery = { source: 'site-wise' }; render() { - return ; + return ; } } diff --git a/packages/components/src/testing/testing-ground/siteWiseQueries.ts b/packages/components/src/testing/testing-ground/siteWiseQueries.ts index 9cb96204e..c4d0d8dab 100644 --- a/packages/components/src/testing/testing-ground/siteWiseQueries.ts +++ b/packages/components/src/testing/testing-ground/siteWiseQueries.ts @@ -27,9 +27,9 @@ export const NUMBER_QUERY = { ], }; -const AGGREGATED_DATA_ASSET = '099b1330-83ff-4fec-b165-c7186ec8eb23'; -const AGGREGATED_DATA_PROPERTY = '05c5c47f-fd92-4823-828e-09ce63b90569'; -const AGGREGATED_DATA_PROPERTY_2 = '11d2599a-2547-451d-ab79-a47f878dbbe3'; +const AGGREGATED_DATA_ASSET = 'f2f74fa8-625a-435f-b89c-d27b2d84f45b'; +const AGGREGATED_DATA_PROPERTY = 'd0dc79be-0dc2-418c-ac23-26f33cdb4b8b'; +const AGGREGATED_DATA_PROPERTY_2 = '69607dc2-5fbe-416d-aac2-0382018626e4'; export const AGGREGATED_DATA_QUERY = { source: 'site-wise', diff --git a/packages/components/src/testing/testing-ground/testing-ground.tsx b/packages/components/src/testing/testing-ground/testing-ground.tsx index 337759f35..0c5ddb7cb 100755 --- a/packages/components/src/testing/testing-ground/testing-ground.tsx +++ b/packages/components/src/testing/testing-ground/testing-ground.tsx @@ -1,5 +1,5 @@ import { Component, State, h } from '@stencil/core'; -import { initialize, ResolutionConfig, IoTAppKitSession } from '@iot-app-kit/core'; +import { initialize, ResolutionConfig, IoTAppKit, query } from '@iot-app-kit/core'; import { ASSET_DETAILS_QUERY, DEMO_TURBINE_ASSET_1, @@ -26,10 +26,10 @@ const DEFAULT_RESOLUTION_MAPPING = { export class TestingGround { @State() resolution: ResolutionConfig = DEFAULT_RESOLUTION_MAPPING; @State() viewport: { duration: string } = VIEWPORT; - private appKitSession: IoTAppKitSession; + private appKit: IoTAppKit; componentWillLoad() { - this.appKitSession = initialize({ awsCredentials: getEnvCredentials(), awsRegion: 'us-east-1' }).session(); + this.appKit = initialize({ awsCredentials: getEnvCredentials(), awsRegion: 'us-east-1' }); } private changeResolution = (ev: Event) => { @@ -58,66 +58,78 @@ export class TestingGround {

-
- +
+
@@ -140,14 +152,19 @@ export class TestingGround {
-
); diff --git a/packages/core/src/interface.d.ts b/packages/core/src/interface.d.ts index e6b23b636..31cf9c4d5 100755 --- a/packages/core/src/interface.d.ts +++ b/packages/core/src/interface.d.ts @@ -20,20 +20,6 @@ export * from './index'; export * from './data-module/data-cache/requestTypes'; export * from './iotsitewise/time-series-data/types.d'; -export type IoTAppKitSession = { - subscribeToTimeSeriesData: ( - { queries, request }: DataModuleSubscription, - callback: (data: TimeSeriesData) => void - ) => { - unsubscribe: () => void; - update: (subscriptionUpdate: SubscriptionUpdate) => void; - }; - iotsitewise: { - subscribeToAssetTree: (query: SiteWiseAssetTreeQuery, callback: SiteWiseAssetTreeCallback) => AssetTreeSubscription; - }; - registerDataSource: (dataSource: DataSource) => void; -}; - export type IoTAppKitInitInputs = | { registerDataSources?: boolean; @@ -48,6 +34,8 @@ export type IoTAppKitInitInputs = export interface IoTAppKit { session: (componentId: string) => IoTAppKitComponentSession; registerTimeSeriesDataSource: (dataSource: DataSource) => void; + /** @todo: create asset provider */ + subscribeToAssetTree: (query: SiteWiseAssetTreeQuery, callback: SiteWiseAssetTreeCallback) => AssetTreeSubscription; } export interface Closeable { diff --git a/packages/core/src/iotAppKit.ts b/packages/core/src/iotAppKit.ts index 24ead2692..20409b545 100644 --- a/packages/core/src/iotAppKit.ts +++ b/packages/core/src/iotAppKit.ts @@ -3,10 +3,10 @@ import { sitewiseSdk } from './iotsitewise/time-series-data/sitewise-sdk'; import { SiteWiseAssetDataSource } from './data-module/types'; import { createSiteWiseAssetDataSource } from './iotsitewise/time-series-data/asset-data-source'; import { SiteWiseAssetModule } from './asset-modules'; -import { IoTAppKitInitInputs, IoTAppKitSession } from './interface.d'; +import { IoTAppKitInitInputs, IoTAppKitComponentSession } from './interface.d'; import { createDataSource } from './iotsitewise/time-series-data'; -import { subscribeToTimeSeriesData } from './iotsitewise/time-series-data/subscribeToTimeSeriesData'; import { subscribeToAssetTree } from './asset-modules/coordinator'; +import { SiteWiseComponentSession } from './iotsitewise/component-session'; /** * Initialize IoT App Kit @@ -21,7 +21,6 @@ export const initialize = (input: IoTAppKitInitInputs) => { const assetDataSource: SiteWiseAssetDataSource = createSiteWiseAssetDataSource(siteWiseSdk); const siteWiseAssetModule = new SiteWiseAssetModule(assetDataSource); - const siteWiseAssetModuleSession = siteWiseAssetModule.startSession(); if (input.registerDataSources !== false) { /** Automatically registered data sources */ @@ -29,12 +28,10 @@ export const initialize = (input: IoTAppKitInitInputs) => { } return { - session: (): IoTAppKitSession => ({ - subscribeToTimeSeriesData: subscribeToTimeSeriesData(siteWiseTimeSeriesModule, siteWiseAssetModuleSession), - iotsitewise: { - subscribeToAssetTree: subscribeToAssetTree(siteWiseAssetModuleSession), - }, - registerDataSource: siteWiseTimeSeriesModule.registerDataSource, - }), + session: (componentId: string): IoTAppKitComponentSession => + new SiteWiseComponentSession({ componentId, siteWiseTimeSeriesModule, siteWiseAssetModule }), + registerTimeSeriesDataSource: siteWiseTimeSeriesModule.registerDataSource, + /** @todo: create asset provider */ + subscribeToAssetTree: subscribeToAssetTree(siteWiseAssetModule.startSession()), }; }; diff --git a/packages/core/src/app-kit-component-session.ts b/packages/core/src/iotsitewise/component-session.ts similarity index 76% rename from packages/core/src/app-kit-component-session.ts rename to packages/core/src/iotsitewise/component-session.ts index e3a716b6e..aed9b13b2 100644 --- a/packages/core/src/app-kit-component-session.ts +++ b/packages/core/src/iotsitewise/component-session.ts @@ -1,12 +1,12 @@ -import { SiteWiseAssetModule } from '.'; -import { IotAppKitDataModule } from './data-module/IotAppKitDataModule'; -import { IoTAppKitComponentSession, DataModuleSession } from './interface.d'; +import { SiteWiseAssetModule } from '..'; +import { IotAppKitDataModule } from '../data-module/IotAppKitDataModule'; +import { IoTAppKitComponentSession, DataModuleSession } from '../interface.d'; /** * Component session to manage component data module sessions. * Contains a reference to sitewise data modules */ -export class AppKitComponentSession implements IoTAppKitComponentSession { +export class SiteWiseComponentSession implements IoTAppKitComponentSession { public componentId: string; public siteWiseTimeSeriesModule: IotAppKitDataModule; diff --git a/packages/core/src/iotsitewise/time-series-data/provider.spec.ts b/packages/core/src/iotsitewise/time-series-data/provider.spec.ts index fca28ec37..0fac22a25 100644 --- a/packages/core/src/iotsitewise/time-series-data/provider.spec.ts +++ b/packages/core/src/iotsitewise/time-series-data/provider.spec.ts @@ -3,7 +3,7 @@ import { SiteWiseAssetModule } from '../..'; import { IotAppKitDataModule } from '../../data-module/IotAppKitDataModule'; import { createSiteWiseAssetDataSource } from './asset-data-source'; import { DESCRIBE_ASSET_RESPONSE } from '../__mocks__/asset'; -import { AppKitComponentSession } from '../../app-kit-component-session'; +import { SiteWiseComponentSession } from '../component-session'; import { DATA_STREAM } from '../__mocks__/mockWidgetProperties'; import { SiteWiseDataStreamQuery } from './types'; import { DataSource, DataStream } from '../../interface'; @@ -28,7 +28,7 @@ const assetModule = new SiteWiseAssetModule( ) ); -const componentSession = new AppKitComponentSession({ +const componentSession = new SiteWiseComponentSession({ componentId: 'componentId', siteWiseAssetModule: assetModule, siteWiseTimeSeriesModule: timeSeriesModule, @@ -73,12 +73,12 @@ it('subscribes, updates, and unsubscribes to time series data by delegating to u }, }); - const START_2 = new Date(2019, 0, 0); - const END_2 = new Date(); - timeSeriesCallback.mockClear(); // update + const START_2 = new Date(2019, 0, 0); + const END_2 = new Date(); + provider.updateSubscription({ request: { viewport: { start: START_2, end: END_2 } }, }); @@ -97,6 +97,29 @@ it('subscribes, updates, and unsubscribes to time series data by delegating to u timeSeriesCallback.mockClear(); + // update viewport + const START_3 = new Date(2018, 0, 0); + const END_3 = new Date(); + + provider.updateViewport({ + start: START_3, + end: END_3, + }); + + expect(timeSeriesCallback).toBeCalledWith({ + dataStreams: [ + expect.objectContaining({ + id: DATA_STREAM.id, + }), + ], + viewport: { + start: START_3, + end: END_3, + }, + }); + + timeSeriesCallback.mockClear(); + // check that subscription refreshes jest.advanceTimersByTime(refreshRate); diff --git a/packages/core/src/iotsitewise/time-series-data/provider.ts b/packages/core/src/iotsitewise/time-series-data/provider.ts index 5af87737a..e5c9df5c3 100644 --- a/packages/core/src/iotsitewise/time-series-data/provider.ts +++ b/packages/core/src/iotsitewise/time-series-data/provider.ts @@ -3,6 +3,7 @@ import { AnyDataStreamQuery, DataModuleSubscription, SubscriptionUpdate } from ' import { datamodule } from '../..'; import { subscribeToTimeSeriesData } from './subscribeToTimeSeriesData'; import { TimeSeriesData } from './types'; +import { MinimalViewPortConfig } from '@synchro-charts/core'; /** * Provider for SiteWise time series data @@ -10,10 +11,10 @@ import { TimeSeriesData } from './types'; export class SiteWiseTimeSeriesDataProvider implements Provider { private session: IoTAppKitComponentSession; - private input: DataModuleSubscription; - private update: (subscriptionUpdate: SubscriptionUpdate) => void; + public input: DataModuleSubscription; + constructor(session: IoTAppKitComponentSession, input: DataModuleSubscription) { this.session = session; this.input = input; @@ -42,4 +43,13 @@ export class SiteWiseTimeSeriesDataProvider implements Provider unsubscribe() { this.session.close(); } + + updateViewport(viewport: MinimalViewPortConfig) { + this.update({ + request: { + settings: this.input.request.settings, + viewport, + }, + }); + } } diff --git a/packages/core/src/module-namespace.ts b/packages/core/src/module-namespace.ts index f6dc04274..24a511c6e 100644 --- a/packages/core/src/module-namespace.ts +++ b/packages/core/src/module-namespace.ts @@ -1,18 +1,18 @@ import { IoTAppKitComponentSession } from './interface'; import { DataModule } from './data-module/types'; import { SiteWiseAssetSession } from '.'; -import { AppKitComponentSession } from './app-kit-component-session'; +import { SiteWiseComponentSession } from './iotsitewise/component-session'; /** * Extensible datamodule namespace exposing module sessions. */ export namespace datamodule.iotsitewise { export function timeSeriesDataSession(session: IoTAppKitComponentSession): DataModule { - return (session as AppKitComponentSession).siteWiseTimeSeriesModule; // casting to hide modules from public interface + return (session as SiteWiseComponentSession).siteWiseTimeSeriesModule; // casting to hide modules from public interface } export function assetDataSession(session: IoTAppKitComponentSession): SiteWiseAssetSession { - const assetSession = (session as AppKitComponentSession).siteWiseAssetModule.startSession(); + const assetSession = (session as SiteWiseComponentSession).siteWiseAssetModule.startSession(); session.attachDataModuleSession(assetSession); return assetSession; }