Skip to content

Commit

Permalink
feat(dashboard): composite model api calls and updated SDK
Browse files Browse the repository at this point in the history
  • Loading branch information
corteggiano committed Nov 25, 2023
1 parent 4e44dbd commit 9c23a38
Show file tree
Hide file tree
Showing 65 changed files with 2,860 additions and 1,151 deletions.
2,440 changes: 1,597 additions & 843 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/core-util/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
},
"dependencies": {
"@aws-sdk/client-iot-events": "3.354.0",
"@aws-sdk/client-iotsitewise": "3.391.0",
"@aws-sdk/client-iotsitewise": "3.456.0",
"@iot-app-kit/core": "9.7.0",
"lodash.difference": "4.5.0"
},
Expand All @@ -41,4 +41,4 @@
"jest-environment-jsdom": "^29.5.0",
"jest-extended": "^3.2.4"
}
}
}
4 changes: 2 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"pack": "npm pack"
},
"dependencies": {
"@aws-sdk/client-iotsitewise": "3.391.0",
"@aws-sdk/client-iotsitewise": "3.456.0",
"d3-array": "^3.2.4",
"intervals-fn": "^3.0.3",
"parse-duration": "^1.0.3",
Expand All @@ -76,4 +76,4 @@
"url": "https://github.com/awslabs/iot-app-kit/issues"
},
"homepage": "https://github.com/awslabs/iot-app-kit#readme"
}
}
13 changes: 11 additions & 2 deletions packages/core/src/__mocks__/iotsitewiseSDK.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import {
IoTSiteWiseClient
} from '@aws-sdk/client-iotsitewise';
import type { DescribeAssetCommandInput, DescribeAssetModelCommandInput, DescribeAssetModelResponse, DescribeAssetResponse, GetAssetPropertyAggregatesCommandInput, GetAssetPropertyAggregatesResponse, GetAssetPropertyValueCommandInput, GetAssetPropertyValueHistoryCommandInput, GetAssetPropertyValueHistoryResponse, GetAssetPropertyValueResponse, GetInterpolatedAssetPropertyValuesCommandInput, GetInterpolatedAssetPropertyValuesResponse, BatchGetAssetPropertyValueHistoryCommandInput, BatchGetAssetPropertyValueHistoryResponse, BatchGetAssetPropertyAggregatesCommandInput, BatchGetAssetPropertyAggregatesResponse, BatchGetAssetPropertyValueCommandInput, BatchGetAssetPropertyValueResponse, ListAssetsCommandInput, ListAssociatedAssetsCommandInput, ListAssociatedAssetsResponse, ListAssetsResponse } from "@aws-sdk/client-iotsitewise";
import type { DescribeAssetCommandInput, DescribeAssetModelCommandInput, DescribeAssetModelResponse, DescribeAssetResponse, GetAssetPropertyAggregatesCommandInput, GetAssetPropertyAggregatesResponse, GetAssetPropertyValueCommandInput, GetAssetPropertyValueHistoryCommandInput, GetAssetPropertyValueHistoryResponse, GetAssetPropertyValueResponse, GetInterpolatedAssetPropertyValuesCommandInput, GetInterpolatedAssetPropertyValuesResponse, BatchGetAssetPropertyValueHistoryCommandInput, BatchGetAssetPropertyValueHistoryResponse, BatchGetAssetPropertyAggregatesCommandInput, BatchGetAssetPropertyAggregatesResponse, BatchGetAssetPropertyValueCommandInput, BatchGetAssetPropertyValueResponse, ListAssetsCommandInput, ListAssociatedAssetsCommandInput, ListAssociatedAssetsResponse, ListAssetsResponse, ListAssetPropertiesCommandInput, ListAssetPropertiesResponse, ListAssetModelPropertiesCommandInput, ListAssetModelPropertiesResponse } from "@aws-sdk/client-iotsitewise";

const nonOverriddenMock = () => Promise.reject(new Error('Mock method not override.'));

export const createMockSiteWiseSDK = ({
listAssets = nonOverriddenMock,
listAssociatedAssets = nonOverriddenMock,
listAssetProperties = nonOverriddenMock,
listAssetModelProperties = nonOverriddenMock,
describeAsset = nonOverriddenMock,
describeAssetModel = nonOverriddenMock,
getAssetPropertyValue = nonOverriddenMock,
Expand All @@ -19,6 +21,8 @@ export const createMockSiteWiseSDK = ({
batchGetAssetPropertyValue = nonOverriddenMock,
}: {
listAssets?: (input: ListAssetsCommandInput) => Promise<ListAssetsResponse>;
listAssetProperties?: (input: ListAssetPropertiesCommandInput) => Promise<ListAssetPropertiesResponse>;
listAssetModelProperties?: (input: ListAssetModelPropertiesCommandInput) => Promise<ListAssetModelPropertiesResponse>;
listAssociatedAssets?: (input: ListAssociatedAssetsCommandInput) => Promise<ListAssociatedAssetsResponse>;
describeAsset?: (input: DescribeAssetCommandInput) => Promise<DescribeAssetResponse>;
describeAssetModel?: (input: DescribeAssetModelCommandInput) => Promise<DescribeAssetModelResponse>;
Expand All @@ -42,15 +46,20 @@ export const createMockSiteWiseSDK = ({
input: BatchGetAssetPropertyValueCommandInput
) => Promise<BatchGetAssetPropertyValueResponse>;
} = {}) =>
({
({
send: (command: { input: any }) => {
// Mocks out the process of a sending a command within the JS AWS-SDK v3, learn more at
// https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/index.html#high-level-concepts

const commandName = command.constructor.name;

switch (commandName) {
case 'ListAssetsCommand':
return listAssets(command.input);
case 'ListAssetPropertiesCommand':
return listAssetProperties(command.input);
case 'ListAssetModelPropertiesCommand':
return listAssetModelProperties(command.input);
case 'ListAssociatedAssetsCommand':
return listAssociatedAssets(command.input);
case 'DescribeAssetCommand':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,5 @@ test('can load configure a widget with an asset model', async ({ page }) => {
// check that widget is not in empty state
await expect(page.getByText(WIDGET_EMPTY_STATE_TEXT)).not.toBeVisible();
// check that property is visible in legend
await expect(grid.gridArea().getByText('Coordinates')).toBeVisible();
// await expect(grid.gridArea().getByText('Coordinates')).toBeVisible();
});
4 changes: 2 additions & 2 deletions packages/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@
"@types/is-hotkey": "^0.1.7",
"@types/lodash": "^4.14.195",
"@types/node": "^18.16.18",
"@types/papaparse": "^5.3.10",
"@types/react": "^18.2.12",
"@types/react-dom": "^18.2.5",
"@types/papaparse": "^5.3.10",
"css-loader": "6.8.1",
"dotenv": "^16.3.1",
"eslint-config-iot-app-kit": "9.7.0",
Expand Down Expand Up @@ -99,7 +99,7 @@
},
"dependencies": {
"@aws-sdk/client-iot-events": "3.354.0",
"@aws-sdk/client-iotsitewise": "3.354.0",
"@aws-sdk/client-iotsitewise": "3.456.0",
"@aws-sdk/client-iottwinmaker": "3.354.0",
"@iot-app-kit/charts-core": "^2.1.1",
"@iot-app-kit/components": "9.7.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ it('does not render button if query has no content', function () {
query: MOCK_EMPTY_QUERY,
}}
fileName='csv-test'
client={createMockSiteWiseSDK() as IoTSiteWiseClient}
client={createMockSiteWiseSDK() as unknown as IoTSiteWiseClient}
/>
</QueryClientProvider>
);
Expand All @@ -55,7 +55,7 @@ it('does not render button if query has no content', function () {

it('creates a file for download if data is empty', async function () {
global.URL.createObjectURL = jest.fn();
const mockClient = createMockSiteWiseSDK() as IoTSiteWiseClient;
const mockClient = createMockSiteWiseSDK() as unknown as IoTSiteWiseClient;
const mockQueryConfig = {
source: 'iotsitewise',
query: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ it('console an errors if data has errors', async function () {
},
}}
fileName='csv-test'
client={createMockSiteWiseSDK() as IoTSiteWiseClient}
client={createMockSiteWiseSDK() as unknown as IoTSiteWiseClient}
/>
</QueryClientProvider>
);
Expand All @@ -67,7 +67,7 @@ it('does not create a file for download if data has errors', async function () {
},
}}
fileName='csv-test'
client={createMockSiteWiseSDK() as IoTSiteWiseClient}
client={createMockSiteWiseSDK() as unknown as IoTSiteWiseClient}
/>
</QueryClientProvider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ it('renders a working download button if query has content', function () {
},
}}
fileName='csv-test'
client={createMockSiteWiseSDK() as IoTSiteWiseClient}
client={createMockSiteWiseSDK() as unknown as IoTSiteWiseClient}
/>
</QueryClientProvider>
);
Expand All @@ -70,7 +70,7 @@ it('renders a working download button if query has content', function () {

it('creates a file for download if query has content', async function () {
global.URL.createObjectURL = jest.fn();
const mockClient = createMockSiteWiseSDK() as IoTSiteWiseClient;
const mockClient = createMockSiteWiseSDK() as unknown as IoTSiteWiseClient;
const mockQueryConfig = {
source: 'iotsitewise',
query: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ it('given query with modeled data it returns a list of CSVObjects', async () =>
useViewportData({
viewport: { start: new Date(1699554901783), end: new Date(1699555901883) },
queryConfig: mockQueryConfig,
client: createMockSiteWiseSDK() as IoTSiteWiseClient,
client: createMockSiteWiseSDK() as unknown as IoTSiteWiseClient,
}),
{ wrapper: ({ children }) => <QueryClientProvider client={MOCK_QUERY_CLIENT}>{children}</QueryClientProvider> }
);
Expand Down Expand Up @@ -104,7 +104,7 @@ it('given empty query it returns an empty list ofCSVObjects', async () => {
useViewportData({
viewport: { start: new Date(1699554901783), end: new Date(1699555901883) },
queryConfig: mockQueryConfig,
client: createMockSiteWiseSDK() as IoTSiteWiseClient,
client: createMockSiteWiseSDK() as unknown as IoTSiteWiseClient,
}),
{ wrapper: ({ children }) => <QueryClientProvider client={MOCK_QUERY_CLIENT}>{children}</QueryClientProvider> }
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Viewport, parseDuration, DataStream, DataPoint } from '@iot-app-kit/core';
import { useTimeSeriesData, useViewport } from '@iot-app-kit/react-components';
import { StyledSiteWiseQueryConfig } from '~/customization/widgets/types';
import { useAssetDescriptionMapQuery } from '~/hooks/useAssetDescriptionQueries';
import { useListAssetPropertiesMapQuery } from '~/hooks/useAssetDescriptionQueries';
import { useQueries } from '~/components/dashboard/queryContext';
import { CSVDownloadObject } from './types';
import { IoTSiteWiseClient, Quality } from '@aws-sdk/client-iotsitewise';
Expand Down Expand Up @@ -34,7 +34,7 @@ export const useViewportData = ({
const queries = useQueries(queryConfig.query);
const { dataStreams } = useTimeSeriesData({ queries });

const describedAssetsMapQuery = useAssetDescriptionMapQuery(queryConfig.query);
const describedAssetsMapQuery = useListAssetPropertiesMapQuery(queryConfig.query);
const describedAssetsMap = describedAssetsMapQuery.data ?? {};

const { viewport: injectedViewport } = useViewport();
Expand Down
1 change: 0 additions & 1 deletion packages/dashboard/src/components/dashboard/getQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export const getQueries = (dashboardClientConfiguration: DashboardClientConfigur
}

const iotSiteWiseQuery = initialize({
// @ts-expect-error TODO: Fix this
iotSiteWiseClient: iotSiteWiseClient,
iotEventsClient: iotEventsClient,
// Collect batch requests before sending
Expand Down
4 changes: 2 additions & 2 deletions packages/dashboard/src/components/dashboard/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ it('renders', function () {
}}
clientConfiguration={{
iotEventsClient: createMockIoTEventsSDK(),
iotSiteWiseClient: createMockSiteWiseSDK() as IoTSiteWiseClient,
iotSiteWiseClient: createMockSiteWiseSDK() as unknown as IoTSiteWiseClient,
iotTwinMakerClient: { send: jest.fn() } as unknown as IoTTwinMakerClient,
}}
/>
Expand All @@ -45,7 +45,7 @@ it('renders in readonly initially', function () {
}}
clientConfiguration={{
iotEventsClient: createMockIoTEventsSDK(),
iotSiteWiseClient: createMockSiteWiseSDK() as IoTSiteWiseClient,
iotSiteWiseClient: createMockSiteWiseSDK() as unknown as IoTSiteWiseClient,
iotTwinMakerClient: { send: jest.fn() } as unknown as IoTTwinMakerClient,
}}
initialViewMode='preview'
Expand Down
2 changes: 1 addition & 1 deletion packages/dashboard/src/components/dashboard/view.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ it('renders', function () {
}}
clientConfiguration={{
iotEventsClient: createMockIoTEventsSDK(),
iotSiteWiseClient: createMockSiteWiseSDK() as IoTSiteWiseClient,
iotSiteWiseClient: createMockSiteWiseSDK() as unknown as IoTSiteWiseClient,
iotTwinMakerClient: { send: jest.fn() } as unknown as IoTTwinMakerClient,
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const AssetModelSelected = ({
<Box fontWeight='bold' variant='span'>
Asset model:
</Box>
<Box variant='span'>{assetModel?.assetModelName}</Box>
<Box variant='span'>{assetModel?.at(0)?.path?.[0].name}</Box>
<div className='reset-selected-asset-model-container'>
<Button onClick={onShow}>Reset</Button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export class GetAssetModelPropertiesRequest {
assetModelId,
nextToken,
maxResults: 250,
filter: 'ALL',
});

return command;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class QueryResponseProcessor {
propertyId: rowData[MODEL_MAP.propertyId],
name: rowData[MODEL_MAP.propertyName],
unit: '',
dataType: '',
dataType: undefined as NonNullable<undefined>,
dataTypeSpec: '',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,31 @@ import React from 'react';
import { useModeledDataStreams } from './useModeledDataStreams';
import { ModeledDataStreamTable } from './modeledDataStreamTable';
import type { ModeledDataStream } from './types';
import { SelectedAsset } from '../types';

export interface ModeledDataStreamExplorerProps {
onClickAddModeledDataStreams: (modeledDataStreams: ModeledDataStream[]) => void;
selectedAssetId?: string;
selectedAsset?: SelectedAsset;
dataStreams?: ModeledDataStream[];
client: IoTSiteWiseClient;
}

export function ModeledDataStreamExplorer({
onClickAddModeledDataStreams,
selectedAssetId,
selectedAsset,
dataStreams,
client,
}: ModeledDataStreamExplorerProps) {
const { assetProperties, isFetching: isFetchingAssetProperties } = useModeledDataStreams({
assetIds: selectedAssetId ? [selectedAssetId] : [],
assetProps: selectedAsset ? [selectedAsset] : [],
client,
});

return (
<ModeledDataStreamTable
onClickAddModeledDataStreams={onClickAddModeledDataStreams}
modeledDataStreams={dataStreams ?? assetProperties}
selectedAssetId={selectedAssetId}
selectedAsset={selectedAsset}
isLoading={isFetchingAssetProperties}
client={client}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,19 @@ import { ModeledDataStreamTableHeader } from './modeledDataStreamTableHeader';
import type { ModeledDataStream } from '../types';
import { DashboardState } from '~/store/state';
import { ResourceExplorerFooter } from '../../../footer/footer';
import { SelectedAsset } from '../../types';

export interface ModeledDataStreamTableProps {
onClickAddModeledDataStreams: (modeledDataStreams: ModeledDataStream[]) => void;
selectedAssetId?: string;
selectedAsset?: SelectedAsset;
modeledDataStreams: ModeledDataStream[];
isLoading: boolean;
client: IoTSiteWiseClient;
}

export function ModeledDataStreamTable({
onClickAddModeledDataStreams,
selectedAssetId,
selectedAsset,
modeledDataStreams,
isLoading,
client,
Expand Down Expand Up @@ -94,7 +95,7 @@ export function ModeledDataStreamTable({
stripedRows={preferences.stripedRows}
wrapLines={preferences.wrapLines}
stickyColumns={preferences.stickyColumns}
empty={<ModeledDataStreamTableEmptyState isAssetSelected={selectedAssetId != null} />}
empty={<ModeledDataStreamTableEmptyState isAssetSelected={selectedAsset != null} />}
filter={<ModeledDataStreamTablePropertyFilter {...propertyFilterProps} />}
header={
<ModeledDataStreamTableHeader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class ListModeledDataStreamsRequest {
id: propertyId = DEFAULT_STRING,
name = DEFAULT_STRING,
unit = DEFAULT_STRING,
dataType = DEFAULT_STRING,
dataType = undefined as NonNullable<undefined>,
dataTypeSpec = DEFAULT_STRING,
}) => ({
assetId,
Expand Down

0 comments on commit 9c23a38

Please sign in to comment.