From cccbe61cb596b284752cc240b8e95e261b03956b Mon Sep 17 00:00:00 2001 From: gareth-amazon <91912440+gareth-amazon@users.noreply.github.com> Date: Mon, 21 Feb 2022 17:32:07 -0800 Subject: [PATCH] feat: Refactor Asset Tree to use the new Query/Provider system (#62) ## Overview Refactor the SiteWise Asset Tree types to use the new Query/Provider mechanism. * AssetTreeSubscription is replaced by a Provider that give the same expand/collapse functionality to the component. * Removed the asset tree demo as it was put in just as an explainer and we don't intend to ship it. Will follow up with the work to make asset details similarly functional. * Remove the AssetDetailsView --- packages/components/src/components.d.ts | 36 +--- .../iot-asset-details/iot-asset-details.tsx | 110 ----------- .../iot-asset-tree-demo.tsx | 95 --------- .../iot-resource-explorer.spec.ts | 11 +- .../iot-resource-explorer.tsx | 5 +- .../sitewise-resource-explorer.spec.ts | 4 +- .../sitewise-resource-explorer.tsx | 24 ++- .../components/iot-resource-explorer/types.ts | 7 +- .../components/iot-resource-explorer/utils.ts | 6 +- .../iot-time-series-connector.tsx | 12 +- .../iot-resource-explorer/setup.tsx | 5 +- .../iot-resource-explorer-demo.tsx | 5 +- .../testing/testing-ground/siteWiseQueries.ts | 22 +-- .../assetTreeModule.spec.ts | 5 +- .../assetTreeSession.spec.ts | 181 +++++++++--------- .../sitewise-asset-tree/assetTreeSession.ts | 23 +-- .../sitewise-asset-tree/types.ts | 64 +++++-- packages/core/src/data-module/index.ts | 12 -- packages/core/src/index.ts | 19 +- .../time-series-data/provider.spec.ts | 2 +- .../iotsitewise/time-series-data/provider.ts | 6 +- packages/core/src/module-namespace.ts | 2 +- packages/core/src/query-namespace.ts | 27 ++- 23 files changed, 243 insertions(+), 440 deletions(-) delete mode 100644 packages/components/src/components/iot-asset-details/iot-asset-details.tsx delete mode 100644 packages/components/src/components/iot-asset-tree-demo/iot-asset-tree-demo.tsx delete mode 100644 packages/core/src/data-module/index.ts diff --git a/packages/components/src/components.d.ts b/packages/components/src/components.d.ts index 1e0537c67..c3f28a00d 100644 --- a/packages/components/src/components.d.ts +++ b/packages/components/src/components.d.ts @@ -5,20 +5,13 @@ * It contains typing information for all components that exist in this project. */ import { HTMLStencilElement, JSXBase } from "@stencil/core/internal"; -import { AssetSummaryQuery, AssetTreeSubscription, IoTAppKit, Provider, SiteWiseAssetTreeQuery, SiteWiseTimeSeriesDataProvider, StyleSettingsMap, TimeSeriesData, TimeSeriesDataRequestSettings, TimeSeriesQuery } from "@iot-app-kit/core"; +import { IoTAppKit, Provider, SiteWiseAssetTreeQuery, SiteWiseTimeSeriesDataProvider, StyleSettingsMap, TimeSeriesData, TimeSeriesDataRequestSettings, TimeSeriesQuery } from "@iot-app-kit/core"; import { Annotations, 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"; import { NonCancelableCustomEvent } from "@awsui/components-react"; export namespace Components { - interface IotAssetDetails { - "query": AssetSummaryQuery; - } - interface IotAssetTreeDemo { - "query": SiteWiseAssetTreeQuery; - "subscription": AssetTreeSubscription; - } interface IotBarChart { "annotations": Annotations; "appKit": IoTAppKit; @@ -144,24 +137,13 @@ export namespace Components { "query": SiteWiseAssetTreeQuery; "selectionType"?: TableProps.SelectionType; "sortingEnabled": boolean; + "widgetId": string; "wrapLines": boolean; } interface TestingGround { } } declare global { - interface HTMLIotAssetDetailsElement extends Components.IotAssetDetails, HTMLStencilElement { - } - var HTMLIotAssetDetailsElement: { - prototype: HTMLIotAssetDetailsElement; - new (): HTMLIotAssetDetailsElement; - }; - interface HTMLIotAssetTreeDemoElement extends Components.IotAssetTreeDemo, HTMLStencilElement { - } - var HTMLIotAssetTreeDemoElement: { - prototype: HTMLIotAssetTreeDemoElement; - new (): HTMLIotAssetTreeDemoElement; - }; interface HTMLIotBarChartElement extends Components.IotBarChart, HTMLStencilElement { } var HTMLIotBarChartElement: { @@ -253,8 +235,6 @@ declare global { new (): HTMLTestingGroundElement; }; interface HTMLElementTagNameMap { - "iot-asset-details": HTMLIotAssetDetailsElement; - "iot-asset-tree-demo": HTMLIotAssetTreeDemoElement; "iot-bar-chart": HTMLIotBarChartElement; "iot-kpi": HTMLIotKpiElement; "iot-line-chart": HTMLIotLineChartElement; @@ -273,13 +253,6 @@ declare global { } } declare namespace LocalJSX { - interface IotAssetDetails { - "query"?: AssetSummaryQuery; - } - interface IotAssetTreeDemo { - "query"?: SiteWiseAssetTreeQuery; - "subscription"?: AssetTreeSubscription; - } interface IotBarChart { "annotations"?: Annotations; "appKit": IoTAppKit; @@ -405,13 +378,12 @@ declare namespace LocalJSX { "query"?: SiteWiseAssetTreeQuery; "selectionType"?: TableProps.SelectionType; "sortingEnabled"?: boolean; + "widgetId"?: string; "wrapLines"?: boolean; } interface TestingGround { } interface IntrinsicElements { - "iot-asset-details": IotAssetDetails; - "iot-asset-tree-demo": IotAssetTreeDemo; "iot-bar-chart": IotBarChart; "iot-kpi": IotKpi; "iot-line-chart": IotLineChart; @@ -433,8 +405,6 @@ export { LocalJSX as JSX }; declare module "@stencil/core" { export namespace JSX { interface IntrinsicElements { - "iot-asset-details": LocalJSX.IotAssetDetails & JSXBase.HTMLAttributes; - "iot-asset-tree-demo": LocalJSX.IotAssetTreeDemo & JSXBase.HTMLAttributes; "iot-bar-chart": LocalJSX.IotBarChart & JSXBase.HTMLAttributes; "iot-kpi": LocalJSX.IotKpi & JSXBase.HTMLAttributes; "iot-line-chart": LocalJSX.IotLineChart & JSXBase.HTMLAttributes; 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 deleted file mode 100644 index b135573ce..000000000 --- a/packages/components/src/components/iot-asset-details/iot-asset-details.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { Component, h, Prop, State, Watch } from '@stencil/core'; -import { - getSiteWiseAssetModule, - SiteWiseAssetSession, - AssetSummaryQuery, - AssetModelQuery, - AssetPropertyValueQuery, -} from '@iot-app-kit/core'; -import { AssetPropertyValue, AssetSummary, DescribeAssetModelResponse } from '@aws-sdk/client-iotsitewise'; - -@Component({ - tag: 'iot-asset-details', - shadow: false, -}) -export class IotAssetDetails { - @Prop() query: AssetSummaryQuery; - @State() assetSummary: AssetSummary | null = null; - @State() assetModel: DescribeAssetModelResponse | null = null; - @State() assetPropertyValues: Map = new Map(); - - @State() assetSession: SiteWiseAssetSession; - - componentWillLoad() { - this.assetSession = getSiteWiseAssetModule().startSession(); - this.assetSession.requestAssetSummary(this.query, { - next: (summary: AssetSummary) => { - this.assetSummary = summary; - const assetId = this.assetSummary?.id as string; - const modelQuery: AssetModelQuery = { assetModelId: this.assetSummary.assetModelId as string }; - this.assetSession.requestAssetModel(modelQuery, { - next: (assetModel: DescribeAssetModelResponse) => { - this.assetModel = assetModel; - assetModel.assetModelProperties?.forEach((prop) => { - let propQuery: AssetPropertyValueQuery = { assetId: assetId, propertyId: prop.id as string }; - this.assetSession.requestAssetPropertyValue(propQuery, { - next: (propValue: AssetPropertyValue) => { - const copy = new Map(this.assetPropertyValues); - copy.set(prop.id as string, this.convertToString(propValue)); - this.assetPropertyValues = copy; - }, - error: (err) => { - // noop - }, - }); - }); - }, - error: (err) => { - // noop - }, - }); - }, - error: (err) => { - // noop - }, - }); - } - - convertToString(propValue: AssetPropertyValue): string { - if (propValue == undefined) { - return ''; - } - const value = propValue.value; - return ( - value?.stringValue || - value?.booleanValue?.toString() || - value?.doubleValue?.toString(10) || - value?.integerValue?.toString(10) || - '' - ); - } - - componentDidUnmount() { - this.assetSession.close(); - } - - /** - * Sync subscription to change in queried data - */ - @Watch('query') - onUpdateProp(newProp: unknown, oldProp: unknown) { - /* TODO: - if (!isEqual(newProp, oldProp) && this.update != null) { - this.update({ - query: this.query, - requestInfo: this.requestInfo, - }); - } - */ - } - - render() { - return ( -
-

{this.assetSummary?.name}

-

{this.assetSummary?.arn}

-

- Model: - {this.assetModel?.assetModelName} -

-
    - {this.assetModel?.assetModelProperties?.map((property) => ( -
  • - {property.name}: {this.assetPropertyValues.get(property?.id as string)} -
  • - ))} -
-
- ); - } -} diff --git a/packages/components/src/components/iot-asset-tree-demo/iot-asset-tree-demo.tsx b/packages/components/src/components/iot-asset-tree-demo/iot-asset-tree-demo.tsx deleted file mode 100644 index cf4c03d24..000000000 --- a/packages/components/src/components/iot-asset-tree-demo/iot-asset-tree-demo.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { Component, h, Prop, State, Watch } from '@stencil/core'; -import { - getSiteWiseAssetModule, - SiteWiseAssetTreeModule, - SiteWiseAssetTreeQuery, - SiteWiseAssetTreeNode, - SiteWiseAssetTreeSession, - BranchReference, - AssetTreeSubscription, - HierarchyGroup, -} from '@iot-app-kit/core'; - -@Component({ - tag: 'iot-asset-tree-demo', - shadow: false, -}) -export class IotAssetTreeDemo { - @Prop() query: SiteWiseAssetTreeQuery; - @Prop() subscription: AssetTreeSubscription; - @State() roots: SiteWiseAssetTreeNode[] = []; - - componentDidLoad() { - // TODO: this needs to be done elsewhere... - let session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeModule(getSiteWiseAssetModule()).startSession( - this.query - ); - this.subscription = session.subscribe({ - next: (newTree) => { - this.roots = newTree; - // check the tree for any new unexpanded nodes and expand them: - this.expandNodes(newTree); - }, - }); - } - - expandNodes(nodes: SiteWiseAssetTreeNode[]) { - nodes.forEach((node) => { - Array.from(node.hierarchies.values()).forEach((hierarchyGroup) => { - if (!hierarchyGroup.isExpanded) { - this.subscription.expand(new BranchReference(node.asset.id, hierarchyGroup.id)); - } - this.expandNodes(hierarchyGroup.children); - }); - }); - } - - componentWillUnmount() { - this.subscription.unsubscribe(); - } - - render() { - return ( -
-

Tree Demo

- {this.renderAssetList(this.roots)} -
- ); - } - - renderAssetList(assets: SiteWiseAssetTreeNode[]) { - if (!assets) { - return ''; - } - - return
    {assets.map((asset) => this.renderAsset(asset))}
; - } - - renderAsset(assetNode: SiteWiseAssetTreeNode) { - return ( -
  • - {assetNode.asset?.name} - {this.renderHierarchies(assetNode)} -
  • - ); - } - - renderHierarchies(node: SiteWiseAssetTreeNode) { - if (!node.hierarchies || !node.hierarchies.size) { - return; - } - - return
      {Array.from(node.hierarchies.values()).map((hierarchy) => this.renderHierarchy(hierarchy))}
    ; - } - - renderHierarchy(hierarchy: HierarchyGroup) { - if (hierarchy.children) { - return ( -
  • - {hierarchy.name} - {this.renderAssetList(hierarchy?.children)} -
  • - ); - } - } -} 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 835696d64..acfccaaa4 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 @@ -1,10 +1,15 @@ -import { initialize, IoTAppKitInitInputs, createMockSiteWiseSDK } from '@iot-app-kit/core'; +import { + initialize, + IoTAppKitInitInputs, + createMockSiteWiseSDK, + query as siteWiseQuery, + SiteWiseAssetTreeQuery, +} from '@iot-app-kit/core'; import { newSpecPage } from '@stencil/core/testing'; import { IotResourceExplorer } from './iot-resource-explorer'; import { Components } from '../../components.d'; import { CustomHTMLElement } from '../../testing/types'; import { update } from '../../testing/update'; -import { ResourceExplorerQuery } from './types'; import flushPromises from 'flush-promises'; import { mocklistAssetsResponse } from '../../testing/mocks/data/listAssetsResponse'; import { mockSiteWiseSDK } from '../../testing/mocks/siteWiseSDK'; @@ -23,7 +28,7 @@ const resourceExplorerSpec = async ( html: '
    ', supportsShadowDom: false, }); - const query: ResourceExplorerQuery = { source: 'site-wise', rootAssetId: undefined }; + const query: SiteWiseAssetTreeQuery = siteWiseQuery.iotsitewise.assetTree.fromRoot(); const resourceExplorer = page.doc.createElement( 'iot-resource-explorer' ) as CustomHTMLElement; 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 5cd2eb9ef..ad4010015 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,8 +1,7 @@ import { Component, h, Prop } from '@stencil/core'; -import { IoTAppKit } from '@iot-app-kit/core'; +import { IoTAppKit, isSiteWiseAssetTreeQuery } from '@iot-app-kit/core'; import { ColumnDefinition, SitewiseAssetResource } from './types'; import { EmptyStateProps } from '@iot-app-kit/related-table'; -import { isSiteWiseQuery } from './utils'; import { TableProps } from '@awsui/components-react/table'; import { ResourceExplorerQuery, FilterTexts } from './types'; import { NonCancelableCustomEvent } from '@awsui/components-react'; @@ -53,7 +52,7 @@ export class IotResourceExplorer { ]; render() { - if (isSiteWiseQuery(this.query)) { + if (isSiteWiseAssetTreeQuery(this.query)) { return ( ', supportsShadowDom: false, }); - const query: core.SiteWiseAssetTreeQuery = { rootAssetId: undefined }; + const query: SiteWiseAssetTreeQuery = new SiteWiseAssetTreeQuery(); const sitewiseResourceExplorer = page.doc.createElement( 'sitewise-resource-explorer' ) as CustomHTMLElement; 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 f80aba631..6a27d9a92 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 @@ -1,11 +1,11 @@ import { Component, h, Prop, State } from '@stencil/core'; import { - AssetTreeSubscription, BranchReference, IoTAppKit, - SiteWiseAssetTreeNode, SiteWiseAssetTreeQuery, ErrorDetails, + SiteWiseAssetTreeProvider, + SiteWiseAssetTreeNode, } from '@iot-app-kit/core'; import { SitewiseAssetResource, FilterTexts, ColumnDefinition } from './types'; import { EmptyStateProps, ITreeNode, UseTreeCollection } from '@iot-app-kit/related-table'; @@ -28,9 +28,10 @@ export class SitewiseResourceExplorer { @Prop() sortingEnabled: boolean; @Prop() paginationEnabled: boolean; @Prop() wrapLines: boolean; - + @Prop() widgetId: string; @Prop() onSelectionChange: (event: NonCancelableCustomEvent>) => void; + @State() provider: SiteWiseAssetTreeProvider; @State() items: SitewiseAssetResource[] = []; @State() errors: ErrorDetails[] = []; @@ -49,26 +50,29 @@ export class SitewiseResourceExplorer { }, }; - subscription: AssetTreeSubscription; + buildProvider() { + return this.query.build(this.appKit.session(this.widgetId)); + } componentWillLoad() { - this.subscription = this.appKit.subscribeToAssetTree(this.query, { - next: (newTree: SiteWiseAssetTreeNode[]) => { - this.items = parseSitewiseAssetTree(newTree); + this.provider = this.buildProvider(); + this.provider.subscribe({ + next: (data: SiteWiseAssetTreeNode[]) => { + this.items = parseSitewiseAssetTree(data); }, error: (err: ErrorDetails[]) => { this.errors = err; }, - }) as AssetTreeSubscription; + }); } componentWillUnmount() { - this.subscription.unsubscribe(); + this.provider.unsubscribe(); } expandNode = (node: ITreeNode) => { node.hierarchies?.forEach((hierarchy) => { - this.subscription.expand(new BranchReference(node.id, hierarchy.id!)); + this.provider.expand(new BranchReference(node.id, hierarchy.id!)); }); }; diff --git a/packages/components/src/components/iot-resource-explorer/types.ts b/packages/components/src/components/iot-resource-explorer/types.ts index 6c0f38004..cf55abb2a 100644 --- a/packages/components/src/components/iot-resource-explorer/types.ts +++ b/packages/components/src/components/iot-resource-explorer/types.ts @@ -1,5 +1,6 @@ import { AssetSummary } from '@aws-sdk/client-iotsitewise'; import { TableProps } from '@awsui/components-react'; +import { SiteWiseAssetTreeQuery } from '@iot-app-kit/core'; export interface FilterTexts { placeholder: string; @@ -17,8 +18,4 @@ export interface SitewiseAssetResource extends AssetSummary { parentId?: string; } -export interface ResourceExplorerBaseQuery { - source: string; -} - -export type ResourceExplorerQuery = ResourceExplorerBaseQuery & any; +export type ResourceExplorerQuery = SiteWiseAssetTreeQuery; // | later | some more types diff --git a/packages/components/src/components/iot-resource-explorer/utils.ts b/packages/components/src/components/iot-resource-explorer/utils.ts index e1f0b4118..428099f99 100644 --- a/packages/components/src/components/iot-resource-explorer/utils.ts +++ b/packages/components/src/components/iot-resource-explorer/utils.ts @@ -1,4 +1,4 @@ -import { SiteWiseAssetTreeNode } from '@iot-app-kit/core'; +import { SiteWiseAssetTreeNode, SiteWiseAssetTreeQuery } from '@iot-app-kit/core'; import { ResourceExplorerQuery, SitewiseAssetResource } from './types'; const recursiveParseSitewiseAssetTree = ( @@ -23,7 +23,3 @@ export const parseSitewiseAssetTree = (tree: SiteWiseAssetTreeNode[]) => { recursiveParseSitewiseAssetTree(flattenTree, tree); return flattenTree; }; - -export const isSiteWiseQuery = (query: ResourceExplorerQuery) => { - return query?.source === 'site-wise'; -}; 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 index 9d9e37e5c..da4408096 100644 --- 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 @@ -24,8 +24,10 @@ export class IotTimeSeriesConnector { }; componentWillLoad() { - this.provider.subscribe((data: TimeSeriesData) => { - this.data = data; + this.provider.subscribe({ + next: (data: TimeSeriesData) => { + this.data = data; + }, }); } @@ -33,8 +35,10 @@ export class IotTimeSeriesConnector { private onProviderUpdate() { this.provider.unsubscribe(); - this.provider.subscribe((data: TimeSeriesData) => { - this.data = data; + this.provider.subscribe({ + next: (data: TimeSeriesData) => { + this.data = data; + }, }); } diff --git a/packages/components/src/integration/iot-resource-explorer/setup.tsx b/packages/components/src/integration/iot-resource-explorer/setup.tsx index d9ed63106..a5712b217 100644 --- a/packages/components/src/integration/iot-resource-explorer/setup.tsx +++ b/packages/components/src/integration/iot-resource-explorer/setup.tsx @@ -1,8 +1,9 @@ import { mount } from '@cypress/vue'; import { h } from 'vue'; -import { initialize } from '@iot-app-kit/core'; +import { initialize, query } from '@iot-app-kit/core'; const { applyPolyfills, defineCustomElements } = require('@iot-app-kit/components/loader'); import '../../styles/awsui.css'; +import iotsitewise = query.iotsitewise; applyPolyfills().then(() => defineCustomElements()); @@ -11,7 +12,7 @@ export const renderComponent = () => { mount({ data: () => { return { - query: { source: 'site-wise' }, + query: iotsitewise.assetTree.fromRoot(), }; }, render: function () { 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 584dc6a1c..7a82238bd 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,7 +1,6 @@ import { Component, h } from '@stencil/core'; -import { initialize, IoTAppKit, SiteWiseAssetTreeQuery } from '@iot-app-kit/core'; +import { initialize, IoTAppKit, query, SiteWiseAssetTreeQuery } from '@iot-app-kit/core'; import { getEnvCredentials } from '../testing-ground/getEnvCredentials'; -import { ResourceExplorerQuery } from '../../components/iot-resource-explorer/types'; @Component({ tag: 'iot-resource-explorer-demo', @@ -14,7 +13,7 @@ export class IotResourceExplorerDemo { this.appKit = initialize({ awsCredentials: getEnvCredentials(), awsRegion: 'us-east-1' }); } - query: ResourceExplorerQuery & SiteWiseAssetTreeQuery = { source: 'site-wise' }; + query: SiteWiseAssetTreeQuery = query.iotsitewise.assetTree.fromRoot(); render() { return ; diff --git a/packages/components/src/testing/testing-ground/siteWiseQueries.ts b/packages/components/src/testing/testing-ground/siteWiseQueries.ts index 75d5aca9f..f0b5c103f 100644 --- a/packages/components/src/testing/testing-ground/siteWiseQueries.ts +++ b/packages/components/src/testing/testing-ground/siteWiseQueries.ts @@ -1,5 +1,4 @@ const STRING_ASSET_ID = 'f2f74fa8-625a-435f-b89c-d27b2d84f45b'; -const STRING_PROPERTY_ID = '797482e4-692f-45a2-b3db-17979481e9c3'; export const DEMO_TURBINE_ASSET_1 = '00eeb4b1-5017-48d4-9f39-1066f080a822'; @@ -8,28 +7,13 @@ export const DEMO_TURBINE_ASSET_1_PROPERTY_2 = '9701d7ad-c22e-43fd-b040-68bad003 export const DEMO_TURBINE_ASSET_1_PROPERTY_3 = 'bded202a-a436-46b8-85c1-21bb5b945f86'; export const DEMO_TURBINE_ASSET_1_PROPERTY_4 = 'd8937b65-5f03-4e40-93ac-c5513420ade7'; -export const STRING_QUERY = { - source: 'site-wise', - assets: [{ assetId: STRING_ASSET_ID, properties: [{ propertyId: STRING_PROPERTY_ID }] }], -}; - export const ASSET_DETAILS_QUERY = { assetId: STRING_ASSET_ID, }; -export const NUMBER_QUERY = { - source: 'site-wise', - assets: [ - { - assetId: DEMO_TURBINE_ASSET_1, - properties: [{ propertyId: DEMO_TURBINE_ASSET_1_PROPERTY_1 }, { propertyId: DEMO_TURBINE_ASSET_1_PROPERTY_4 }], - }, - ], -}; - -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 = STRING_ASSET_ID; +const AGGREGATED_DATA_PROPERTY = 'd0dc79be-0dc2-418c-ac23-26f33cdb4b8b'; +const AGGREGATED_DATA_PROPERTY_2 = '69607dc2-5fbe-416d-aac2-0382018626e4'; export const AGGREGATED_DATA_QUERY = { assets: [ diff --git a/packages/core/src/asset-modules/sitewise-asset-tree/assetTreeModule.spec.ts b/packages/core/src/asset-modules/sitewise-asset-tree/assetTreeModule.spec.ts index 5d55c70d4..2986bbc81 100644 --- a/packages/core/src/asset-modules/sitewise-asset-tree/assetTreeModule.spec.ts +++ b/packages/core/src/asset-modules/sitewise-asset-tree/assetTreeModule.spec.ts @@ -2,6 +2,7 @@ import { SiteWiseAssetTreeModule } from './assetTreeModule'; import { MockSiteWiseAssetModule, MockSiteWiseAssetsReplayData } from '../mocks'; import { HIERARCHY_ROOT_ID, HierarchyAssetSummaryList, LoadingStateEnum } from '../sitewise/types'; import { sampleAssetSummary } from '../../iotsitewise/__mocks__/asset'; +import { RootedSiteWiseAssetTreeQueryArguments, SiteWiseAssetTreeQuery } from './types'; it('initializes', () => { expect( @@ -19,6 +20,8 @@ it('returns a session', () => { replayData.addHierarchyAssetSummaryList({ assetHierarchyId: HIERARCHY_ROOT_ID }, testData); replayData.addAssetSummaries([sampleAssetSummary]); expect(() => - new SiteWiseAssetTreeModule(new MockSiteWiseAssetModule(replayData)).startSession({ rootAssetId: undefined }) + new SiteWiseAssetTreeModule(new MockSiteWiseAssetModule(replayData)).startSession( + new SiteWiseAssetTreeQuery({ asset: undefined }) + ) ).not.toBeUndefined(); }); diff --git a/packages/core/src/asset-modules/sitewise-asset-tree/assetTreeSession.spec.ts b/packages/core/src/asset-modules/sitewise-asset-tree/assetTreeSession.spec.ts index c6e3f52ee..741d114f0 100644 --- a/packages/core/src/asset-modules/sitewise-asset-tree/assetTreeSession.spec.ts +++ b/packages/core/src/asset-modules/sitewise-asset-tree/assetTreeSession.spec.ts @@ -1,5 +1,5 @@ import { SiteWiseAssetTreeSession } from './assetTreeSession'; -import { BranchReference } from './types'; +import { BranchReference, SiteWiseAssetTreeQuery } from './types'; import { HIERARCHY_ROOT_ID, HierarchyAssetSummaryList, LoadingStateEnum } from '../sitewise/types'; import { AssetSummary, @@ -22,7 +22,7 @@ it('initializes', () => { replayData.addHierarchyAssetSummaryList({ assetHierarchyId: HIERARCHY_ROOT_ID }, testData); replayData.addAssetSummaries([sampleAssetSummary]); expect( - () => new SiteWiseAssetTreeSession(new MockSiteWiseAssetSession(replayData), { rootAssetId: '' }) + () => new SiteWiseAssetTreeSession(new MockSiteWiseAssetSession(replayData), new SiteWiseAssetTreeQuery({})) ).not.toThrowError(); }); @@ -40,9 +40,10 @@ describe('root loading functionality', () => { replayData.addAssetSummaries([rootAsset]); it('When you subscribe the root is returned', (done) => { - const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession(new MockSiteWiseAssetSession(replayData), { - rootAssetId: '', - }); + const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession( + new MockSiteWiseAssetSession(replayData), + new SiteWiseAssetTreeQuery({}) + ); session.subscribe({ next: (treeRoot) => { if (!treeRoot || treeRoot.length == 0) { @@ -74,9 +75,10 @@ describe('branch loading functionality', () => { // This time the asset has no hierarchis and the loading will stop at just the asset it('When you subscribe the asset is returned', (done) => { - const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession(new MockSiteWiseAssetSession(replayData), { - rootAssetId: rootAsset.id, - }); + const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession( + new MockSiteWiseAssetSession(replayData), + new SiteWiseAssetTreeQuery({ asset: { assetId: rootAsset.id as string } }) + ); session.subscribe({ next: (treeRoot) => { if (!treeRoot || treeRoot.length == 0) { @@ -106,10 +108,10 @@ describe('model loading', () => { replayData.addAssetModels([sampleAssetModel]); it('When you request the model you get the model', (done) => { - const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession(new MockSiteWiseAssetSession(replayData), { - rootAssetId: '', - withModels: true, - }); + const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession( + new MockSiteWiseAssetSession(replayData), + new SiteWiseAssetTreeQuery({ asset: { assetId: rootAsset.id as string }, withModels: true }) + ); session.subscribe({ next: (treeRoot) => { if (!treeRoot || treeRoot.length == 0) { @@ -118,7 +120,6 @@ describe('model loading', () => { expect(treeRoot.length).toEqual(1); expect(treeRoot[0]?.asset).toEqual(rootAsset); expect(treeRoot[0]?.model).toEqual(sampleAssetModel); - expect(treeRoot[0]?.properties).toBeEmpty(); done(); }, @@ -180,11 +181,13 @@ describe('asset property loading', () => { }); it('When you request a property and it exists it is attached to the asset node', (done) => { - const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession(new MockSiteWiseAssetSession(replayData), { - rootAssetId: '', - withModels: true, - propertyIds: ['propertyNotInModel.id.1234', 'modelNumber.id.1234'], - }); + const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession( + new MockSiteWiseAssetSession(replayData), + new SiteWiseAssetTreeQuery({ + withModels: true, + withPropertyValues: ['propertyNotInModel.id.1234', 'modelNumber.id.1234'], + }) + ); session.subscribe({ next: (treeRoot) => { if (!treeRoot || treeRoot.length == 0) { @@ -227,9 +230,10 @@ describe('expand functionality', () => { replayData.addAssetSummaries([rootAsset, bananaOne, bananaTwo]); it('Expands a hierarchy when requested', (done) => { - const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession(new MockSiteWiseAssetSession(replayData), { - rootAssetId: '', - }); + const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession( + new MockSiteWiseAssetSession(replayData), + new SiteWiseAssetTreeQuery({}) + ); session.expand(new BranchReference(rootAsset.id, 'bananas1234')); session.subscribe({ next: (treeRoot) => { @@ -252,9 +256,10 @@ describe('expand functionality', () => { }); it('Collapses and expanded hierarchy', (done) => { - const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession(new MockSiteWiseAssetSession(replayData), { - rootAssetId: '', - }); + const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession( + new MockSiteWiseAssetSession(replayData), + new SiteWiseAssetTreeQuery({}) + ); session.collapse(new BranchReference(rootAsset.id, 'bananas1234')); session.subscribe({ next: (treeRoot) => { @@ -281,84 +286,80 @@ describe('error handling', () => { replayData.addErrors([error]); it('it returns the error when requesting root asset fails', (done) => { - const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession(new MockSiteWiseAssetSession(replayData), { - rootAssetId: '', - }); + const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession( + new MockSiteWiseAssetSession(replayData), + new SiteWiseAssetTreeQuery({ asset: { assetId: '' } }) + ); session.expand(new BranchReference(undefined, HIERARCHY_ROOT_ID)); - session - .subscribe({ - next: (treeRoot) => { - // noop - }, - error: (err) => { - expect(err.length).toEqual(1); - expect(err[0].msg).toEqual(error.msg); - expect(err[0].type).toEqual(error.type); - expect(err[0].status).toEqual(error.status); - done(); - }, - }) - .unsubscribe(); + session.subscribe({ + next: (treeRoot) => { + // noop + }, + error: (err) => { + expect(err.length).toEqual(1); + expect(err[0].msg).toEqual(error.msg); + expect(err[0].type).toEqual(error.type); + expect(err[0].status).toEqual(error.status); + done(); + }, + }); }); it('it returns the error when requesting asset hierarchy fails', (done) => { - const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession(new MockSiteWiseAssetSession(replayData), { - rootAssetId: '', - }); + const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession( + new MockSiteWiseAssetSession(replayData), + new SiteWiseAssetTreeQuery({ asset: { assetId: '' } }) + ); session.expand(new BranchReference('asset-id', 'hierarchy-id')); - session - .subscribe({ - next: (treeRoot) => { - // noop - }, - error: (err) => { - expect(err.length).toEqual(1); - expect(err[0].msg).toEqual(error.msg); - expect(err[0].type).toEqual(error.type); - expect(err[0].status).toEqual(error.status); - done(); - }, - }) - .unsubscribe(); + session.subscribe({ + next: (treeRoot) => { + // noop + }, + error: (err) => { + expect(err.length).toEqual(1); + expect(err[0].msg).toEqual(error.msg); + expect(err[0].type).toEqual(error.type); + expect(err[0].status).toEqual(error.status); + done(); + }, + }); }); it('it returns the error when requesting asset summary fails', (done) => { - const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession(new MockSiteWiseAssetSession(replayData), { - rootAssetId: 'root-asset-id', + const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession( + new MockSiteWiseAssetSession(replayData), + new SiteWiseAssetTreeQuery({ asset: { assetId: 'root-asset-id' } }) + ); + session.subscribe({ + next: (treeRoot) => { + // noop + }, + error: (err) => { + expect(err.length).toEqual(1); + expect(err[0].msg).toEqual(error.msg); + expect(err[0].type).toEqual(error.type); + expect(err[0].status).toEqual(error.status); + done(); + }, }); - session - .subscribe({ - next: (treeRoot) => { - // noop - }, - error: (err) => { - expect(err.length).toEqual(1); - expect(err[0].msg).toEqual(error.msg); - expect(err[0].type).toEqual(error.type); - expect(err[0].status).toEqual(error.status); - done(); - }, - }) - .unsubscribe(); }); it('it returns the error when requesting asset model fails', (done) => { - const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession(new MockSiteWiseAssetSession(replayData), { - rootAssetId: 'root-asset-id', + const session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeSession( + new MockSiteWiseAssetSession(replayData), + new SiteWiseAssetTreeQuery({ asset: { assetId: 'root-asset-id' } }) + ); + session.subscribe({ + next: (treeRoot) => { + // noop + }, + error: (err) => { + expect(err.length).toEqual(1); + expect(err[0].msg).toEqual(error.msg); + expect(err[0].type).toEqual(error.type); + expect(err[0].status).toEqual(error.status); + done(); + }, }); - session - .subscribe({ - next: (treeRoot) => { - // noop - }, - error: (err) => { - expect(err.length).toEqual(1); - expect(err[0].msg).toEqual(error.msg); - expect(err[0].type).toEqual(error.type); - expect(err[0].status).toEqual(error.status); - done(); - }, - }) - .unsubscribe(); }); }); diff --git a/packages/core/src/asset-modules/sitewise-asset-tree/assetTreeSession.ts b/packages/core/src/asset-modules/sitewise-asset-tree/assetTreeSession.ts index ed6e40d42..2f804e3ad 100644 --- a/packages/core/src/asset-modules/sitewise-asset-tree/assetTreeSession.ts +++ b/packages/core/src/asset-modules/sitewise-asset-tree/assetTreeSession.ts @@ -1,10 +1,10 @@ import { - AssetTreeSubscription, BranchReference, HierarchyGroup, SiteWiseAssetTreeNode, SiteWiseAssetTreeQuery, SiteWiseAssetTreeObserver, + SiteWiseAssetTreeProvider, } from './types'; import { BehaviorSubject, debounceTime, Subject, Subscription } from 'rxjs'; import { AssetModelQuery, HIERARCHY_ROOT_ID, LoadingStateEnum, SiteWiseAssetSessionInterface } from '../sitewise/types'; @@ -28,7 +28,7 @@ class AssetNode { } } -export class SiteWiseAssetTreeSession { +export class SiteWiseAssetTreeSession implements SiteWiseAssetTreeProvider { private readonly assetSession: SiteWiseAssetSessionInterface; private readonly query: SiteWiseAssetTreeQuery; // look up a node by its assetId @@ -71,20 +71,13 @@ export class SiteWiseAssetTreeSession { } } - public subscribe(observer: SiteWiseAssetTreeObserver): AssetTreeSubscription { - const subscription: Subscription = this.subject.subscribe(observer); + public subscribe(observer: SiteWiseAssetTreeObserver): void { + this.subject.subscribe(observer); + } - return { - unsubscribe: () => { - subscription.unsubscribe(); - }, - expand: (branchRef) => { - this.expand(branchRef); - }, - collapse: (branchRef) => { - this.collapse(branchRef); - }, - }; + public unsubscribe(): void { + this.treeUpdateSubscription.unsubscribe(); + this.assetSession.close(); } public expand(branchRef: BranchReference): void { diff --git a/packages/core/src/asset-modules/sitewise-asset-tree/types.ts b/packages/core/src/asset-modules/sitewise-asset-tree/types.ts index 2557cf186..806f2db58 100644 --- a/packages/core/src/asset-modules/sitewise-asset-tree/types.ts +++ b/packages/core/src/asset-modules/sitewise-asset-tree/types.ts @@ -1,7 +1,17 @@ import { AssetPropertyValue, AssetSummary, DescribeAssetModelResponse } from '@aws-sdk/client-iotsitewise'; -import { LoadingStateEnum } from '../sitewise/types'; +import { AssetSummaryQuery, LoadingStateEnum } from '../sitewise/types'; import { ErrorDetails } from '../../common/types'; +import { + IoTAppKitComponentSession, + Provider, + ProviderObserver, + datamodule, + SiteWiseAssetTreeSession, + Query, + SiteWiseAssetSession, +} from '../../index'; + export type SiteWiseAssetTreeNode = { asset: AssetSummary; model?: DescribeAssetModelResponse; @@ -17,18 +27,51 @@ export type HierarchyGroup = { children: SiteWiseAssetTreeNode[]; }; -export type SiteWiseAssetTreeQuery = { - rootAssetId: string | undefined; +export type SiteWiseAssetTreeQueryArguments = { withModels?: boolean; - propertyIds?: string[]; + withPropertyValues?: [string]; +}; + +export type RootedSiteWiseAssetTreeQueryArguments = SiteWiseAssetTreeQueryArguments & { + asset: AssetSummaryQuery; }; -export type AssetTreeSubscription = { - unsubscribe: () => void; - expand: (branchRef: BranchReference) => void; - collapse: (branchRef: BranchReference) => void; +export class SiteWiseAssetTreeQuery implements Query { + readonly rootAssetId: string | undefined; + readonly withModels: boolean; + readonly propertyIds: string[]; + + constructor(args?: { asset?: AssetSummaryQuery; withModels?: boolean; withPropertyValues?: string[] }) { + this.rootAssetId = args?.asset?.assetId; + this.withModels = args?.withModels || false; + this.propertyIds = args?.withPropertyValues || []; + } + + build(session: IoTAppKitComponentSession, params?: void): SiteWiseAssetTreeProvider { + const assetSession: SiteWiseAssetSession = datamodule.iotsitewise.assetDataSession(session); + return new SiteWiseAssetTreeSession(assetSession, this); + } +} + +export const isSiteWiseAssetTreeQuery = (query: SiteWiseAssetTreeQuery | any): query is SiteWiseAssetTreeQuery => { + const asSiteWiseQuery: SiteWiseAssetTreeQuery = query as SiteWiseAssetTreeQuery; + return ( + asSiteWiseQuery.hasOwnProperty('rootAssetId') && + asSiteWiseQuery.hasOwnProperty('withModels') && + asSiteWiseQuery.hasOwnProperty('propertyIds') + ); }; +export interface SiteWiseAssetTreeObserver extends ProviderObserver { + next: (tree: SiteWiseAssetTreeNode[]) => void; + error?: (err: ErrorDetails[]) => void; +} + +export interface SiteWiseAssetTreeProvider extends Provider { + expand(branchRef: BranchReference): void; + collapse(branchRef: BranchReference): void; +} + export class BranchReference { public readonly assetId: string | undefined; public readonly hierarchyId: string; @@ -40,8 +83,3 @@ export class BranchReference { this.key = this.hierarchyId + (assetId || ''); } } - -export type SiteWiseAssetTreeObserver = { - next: (tree: SiteWiseAssetTreeNode[]) => void; - error?: (err: ErrorDetails[]) => void; -}; diff --git a/packages/core/src/data-module/index.ts b/packages/core/src/data-module/index.ts deleted file mode 100644 index 9baeda958..000000000 --- a/packages/core/src/data-module/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { SiteWiseAssetModule } from '../asset-modules'; - -let siteWiseAssetModule: SiteWiseAssetModule | undefined = undefined; - -export const getSiteWiseAssetModule = (): SiteWiseAssetModule => { - if (siteWiseAssetModule != null) { - return siteWiseAssetModule; - } - throw new Error( - 'No SiteWiseAssetModule module initialize: you must first call initialize to ensure the SiteWiseAssetModule is present.' - ); -}; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index fd7138a25..a7dc8190c 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -2,11 +2,9 @@ import { IoTSiteWiseClient } from '@aws-sdk/client-iotsitewise/dist-types/IoTSit import { Credentials } from '@aws-sdk/types'; import { Provider as AWSCredentialsProvider } from '@aws-sdk/types/dist-types/util'; import { DataSource, DataStreamQuery } from './data-module/types'; -import { AssetTreeSubscription, SiteWiseAssetTreeObserver, SiteWiseAssetTreeQuery } from './asset-modules'; import { TimeSeriesDataRequest } from './data-module/data-cache/requestTypes'; export * from './data-module/data-cache/requestTypes'; -export * from './data-module/index'; export * from './asset-modules/index'; export * from './iotAppKit'; export * from './module-namespace'; @@ -31,8 +29,6 @@ export type IoTAppKitInitInputs = export interface IoTAppKit { session: (componentId: string) => IoTAppKitComponentSession; registerTimeSeriesDataSource: (dataSource: DataSource) => void; - /** @todo: create asset provider */ - subscribeToAssetTree: (query: SiteWiseAssetTreeQuery, observer: SiteWiseAssetTreeObserver) => AssetTreeSubscription; } export interface Closeable { @@ -46,13 +42,18 @@ export interface IoTAppKitComponentSession extends Closeable { attachDataModuleSession(session: DataModuleSession): void; } -export interface Query { - build(session: IoTAppKitComponentSession, params?: Params): Provider; +export interface ProviderObserver { + next: (data: DataType) => void; + error?: (error: any) => void; } -export interface TimeSeriesQuery extends Query {} - export interface Provider { - subscribe(callback: (data: DataType) => void): void; + subscribe(observer: ProviderObserver): void; unsubscribe(): void; } + +export interface Query { + build(session: IoTAppKitComponentSession, params?: Params): Provider; +} + +export interface TimeSeriesQuery extends Query {} 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 3ebd83bfc..cdf07a55a 100644 --- a/packages/core/src/iotsitewise/time-series-data/provider.spec.ts +++ b/packages/core/src/iotsitewise/time-series-data/provider.spec.ts @@ -59,7 +59,7 @@ it('subscribes, updates, and unsubscribes to time series data by delegating to u const timeSeriesCallback = jest.fn(); // subscribe - provider.subscribe(timeSeriesCallback); + provider.subscribe({ next: timeSeriesCallback }); expect(timeSeriesCallback).toBeCalledWith({ dataStreams: [ diff --git a/packages/core/src/iotsitewise/time-series-data/provider.ts b/packages/core/src/iotsitewise/time-series-data/provider.ts index d26781d40..9d7025342 100644 --- a/packages/core/src/iotsitewise/time-series-data/provider.ts +++ b/packages/core/src/iotsitewise/time-series-data/provider.ts @@ -1,5 +1,5 @@ import { DataModuleSubscription, SubscriptionUpdate } from '../../data-module/types'; -import { datamodule, IoTAppKitComponentSession, Provider } from '../..'; +import { datamodule, IoTAppKitComponentSession, Provider, ProviderObserver } from '../..'; import { subscribeToTimeSeriesData } from './subscribeToTimeSeriesData'; import { TimeSeriesData, SiteWiseDataStreamQuery } from './types'; import { MinimalViewPortConfig } from '@synchro-charts/core'; @@ -19,13 +19,13 @@ export class SiteWiseTimeSeriesDataProvider implements Provider this.input = input; } - subscribe(callback: (data: TimeSeriesData) => void) { + subscribe(observer: ProviderObserver) { const { session } = this; const { update, unsubscribe } = subscribeToTimeSeriesData( datamodule.iotsitewise.timeSeriesDataSession(session), datamodule.iotsitewise.assetDataSession(session) - )(this.input, callback); + )(this.input, observer.next); this.update = update; diff --git a/packages/core/src/module-namespace.ts b/packages/core/src/module-namespace.ts index b9aa08b74..5f5d3583b 100644 --- a/packages/core/src/module-namespace.ts +++ b/packages/core/src/module-namespace.ts @@ -1,4 +1,4 @@ -import { IoTAppKitComponentSession } from './index'; +import { IoTAppKitComponentSession, SiteWiseAssetTreeSession } from './index'; import { DataModule } from './data-module/types'; import { SiteWiseAssetSession } from '.'; import { SiteWiseComponentSession } from './iotsitewise/component-session'; diff --git a/packages/core/src/query-namespace.ts b/packages/core/src/query-namespace.ts index 7d7b585f9..340735cbb 100644 --- a/packages/core/src/query-namespace.ts +++ b/packages/core/src/query-namespace.ts @@ -1,5 +1,13 @@ import { SiteWiseTimeSeriesDataProvider } from './iotsitewise/time-series-data/provider'; -import { IoTAppKitComponentSession, TimeSeriesDataRequest, TimeSeriesQuery, SiteWiseAssetQuery } from './index'; +import { + IoTAppKitComponentSession, + TimeSeriesDataRequest, + TimeSeriesQuery, + SiteWiseAssetQuery, + SiteWiseAssetTreeQuery, + SiteWiseAssetTreeQueryArguments, + RootedSiteWiseAssetTreeQueryArguments, +} from './index'; /** * Extensible query namespace exposing methods that return Query implementations @@ -17,4 +25,21 @@ export namespace query.iotsitewise { request: params, }), }); + + export const assetTree = { + fromRoot(args?: SiteWiseAssetTreeQueryArguments): SiteWiseAssetTreeQuery { + return new SiteWiseAssetTreeQuery({ + asset: undefined, + withModels: args?.withModels, + withPropertyValues: args?.withPropertyValues, + }); + }, + fromAsset(args: RootedSiteWiseAssetTreeQueryArguments): SiteWiseAssetTreeQuery { + return new SiteWiseAssetTreeQuery({ + asset: args.asset, + withModels: args.withModels, + withPropertyValues: args.withPropertyValues, + }); + }, + }; }