From 7b0f3cf443d89ff7f89f334d9c5abb7400ab084b Mon Sep 17 00:00:00 2001 From: db <77755322+diehbria@users.noreply.github.com> Date: Wed, 16 Feb 2022 11:28:55 -0800 Subject: [PATCH] feat: create react-components and source-iotsitewise pkgs (#57) * move core build files away from stencil config into package.json to prepare moving away from stencil to build core * fix various typing issues in iot-app-kit * remove unused code * remove unecessary `AssetQuery` type, which collides with other types * make test runner fail if uncommited changes present --- package.json | 7 +- packages/components/package.json | 8 +- .../iot-connector.spec.component.ts | 5 +- .../src/testing/mockWidgetProperties.ts | 112 +-- .../components/src/testing/renderChart.tsx | 5 +- packages/components/tsconfig.json | 1 + packages/core/global.d.ts | 1 + packages/core/jest.config.js | 20 + packages/core/package.json | 31 +- packages/core/rollup.config.js | 24 + .../sitewise/requestProcessorWorkerGroup.ts | 5 +- .../src/asset-modules/sitewise/session.ts | 32 +- .../core/src/asset-modules/sitewise/types.ts | 18 +- packages/core/src/common/getDataPoints.ts | 2 +- packages/core/src/components.d.ts | 0 .../data-module/IotAppKitDataModule.spec.ts | 2 +- .../src/data-module/IotAppKitDataModule.ts | 6 +- .../src/data-module/data-cache/dataActions.ts | 2 +- .../data-module/data-cache/requestTypes.ts | 2 +- .../data-module/data-cache/toDataStreams.ts | 2 +- .../data-source-store/dataSourceStore.spec.ts | 2 +- .../data-source-store/dataSourceStore.ts | 2 +- .../subscriptionStore.spec.ts | 9 +- .../subscription-store/subscriptionStore.ts | 2 +- .../src/data-module/{types.d.ts => types.ts} | 19 +- packages/core/src/global.d.ts | 790 ------------------ packages/core/src/index.html | 13 - packages/core/src/index.ts | 50 ++ packages/core/src/interface.d.ts | 61 -- packages/core/src/iotAppKit.ts | 2 +- .../src/iotsitewise/__mocks__/data-source.ts | 2 +- .../core/src/iotsitewise/component-session.ts | 2 +- .../client/getAggregatedPropertyDataPoints.ts | 3 +- .../client/getHistoricalPropertyDataPoints.ts | 43 +- .../time-series-data/data-source.spec.ts | 18 +- .../time-series-data/provider.spec.ts | 2 +- .../iotsitewise/time-series-data/provider.ts | 3 +- .../subscribeToTimeSeriesData.spec.ts | 11 +- .../subscribeToTimeSeriesData.ts | 12 +- .../time-series-data/{types.d.ts => types.ts} | 13 +- packages/core/src/module-namespace.ts | 2 +- packages/core/src/query-namespace.ts | 2 +- packages/core/stencil.config.ts | 28 - packages/core/tsconfig.json | 11 +- packages/react-components/package.json | 50 ++ packages/react-components/src/components.ts | 16 + .../react-components/src/components/index.ts | 1 + .../src/components/stencil-generated/index.ts | 30 + packages/react-components/src/index.ts | 1 + .../react-component-lib/createComponent.tsx | 106 +++ .../createOverlayComponent.tsx | 142 ++++ .../src/react-component-lib/index.ts | 2 + .../src/react-component-lib/interfaces.ts | 34 + .../react-component-lib/utils/attachProps.ts | 114 +++ .../src/react-component-lib/utils/case.ts | 7 + .../src/react-component-lib/utils/dev.ts | 14 + .../src/react-component-lib/utils/index.tsx | 50 ++ packages/react-components/tsconfig.json | 32 + packages/related-table/jest.config.ts | 184 +--- packages/related-table/package.json | 22 +- packages/source-iotsitewise/README.md | 11 + .../lib/source-iotsitewise.js | 7 + packages/source-iotsitewise/package.json | 28 + 63 files changed, 886 insertions(+), 1352 deletions(-) create mode 100644 packages/core/global.d.ts create mode 100644 packages/core/jest.config.js create mode 100644 packages/core/rollup.config.js mode change 100755 => 100644 packages/core/src/components.d.ts rename packages/core/src/data-module/{types.d.ts => types.ts} (90%) delete mode 100755 packages/core/src/global.d.ts delete mode 100755 packages/core/src/index.html delete mode 100755 packages/core/src/interface.d.ts rename packages/core/src/iotsitewise/time-series-data/{types.d.ts => types.ts} (76%) delete mode 100755 packages/core/stencil.config.ts create mode 100644 packages/react-components/package.json create mode 100644 packages/react-components/src/components.ts create mode 100644 packages/react-components/src/components/index.ts create mode 100644 packages/react-components/src/components/stencil-generated/index.ts create mode 100644 packages/react-components/src/index.ts create mode 100644 packages/react-components/src/react-component-lib/createComponent.tsx create mode 100644 packages/react-components/src/react-component-lib/createOverlayComponent.tsx create mode 100644 packages/react-components/src/react-component-lib/index.ts create mode 100644 packages/react-components/src/react-component-lib/interfaces.ts create mode 100644 packages/react-components/src/react-component-lib/utils/attachProps.ts create mode 100644 packages/react-components/src/react-component-lib/utils/case.ts create mode 100644 packages/react-components/src/react-component-lib/utils/dev.ts create mode 100644 packages/react-components/src/react-component-lib/utils/index.tsx create mode 100644 packages/react-components/tsconfig.json create mode 100644 packages/source-iotsitewise/README.md create mode 100644 packages/source-iotsitewise/lib/source-iotsitewise.js create mode 100644 packages/source-iotsitewise/package.json diff --git a/package.json b/package.json index 88bb7dbe8..ede4c937b 100755 --- a/package.json +++ b/package.json @@ -15,12 +15,12 @@ "start": "cd packages/components && yarn run start", "build": "lerna run build --stream", "clean": "git clean -dxf -e /.idea -e /.vscode -e creds.json", - "lint": "npm-run-all -p lint:eslint", - "lint:eslint": "eslint --ext .js,.ts,.tsx . --max-warnings 0", "fix": "npm-run-all -p fix:eslint", "fix:eslint": "eslint --fix --ext .js,.ts,.tsx .", - "test": "npm-run-all -p test:unit lint", + "test": "npm-run-all -p test:unit test:eslint test:git", + "test:eslint": "eslint --ext .js,.ts,.tsx . --max-warnings 0", "test:unit": "lerna run test --stream --concurrency 1", + "test:git": "git diff --exit-code", "pack": "lerna run pack" }, "devDependencies": { @@ -55,7 +55,6 @@ "cypress-shadow-dom": "^1.3.0", "eslint": "^8.2.0", "eslint-config-airbnb-base": "^15.0.0", - "eslint-config-airbnb-typescript": "14.0.1", "eslint-config-prettier": "8.3.0", "eslint-plugin-chai-friendly": "0.7.2", "eslint-plugin-cypress": "2.12.1", diff --git a/packages/components/package.json b/packages/components/package.json index 51deae7e4..c70fba19d 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -30,10 +30,10 @@ "@awsui/collection-hooks": "^1.0.0", "@awsui/components-react": "^3.0.0", "@awsui/design-tokens": "^3.0.0", - "@iot-app-kit/core": "^0.0.1", - "@iot-app-kit/related-table": "^1.0.0", + "@iot-app-kit/core": "0.0.1", + "@iot-app-kit/related-table": "1.0.0", "@stencil/core": "^2.7.0", - "@synchro-charts/core": "^1.0.8", + "@synchro-charts/core": "^1.1.1", "styled-components": "^5.3.0" }, "devDependencies": { @@ -50,6 +50,8 @@ "cypress": "7.7.0", "cypress-image-snapshot": "^4.0.1", "cypress-wait-until": "^1.7.2", + "jest": "26.3.0", + "jest-cli": "^26.5.1", "vue": "^3.2.26" }, "license": "Apache-2.0" diff --git a/packages/components/src/integration/iot-connector/iot-connector.spec.component.ts b/packages/components/src/integration/iot-connector/iot-connector.spec.component.ts index 1d6ab091c..f0bfae3e4 100644 --- a/packages/components/src/integration/iot-connector/iot-connector.spec.component.ts +++ b/packages/components/src/integration/iot-connector/iot-connector.spec.component.ts @@ -1,8 +1,9 @@ -import { renderChart, testChartContainerClassNameSelector } from '@iot-app-kit/components/src/testing/renderChart'; -import { SECOND_IN_MS } from '@iot-app-kit/core/src/common/time'; +import { renderChart, testChartContainerClassNameSelector } from '../../testing/renderChart'; import { mockGetAggregatedOrRawResponse } from '../../testing/mocks/mockGetAggregatedOrRawResponse'; import { mockGetAssetSummary } from '../../testing/mocks/mockGetAssetSummaries'; +const SECOND_IN_MS = 1000; + const snapshotOptions = { clip: { x: 0, y: 0, width: 400, height: 500 }, }; diff --git a/packages/components/src/testing/mockWidgetProperties.ts b/packages/components/src/testing/mockWidgetProperties.ts index c5e6143ad..ebe7ebcce 100755 --- a/packages/components/src/testing/mockWidgetProperties.ts +++ b/packages/components/src/testing/mockWidgetProperties.ts @@ -1,72 +1,12 @@ -import { - COMPARISON_OPERATOR, - DataStreamInfo, - DataType, - StatusIcon, - StreamType, - Threshold, - ViewPort, -} from '@synchro-charts/core'; import { DataStream } from '@iot-app-kit/core'; import { toDataStreamId } from './dataStreamId'; -const DAY_IN_MS = 1000 * 60 * 60 * 24; -const VIEW_PORT: ViewPort = { - start: new Date(2000, 0, 0, 0), - end: new Date(2001, 0, 0, 0), - yMin: 0, - yMax: 100, -}; - -/** - * Shared Mock Data - */ -// Number 1 -export const NUMBER_INFO_1: DataStreamInfo = { - id: 'number-some-id', - resolution: 0, - dataType: DataType.NUMBER, - color: 'cyan', - name: 'number-some-name', -}; -export const NUMBER_STREAM_1: DataStream = { - id: NUMBER_INFO_1.id, - color: 'cyan', - name: 'number-some-name', - dataType: 'NUMBER', - resolution: 0, - data: [ - { - x: new Date(2000, 0, 0, 0, 0).getTime(), - y: 100, - }, - ], -}; - -/** - * String Mock Data - */ - -// String Info 1 -export const STRING_INFO_1: DataStreamInfo = { - id: 'some-string-info', - resolution: 0, - dataType: DataType.STRING, - color: 'red', - name: 'some-name', -}; - -export const DATA_STREAM_INFO: DataStreamInfo = { +export const DATA_STREAM: DataStream = { id: toDataStreamId({ assetId: 'some-asset-id', propertyId: 'some-property-id' }), resolution: 0, detailedName: 'data-stream-name/detailed-name', name: 'data-stream-name', color: 'black', - dataType: DataType.NUMBER, -}; - -export const DATA_STREAM: DataStream = { - ...DATA_STREAM_INFO, dataType: 'NUMBER', data: [], }; @@ -79,53 +19,3 @@ export const DATA_STREAM_2: DataStream = { dataType: 'NUMBER', data: [], }; - -export const ALARM = 'alarm'; -export const OK = 'ok'; - -export const NON_BREACHED_ALARM_INFO: DataStreamInfo = { - id: 'alarm-stream-2', - resolution: 0, - dataType: DataType.STRING, - streamType: StreamType.ALARM, - name: 'alarm stream 2', - color: 'blue', -}; -export const WITHIN_VIEWPORT_DATE = new Date(2000, 0, 1); -export const BEFORE_VIEWPORT_DATE = new Date(VIEW_PORT.start.getTime() - DAY_IN_MS); - -export const ALARM_STREAM: DataStream = { - id: 'alarm-stream', - dataType: 'STRING', - name: 'alarm stream', - color: 'red', - streamType: StreamType.ALARM, - resolution: 0, - data: [ - { - x: WITHIN_VIEWPORT_DATE.getTime(), - y: ALARM, - }, - ], -}; - -export const ALARM_THRESHOLD: Threshold = { - value: ALARM, - color: 'orange', - comparisonOperator: COMPARISON_OPERATOR.EQUAL, - icon: StatusIcon.ACTIVE, -}; - -export const STRING_STREAM_1: DataStream = { - id: STRING_INFO_1.id, - dataType: 'STRING', - color: 'red', - name: 'some-name', - resolution: 0, - data: [ - { - x: new Date(2000, 0, 0, 0, 0).getTime(), - y: 'ALARM', - }, - ], -}; diff --git a/packages/components/src/testing/renderChart.tsx b/packages/components/src/testing/renderChart.tsx index 9e157360f..6f6c59845 100644 --- a/packages/components/src/testing/renderChart.tsx +++ b/packages/components/src/testing/renderChart.tsx @@ -1,5 +1,6 @@ import { mount } from '@cypress/vue'; import { h } from 'vue'; +import '@synchro-charts/core'; import { StyleSettingsMap, initialize, @@ -11,10 +12,10 @@ import { } 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'); +const { defineCustomElements } = require('@iot-app-kit/components/loader'); import '@synchro-charts/core/dist/synchro-charts/synchro-charts.css'; -applyPolyfills().then(() => defineCustomElements()); +defineCustomElements(); export const testChartContainerClassName = 'test-chart-container'; diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index b0784303c..799321c92 100755 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -10,6 +10,7 @@ "target": "es2017", "jsx": "react", "jsxFactory": "h", + "importHelpers": true, "esModuleInterop": true, "strict": true, "strictPropertyInitialization": false, diff --git a/packages/core/global.d.ts b/packages/core/global.d.ts new file mode 100644 index 000000000..9e6c1dbd9 --- /dev/null +++ b/packages/core/global.d.ts @@ -0,0 +1 @@ +import 'jest-extended'; diff --git a/packages/core/jest.config.js b/packages/core/jest.config.js new file mode 100644 index 000000000..a8ab4fc27 --- /dev/null +++ b/packages/core/jest.config.js @@ -0,0 +1,20 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + setupFilesAfterEnv: ['jest-extended/all'], + collectCoverageFrom: ['src/**/*.{ts,tsx}'], + coveragePathIgnorePatterns: ['/typings/', '/src/testing/', '/src/iotsitewise/__mocks__'], + testPathIgnorePatterns: ['/src/testing', '/dist'], + coverageReporters: ['text-summary', 'cobertura', 'html', 'json', 'json-summary'], + moduleNameMapper: { + '\\.(css|scss|svg)$': 'identity-obj-proxy', + }, + coverageThreshold: { + global: { + statements: 80, + branches: 80, + functions: 80, + lines: 80, + }, + }, +}; diff --git a/packages/core/package.json b/packages/core/package.json index 122aa67d1..ec61ea120 100755 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,16 +1,11 @@ { "name": "@iot-app-kit/core", + "license": "Apache-2.0", "version": "0.0.1", "description": "IoT Application Kit core", "main": "./dist/index.cj.js", "module": "./dist/index.js", - "es2015": "./dist/esm/index.js", - "es2017": "./dist/esm/index.js", - "jsnext:main": "./dist/esm/index.js", - "types": "./dist/types/interface.d.ts", - "collection": "./dist/collection/collection-manifest.json", - "collection:main": "./dist/collection/index.js", - "unpkg": "./dist/iot-app-kit/iot-app-kit.js", + "types": "./dist/index.d.ts", "publishConfig": { "access": "public" }, @@ -23,15 +18,14 @@ }, "scripts": { "clean": "rm -rf dist && rm -rf screenshot", - "build": "stencil build", - "start": "stencil build --dev --watch --serve", - "test": "npm-run-all -p test:unit-test test:typescript", - "test:unit-test": "TZ=UTC stencil test --spec --coverage", + "build": "yarn run clean && rollup --config rollup.config.js", + "test": "npm-run-all -p test:jest test:typescript", + "test:jest": "TZ=UTC jest --coverage", + "test.watch": "TZ=UTC jest --watchAll", "test:typescript": "tsc --noEmit", - "test.watch": "TZ=UTC stencil test --spec --watchAll", "copy:license": "cp ../../LICENSE LICENSE", "copy:notice": "cp ../../NOTICE NOTICE", - "release": "yarn run clean && npm-run-all -p build test lint", + "release": "yarn run clean && npm-run-all -p build test", "prepublishOnly": "yarn release", "prepack": "yarn run copy:license && yarn run copy:notice", "pack": "yarn pack" @@ -39,8 +33,8 @@ "dependencies": { "@aws-sdk/client-iotsitewise": "^3.39.0", "@aws-sdk/credential-providers": "^3.39.0", - "@stencil/core": "^2.10.0", - "@synchro-charts/core": "^1.0.8", + "@rollup/plugin-typescript": "^8.3.0", + "@synchro-charts/core": "^1.1.1", "d3-array": "^2.3.2", "flush-promises": "^1.0.2", "intervals-fn": "^3.0.3", @@ -56,5 +50,10 @@ "typescript": "4.4.4", "uuid": "^3.3.2" }, - "license": "Apache-2.0" + "devDependencies": { + "@types/jest": "^27.4.0", + "jest": "^27.5.1", + "jest-extended": "^2.0.0", + "ts-jest": "^27.1.3" + } } diff --git a/packages/core/rollup.config.js b/packages/core/rollup.config.js new file mode 100644 index 000000000..8acb654ac --- /dev/null +++ b/packages/core/rollup.config.js @@ -0,0 +1,24 @@ +import typescript from '@rollup/plugin-typescript'; +import pkg from './package.json'; + +export default [ + { + input: 'src/index.ts', + output: [ + { + file: pkg.main, + format: 'cjs', + }, + { + file: pkg.module, + format: 'esm', + }, + ], + plugins: [typescript({ tsconfig: './tsconfig.json' })], + }, + { + input: 'src/testing/index.ts', + output: { file: 'dist/testing/index.js', format: 'es' }, + plugins: [typescript()], + }, +]; diff --git a/packages/core/src/asset-modules/sitewise/requestProcessorWorkerGroup.ts b/packages/core/src/asset-modules/sitewise/requestProcessorWorkerGroup.ts index 019aa3491..7eea3df8f 100644 --- a/packages/core/src/asset-modules/sitewise/requestProcessorWorkerGroup.ts +++ b/packages/core/src/asset-modules/sitewise/requestProcessorWorkerGroup.ts @@ -1,8 +1,7 @@ -import { AssetQuery } from './types'; -import { Observable, Subscriber, Subscription } from 'rxjs'; +import { Observable, Subscriber } from 'rxjs'; import { RequestProcessorWorker } from './requestProcessorWorker'; -export class RequestProcessorWorkerGroup { +export class RequestProcessorWorkerGroup { private readonly activeQueries: Map> = new Map(); private readonly workerFactory: (query: TQuery) => Observable; private readonly queryToKey: (query: TQuery) => string; diff --git a/packages/core/src/asset-modules/sitewise/session.ts b/packages/core/src/asset-modules/sitewise/session.ts index f872df1c6..462d65d0b 100644 --- a/packages/core/src/asset-modules/sitewise/session.ts +++ b/packages/core/src/asset-modules/sitewise/session.ts @@ -3,67 +3,51 @@ import { AssetHierarchyQuery, AssetModelQuery, AssetPropertyValueQuery, - AssetQuery, AssetSummaryQuery, HIERARCHY_ROOT_ID, HierarchyAssetSummaryList, SiteWiseAssetSessionInterface, } from './types'; -import { AssetSummary, DescribeAssetModelResponse } from '@aws-sdk/client-iotsitewise/dist-types'; +import { AssetSummary, DescribeAssetModelResponse } from '@aws-sdk/client-iotsitewise'; import { RequestProcessor } from './requestProcessor'; import { AssetPropertyValue } from '@aws-sdk/client-iotsitewise'; -type QueueEntry = { query: AssetQuery; observable: Observable }; - export class SiteWiseAssetSession implements SiteWiseAssetSessionInterface { private processor: RequestProcessor; - private requestQueue: QueueEntry[] = []; constructor(processor: RequestProcessor) { this.processor = processor; } private _requestAssetSummary(query: AssetSummaryQuery): Observable { - const observable: Observable = new Observable((observer) => { + return new Observable((observer) => { this.processor.getAssetSummary(query, observer); - this.requestQueue.push({ query: query, observable: observable }); }); - return observable; } private _requestAssetModel(query: AssetModelQuery): Observable { - const observable: Observable = new Observable( - (observer) => { - this.processor.getAssetModel(query, observer); - this.requestQueue.push({ query: query, observable: observable }); - } - ); - return observable; + return new Observable((observer) => { + this.processor.getAssetModel(query, observer); + }); } private _requestAssetPropertyValue(query: AssetPropertyValueQuery): Observable { - const observable: Observable = new Observable((observer) => { + return new Observable((observer) => { this.processor.getAssetPropertyValue(query, observer); - this.requestQueue.push({ query: query, observable: observable }); }); - return observable; } private _requestRootAssets(): Observable { - const observable: Observable = new Observable((observer) => { + return new Observable((observer) => { const query: AssetHierarchyQuery = { assetHierarchyId: HIERARCHY_ROOT_ID }; this.processor.getAssetHierarchy(query, observer); - this.requestQueue.push({ query: query, observable: observable }); }); - return observable; } private _requestAssetHierarchy(query: AssetHierarchyQuery): Observable { - const observable: Observable = new Observable((observer) => { + return new Observable((observer) => { this.processor.getAssetHierarchy(query, observer); - this.requestQueue.push({ query: query, observable: observable }); }); - return observable; } fetchAssetHierarchy(query: AssetHierarchyQuery): Promise { diff --git a/packages/core/src/asset-modules/sitewise/types.ts b/packages/core/src/asset-modules/sitewise/types.ts index 2bfe8d54f..bad0536d2 100644 --- a/packages/core/src/asset-modules/sitewise/types.ts +++ b/packages/core/src/asset-modules/sitewise/types.ts @@ -4,28 +4,20 @@ import { AssetPropertyValue, AssetSummary, DescribeAssetModelResponse } from '@aws-sdk/client-iotsitewise'; import { Subscription } from 'rxjs'; -export type AssetQuery = {}; - -export type AssetSummaryQuery = AssetQuery & { +export type AssetSummaryQuery = { assetId: string; }; -export const isAssetSummaryQuery = (query: AssetQuery): query is AssetSummaryQuery => - (query as AssetSummaryQuery).assetId != undefined && !(query as AssetPropertyValueQuery).propertyId; -export type AssetModelQuery = AssetQuery & { +export type AssetModelQuery = { assetModelId: string; }; -export const isAssetModelQuery = (query: AssetQuery): query is AssetModelQuery => - (query as AssetModelQuery).assetModelId != undefined; -export type AssetPropertyValueQuery = AssetQuery & { +export type AssetPropertyValueQuery = { assetId: string; propertyId: string; }; -export const isAssetPropertyValueQuery = (query: AssetQuery): query is AssetPropertyValueQuery => - (query as AssetPropertyValueQuery).propertyId != undefined && (query as AssetPropertyValueQuery).assetId != undefined; -export type AssetHierarchyQuery = AssetQuery & { +export type AssetHierarchyQuery = { assetId?: string; assetHierarchyId: string; }; @@ -33,8 +25,6 @@ export type AssetHierarchyQuery = AssetQuery & { export function assetHierarchyQueryKey(query: AssetHierarchyQuery): string { return (query.assetId ? query.assetId + ':' : '') + query.assetHierarchyId; } -export const isAssetHierarchyQuery = (query: AssetQuery): query is AssetHierarchyQuery => - (query as AssetHierarchyQuery).assetHierarchyId != undefined; export enum LoadingStateEnum { NOT_LOADED, diff --git a/packages/core/src/common/getDataPoints.ts b/packages/core/src/common/getDataPoints.ts index 031927ea8..0f1d78774 100644 --- a/packages/core/src/common/getDataPoints.ts +++ b/packages/core/src/common/getDataPoints.ts @@ -1,5 +1,5 @@ import { DataPoint, Primitive, Resolution } from '@synchro-charts/core'; -import { DataStream } from '../data-module/types.d'; +import { DataStream } from '../data-module/types'; /** * Get the points for a given resolution from a data stream diff --git a/packages/core/src/components.d.ts b/packages/core/src/components.d.ts old mode 100755 new mode 100644 diff --git a/packages/core/src/data-module/IotAppKitDataModule.spec.ts b/packages/core/src/data-module/IotAppKitDataModule.spec.ts index de0fa3af7..b782f24cf 100644 --- a/packages/core/src/data-module/IotAppKitDataModule.spec.ts +++ b/packages/core/src/data-module/IotAppKitDataModule.spec.ts @@ -1,6 +1,6 @@ import flushPromises from 'flush-promises'; import { DATA_STREAM, DATA_STREAM_INFO, DATA_STREAM_2 } from '../iotsitewise/__mocks__/mockWidgetProperties'; -import { DataSource, DataStreamQuery, DataStream } from './types.d'; +import { DataSource, DataStreamQuery, DataStream } from './types'; import { DataPoint } from '@synchro-charts/core'; import { TimeSeriesDataRequest, TimeSeriesDataRequestSettings } from './data-cache/requestTypes'; import { DataStreamsStore, DataStreamStore } from './data-cache/types'; diff --git a/packages/core/src/data-module/IotAppKitDataModule.ts b/packages/core/src/data-module/IotAppKitDataModule.ts index f0225d60c..22892e055 100644 --- a/packages/core/src/data-module/IotAppKitDataModule.ts +++ b/packages/core/src/data-module/IotAppKitDataModule.ts @@ -7,13 +7,11 @@ import { DataStreamQuery, RequestInformation, RequestInformationAndRange, - Subscription, SubscriptionUpdate, -} from './types.d'; -import { TimeSeriesData } from '../interface'; +} from './types'; import { DataStreamsStore, CacheSettings } from './data-cache/types'; import DataSourceStore from './data-source-store/dataSourceStore'; -import { SubscriptionResponse } from '../iotsitewise/time-series-data/types.d'; +import { SubscriptionResponse, TimeSeriesData } from '../iotsitewise/time-series-data/types'; import { DataCache } from './data-cache/dataCacheWrapped'; import { TimeSeriesDataRequest } from './data-cache/requestTypes'; import { requestRange } from './data-cache/requestRange'; diff --git a/packages/core/src/data-module/data-cache/dataActions.ts b/packages/core/src/data-module/data-cache/dataActions.ts index a4f2c462f..15d5ae4c1 100755 --- a/packages/core/src/data-module/data-cache/dataActions.ts +++ b/packages/core/src/data-module/data-cache/dataActions.ts @@ -1,6 +1,6 @@ import { Action, Dispatch } from 'redux'; import { DataStreamId, Resolution } from '@synchro-charts/core'; -import { DataStream } from '../types.d'; +import { DataStream } from '../types'; /** * diff --git a/packages/core/src/data-module/data-cache/requestTypes.ts b/packages/core/src/data-module/data-cache/requestTypes.ts index da8da475c..62ffeb668 100755 --- a/packages/core/src/data-module/data-cache/requestTypes.ts +++ b/packages/core/src/data-module/data-cache/requestTypes.ts @@ -1,5 +1,5 @@ import { DataStreamId, MinimalViewPortConfig, Resolution } from '@synchro-charts/core'; -import { DataStream } from '../types.d'; +import { DataStream } from '../types'; export type DateInterval = { start: Date; end: Date }; diff --git a/packages/core/src/data-module/data-cache/toDataStreams.ts b/packages/core/src/data-module/data-cache/toDataStreams.ts index 8c5897df7..3e509eae5 100755 --- a/packages/core/src/data-module/data-cache/toDataStreams.ts +++ b/packages/core/src/data-module/data-cache/toDataStreams.ts @@ -1,7 +1,7 @@ import { DataPoint, DataType } from '@synchro-charts/core'; import { DataStreamsStore } from './types'; import { isDefined } from '../../common/predicates'; -import { DataStream, RequestInformation } from '../types.d'; +import { DataStream, RequestInformation } from '../types'; /** * To Data Streams diff --git a/packages/core/src/data-module/data-source-store/dataSourceStore.spec.ts b/packages/core/src/data-module/data-source-store/dataSourceStore.spec.ts index 80ea35db3..02518c3ae 100644 --- a/packages/core/src/data-module/data-source-store/dataSourceStore.spec.ts +++ b/packages/core/src/data-module/data-source-store/dataSourceStore.spec.ts @@ -1,5 +1,5 @@ import DataSourceStore from './dataSourceStore'; -import { DataSource } from '../types.d'; +import { DataSource } from '../types'; it('registers a data source', () => { const dataSourceStore = new DataSourceStore(); diff --git a/packages/core/src/data-module/data-source-store/dataSourceStore.ts b/packages/core/src/data-module/data-source-store/dataSourceStore.ts index 226dfbc54..5845b91e4 100644 --- a/packages/core/src/data-module/data-source-store/dataSourceStore.ts +++ b/packages/core/src/data-module/data-source-store/dataSourceStore.ts @@ -5,7 +5,7 @@ import { DataStreamQuery, RequestInformation, RequestInformationAndRange, -} from '../types.d'; +} from '../types'; import { TimeSeriesDataRequest } from '../data-cache/requestTypes'; /** diff --git a/packages/core/src/data-module/subscription-store/subscriptionStore.spec.ts b/packages/core/src/data-module/subscription-store/subscriptionStore.spec.ts index bf0f1c993..6541dec1c 100644 --- a/packages/core/src/data-module/subscription-store/subscriptionStore.spec.ts +++ b/packages/core/src/data-module/subscription-store/subscriptionStore.spec.ts @@ -1,5 +1,5 @@ import SubscriptionStore from './subscriptionStore'; -import { Subscription } from '../types.d'; +import { Subscription } from '../types'; import { DataCache } from '../data-cache/dataCacheWrapped'; import DataSourceStore from '../data-source-store/dataSourceStore'; import { SiteWiseDataStreamQuery } from '../../iotsitewise/time-series-data/types'; @@ -39,6 +39,8 @@ it('adds subscription', () => { subscriptionStore.addSubscription('some-id', MOCK_SUBSCRIPTION); expect(subscriptionStore.getSubscriptions()).toEqual([MOCK_SUBSCRIPTION]); + + subscriptionStore.removeSubscription('some-id'); }); it('updates subscription', () => { @@ -56,6 +58,8 @@ it('updates subscription', () => { subscriptionStore.updateSubscription(SUBSCRIPTION_ID, { queries }); expect(subscriptionStore.getSubscriptions()).toEqual([{ ...MOCK_SUBSCRIPTION, queries }]); + + subscriptionStore.removeSubscription(SUBSCRIPTION_ID); }); it('removes subscription', () => { @@ -72,6 +76,7 @@ it('gets subscription by subscriptionId', () => { subscriptionStore.addSubscription('some-id', MOCK_SUBSCRIPTION); expect(subscriptionStore.getSubscription('some-id')).toEqual(MOCK_SUBSCRIPTION); + subscriptionStore.removeSubscription('some-id'); }); describe('throws errors when', () => { @@ -91,5 +96,7 @@ describe('throws errors when', () => { subscriptionStore.addSubscription(SUBSCRIPTION_ID, MOCK_SUBSCRIPTION); expect(() => subscriptionStore.addSubscription(SUBSCRIPTION_ID, MOCK_SUBSCRIPTION)).toThrowError(/some-id/); + + subscriptionStore.removeSubscription('some-id'); }); }); diff --git a/packages/core/src/data-module/subscription-store/subscriptionStore.ts b/packages/core/src/data-module/subscription-store/subscriptionStore.ts index bd2d6f3a8..ede461345 100644 --- a/packages/core/src/data-module/subscription-store/subscriptionStore.ts +++ b/packages/core/src/data-module/subscription-store/subscriptionStore.ts @@ -1,4 +1,4 @@ -import { DataStreamQuery, Subscription, SubscriptionUpdate } from '../types.d'; +import { DataStreamQuery, Subscription, SubscriptionUpdate } from '../types'; import { DataCache } from '../data-cache/dataCacheWrapped'; import { CacheSettings } from '../data-cache/types'; import DataSourceStore from '../data-source-store/dataSourceStore'; diff --git a/packages/core/src/data-module/types.d.ts b/packages/core/src/data-module/types.ts similarity index 90% rename from packages/core/src/data-module/types.d.ts rename to packages/core/src/data-module/types.ts index 798f97563..3d8fdcb3b 100644 --- a/packages/core/src/data-module/types.d.ts +++ b/packages/core/src/data-module/types.ts @@ -12,10 +12,9 @@ import { ListAssociatedAssetsCommandInput, ListAssociatedAssetsCommandOutput, } from '@aws-sdk/client-iotsitewise'; -import { RefId } from '../iotsitewise/time-series-data/types'; +import { RefId, TimeSeriesData } from '../iotsitewise/time-series-data/types'; import { CacheSettings } from './data-cache/types'; import { DataPoint, StreamAssociation } from '@synchro-charts/core/dist/types/utils/dataTypes'; -import { TimeSeriesData } from '../interface'; export type RequestInformation = { id: DataStreamId; @@ -55,13 +54,7 @@ export type DataSource = { // An identifier for the name of the source, i.e. 'site-wise', 'roci', etc.. name: DataSourceName; // this is unique initiateRequest: (request: DataSourceRequest, requestInformations: RequestInformationAndRange[]) => void; - getRequestsFromQuery: ({ - query, - requestInfo, - }: { - query: Query; - request: TimeSeriesDataRequest; - }) => RequestInformation[]; + getRequestsFromQuery: ({ query, request }: { query: Query; request: TimeSeriesDataRequest }) => RequestInformation[]; }; export type DataStreamCallback = (dataStreams: DataStream[]) => void; @@ -88,7 +81,7 @@ export type DataStreamQuery = { export type AnyDataStreamQuery = DataStreamQuery & any; -export type ErrorCallback = ({ id, resolution, error }) => void; +export type ErrorCallback = ({ id, resolution, error }: { id: string; resolution: number; error: string }) => void; export type SubscriptionUpdate = Partial, 'emit'>>; @@ -107,7 +100,7 @@ export type DataSourceRequest = { */ export type SubscribeToDataStreams = ( dataModule: DataModule, - { queries, requestInfo }: DataModuleSubscription, + { queries, request }: DataModuleSubscription, callback: (data: TimeSeriesData) => void ) => { unsubscribe: () => void; @@ -115,7 +108,7 @@ export type SubscribeToDataStreams = ( }; type SubscribeToDataStreamsPrivate = ( - { queries, requestInfo }: DataModuleSubscription, + { queries, request }: DataModuleSubscription, callback: (data: TimeSeriesData) => void ) => { unsubscribe: () => void; @@ -162,7 +155,7 @@ export type RegisterDataSource = ( * The core of the IoT App Kit, manages the data, and getting data to those who subscribe. */ export interface DataModule { - registerDataSource: RegisterDataSourcePrivate; + registerDataSource: (dataSource: DataSource) => void; subscribeToDataStreams: SubscribeToDataStreamsPrivate; } diff --git a/packages/core/src/global.d.ts b/packages/core/src/global.d.ts deleted file mode 100755 index f0a70f054..000000000 --- a/packages/core/src/global.d.ts +++ /dev/null @@ -1,790 +0,0 @@ -declare module '*.frag'; -declare module '*.vert'; - -// TODO(btd): make this live with the matchers. Currently copying over jest-extended matcher -// type declarations as I had issues getting the name space declarations to merge correctly. - -declare namespace jest { - interface Expect { - /** - * - * CUSTOM - * - */ - - /** - * Use .toBeNear date to check if a date string or a date is near another date/date string - * - * @param {String | Date} date - date to be tested against to see if the dates are near - * @param {number} [withinMS] - millisecond threshold which the dates are considered as near - */ - toBeNearDate(date: Date | string, withinMS: number): Matchers; - - /** - * Use .toBeValidSvgRect to ensure the attributes of a `rect` are all valid - * - * @param {SVGGElement} el - */ - toBeValidSvgRect(): Matchers; - - /** - * Use .toNotOverlap to check if two elements overlap each other or not. - * - * @param {BoundingBox} el1 - * @param {BoundingBox} el2 - */ - - toNotOverlap(el2: any): Matchers; - - /** - * - * jest-expected - * - */ - - /** - * Note: Currently unimplemented - * Passing assertion - * - * @param {String} message - */ - pass(message: string): any; - - /** - * Note: Currently unimplemented - * Failing assertion - * - * @param {String} message - */ - fail(message: string): any; - - /** - * Use .toBeEmpty when checking if a String '', Array [] or Object {} is empty. - */ - toBeEmpty(): any; - - /** - * Use .toBeOneOf when checking if a value is a member of a given Array. - * @param {Array.<*>} members - */ - toBeOneOf(members: any[]): any; - - /** - * Use `.toBeNil` when checking a value is `null` or `undefined`. - */ - toBeNil(): any; - - /** - * Use `.toSatisfy` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean`. - * @param {Function} predicate - */ - toSatisfy(predicate: (x: any) => boolean): any; - - /** - * Use `.toBeArray` when checking if a value is an `Array`. - */ - toBeArray(): any; - - /** - * Use `.toBeArrayOfSize` when checking if a value is an `Array` of size x. - * @param {Number} x - */ - toBeArrayOfSize(x: number): any; - - /** - * Use `.toBeAfter` when checking if a date occurs after `date`. - * @param {Date} date - */ - toBeAfter(date: Date): any; - - /** - * Use `.toBeBefore` when checking if a date occurs before `date`. - * @param {Date} date - */ - toBeBefore(date: Date): any; - - /** - * Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set. - * @param {Array.<*>} members - */ - toIncludeAllMembers(members: any[]): any; - - /** - * Use `.toIncludeAnyMembers` when checking if an `Array` contains any of the members of a given set. - * @param {Array.<*>} members - */ - toIncludeAnyMembers(members: any[]): any; - - /** - * Use `.toIncludeSameMembers` when checking if two arrays contain equal values, in any order. - * @param {Array.<*>} members - */ - toIncludeSameMembers(members: any[]): any; - - /** - * Use `.toSatisfyAll` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean` for all values in an array. - * @param {Function} predicate - */ - toSatisfyAll(predicate: (x: any) => boolean): any; - - /** - * Use `.toBeBoolean` when checking if a value is a `Boolean`. - */ - toBeBoolean(): any; - - /** - * Use `.toBeTrue` when checking a value is equal (===) to `true`. - */ - toBeTrue(): any; - - /** - * Use `.toBeFalse` when checking a value is equal (===) to `false`. - */ - toBeFalse(): any; - - /** - * Use `.toBeDate` when checking if a value is a `Date`. - */ - toBeDate(): any; - - /** - * Use `.toBeValidDate` when checking if a value is a `valid Date`. - */ - toBeValidDate(): any; - - /** - * Use `.toBeFunction` when checking if a value is a `Function`. - */ - toBeFunction(): any; - - /** - * Use `.toBeHexadecimal` when checking if a value is a valid HTML hex color. - * - * @param {String} string - */ - toBeHexadecimal(string: string): any; - - /** - * Use `.toHaveBeenCalledBefore` when checking if a `Mock` was called before another `Mock`. - * - * Note: Required Jest version >=23 - * - * @param {Mock} mock - */ - toHaveBeenCalledBefore(mock: jest.Mock): any; - - /** - * Use `.toHaveBeenCalledAfter` when checking if a `Mock` was called after another `Mock`. - * - * Note: Required Jest version >=23 - * - * @param {Mock} mock - */ - toHaveBeenCalledAfter(mock: jest.Mock): any; - - /** - * Use `.toBeNumber` when checking if a value is a `Number`. - */ - toBeNumber(): any; - - /** - * Use `.toBeNaN` when checking a value is `NaN`. - */ - toBeNaN(): any; - - /** - * Use `.toBeFinite` when checking if a value is a `Number`, not `NaN` or `Infinity`. - */ - toBeFinite(): any; - - /** - * Use `.toBePositive` when checking if a value is a positive `Number`. - */ - toBePositive(): any; - - /** - * Use `.toBeNegative` when checking if a value is a negative `Number`. - */ - toBeNegative(): any; - - /** - * Use `.toBeEven` when checking if a value is an even `Number`. - */ - toBeEven(): any; - - /** - * Use `.toBeOdd` when checking if a value is an odd `Number`. - */ - toBeOdd(): any; - - /** - * Use `.toBeWithin` when checking if a number is in between the given bounds of: start (inclusive) and end (exclusive). - * - * @param {Number} start - * @param {Number} end - */ - toBeWithin(start: number, end: number): any; - - /** - * Use `.toBeObject` when checking if a value is an `Object`. - */ - toBeObject(): any; - - /** - * Use `.toContainKey` when checking if an object contains the provided key. - * - * @param {String} key - */ - toContainKey(key: string): any; - - /** - * Use `.toContainKeys` when checking if an object has all of the provided keys. - * - * @param {Array.} keys - */ - toContainKeys(keys: string[]): any; - - /** - * Use `.toContainAllKeys` when checking if an object only contains all of the provided keys. - * - * @param {Array.} keys - */ - toContainAllKeys(keys: string[]): any; - - /** - * Use `.toContainAnyKeys` when checking if an object contains at least one of the provided keys. - * - * @param {Array.} keys - */ - toContainAnyKeys(keys: string[]): any; - - /** - * Use `.toContainValue` when checking if an object contains the provided value. - * - * @param {*} value - */ - toContainValue(value: any): any; - - /** - * Use `.toContainValues` when checking if an object contains all of the provided values. - * - * @param {Array.<*>} values - */ - toContainValues(values: any[]): any; - - /** - * Use `.toContainAllValues` when checking if an object only contains all of the provided values. - * - * @param {Array.<*>} values - */ - toContainAllValues(values: any[]): any; - - /** - * Use `.toContainAnyValues` when checking if an object contains at least one of the provided values. - * - * @param {Array.<*>} values - */ - toContainAnyValues(values: any[]): any; - - /** - * Use `.toContainEntry` when checking if an object contains the provided entry. - * - * @param {Array.<[keyof T, T[keyof T]>} entry - */ - toContainEntry(entry: [keyof T, T[keyof T]]): any; - - /** - * Use `.toContainEntries` when checking if an object contains all of the provided entries. - * - * @param {Array.>} entries - */ - toContainEntries(entries: [keyof T, T[keyof T]][]): any; - - /** - * Use `.toContainAllEntries` when checking if an object only contains all of the provided entries. - * - * @param {Array.>} entries - */ - toContainAllEntries(entries: [keyof T, T[keyof T]][]): any; - - /** - * Use `.toContainAnyEntries` when checking if an object contains at least one of the provided entries. - * - * @param {Array.>} entries - */ - toContainAnyEntries(entries: [keyof T, T[keyof T]][]): any; - - /** - * Use `.toBeExtensible` when checking if an object is extensible. - */ - toBeExtensible(): any; - - /** - * Use `.toBeFrozen` when checking if an object is frozen. - */ - toBeFrozen(): any; - - /** - * Use `.toBeSealed` when checking if an object is sealed. - */ - toBeSealed(): any; - - /** - * Use `.toResolve` when checking if a promise resolves. - */ - toResolve(): any; - - /** - * Use `.toReject` when checking if a promise rejects. - */ - toReject(): any; - - /** - * Use `.toBeString` when checking if a value is a `String`. - */ - toBeString(): any; - - /** - * Use `.toEqualCaseInsensitive` when checking if a string is equal (===) to another ignoring the casing of both strings. - * - * @param {String} string - */ - toEqualCaseInsensitive(string: string): any; - - /** - * Use `.toStartWith` when checking if a `String` starts with a given `String` prefix. - * - * @param {String} prefix - */ - toStartWith(prefix: string): any; - - /** - * Use `.toEndWith` when checking if a `String` ends with a given `String` suffix. - * - * @param {String} suffix - */ - toEndWith(suffix: string): any; - - /** - * Use `.toInclude` when checking if a `String` includes the given `String` substring. - * - * @param {String} substring - */ - toInclude(substring: string): any; - - /** - * Use `.toIncludeRepeated` when checking if a `String` includes the given `String` substring the correct number of times. - * - * @param {String} substring - * @param {Number} times - */ - toIncludeRepeated(substring: string, times: number): any; - - /** - * Use `.toIncludeMultiple` when checking if a `String` includes all of the given substrings. - * - * @param {Array.} substring - */ - toIncludeMultiple(substring: string[]): any; - - /** - * Use `.toThrowWithMessage` when checking if a callback function throws an error of a given type with a given error message. - * - * @param {Function} type - * @param {String | RegExp} message - */ - toThrowWithMessage(type: Function, message: string | RegExp): any; - } - - // @ts-ignore - interface Matchers { - /** - * - * CUSTOM - * - */ - - /** - * Use .toBeNear date to check if a date string or a date is near another date/date string - * - * @param {String | Date} date - date to be tested against to see if the dates are near - * @param {number} [withinMS] - millisecond threshold which the dates are considered as near - */ - toBeNearDate(date: Date | string, withinMS?: number): R; - - /** - * Use .toBeValidSvgRect to ensure the attributes of a `rect` are all valid - * - * @param {SVGGElement} el - */ - toBeValidSvgRect(): Matchers; - - /** - * Use .toNotOverlap to check if two elements overlap each other or not. - * - * @param {BoundingBox} el1 - * @param {BoundingBox} el2 - */ - - toNotOverlap(el2: any): R; - - /** - * - * jest-expected - * - */ - - /** - * Note: Currently unimplemented - * Passing assertion - * - * @param {String} message - */ - pass(message: string): R; - - /** - * Note: Currently unimplemented - * Failing assertion - * - * @param {String} message - */ - fail(message: string): R; - - /** - * Use .toBeEmpty when checking if a String '', Array [], Object {} or Iterable (i.e. Map, Set) is empty. - */ - toBeEmpty(): R; - - /** - * Use .toBeOneOf when checking if a value is a member of a given Array. - * @param {Array.<*>} members - */ - toBeOneOf(members: any[]): R; - - /** - * Use `.toBeNil` when checking a value is `null` or `undefined`. - */ - toBeNil(): R; - - /** - * Use `.toSatisfy` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean`. - * @param {Function} predicate - */ - toSatisfy(predicate: (x: any) => boolean): R; - - /** - * Use `.toBeArray` when checking if a value is an `Array`. - */ - toBeArray(): R; - - /** - * Use `.toBeArrayOfSize` when checking if a value is an `Array` of size x. - * @param {Number} x - */ - toBeArrayOfSize(x: number): R; - - /** - * Use `.toBeAfter` when checking if a date occurs after `date`. - * @param {Date} date - */ - toBeAfter(date: Date): R; - - /** - * Use `.toBeBefore` when checking if a date occurs before `date`. - * @param {Date} date - */ - toBeBefore(date: Date): R; - - /** - * Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set. - * @param {Array.<*>} members - */ - toIncludeAllMembers(members: any[]): R; - - /** - * Use `.toIncludeAnyMembers` when checking if an `Array` contains any of the members of a given set. - * @param {Array.<*>} members - */ - toIncludeAnyMembers(members: any[]): R; - - /** - * Use `.toIncludeSameMembers` when checking if two arrays contain equal values, in any order. - * @param {Array.<*>} members - */ - toIncludeSameMembers(members: any[]): R; - - /** - * Use `.toSatisfyAll` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean` for all values in an array. - * @param {Function} predicate - */ - toSatisfyAll(predicate: (x: any) => boolean): R; - - /** - * Use `.toBeBoolean` when checking if a value is a `Boolean`. - */ - toBeBoolean(): R; - - /** - * Use `.toBeTrue` when checking a value is equal (===) to `true`. - */ - toBeTrue(): R; - - /** - * Use `.toBeFalse` when checking a value is equal (===) to `false`. - */ - toBeFalse(): R; - - /** - * Use `.toBeDate` when checking if a value is a `Date`. - */ - toBeDate(): R; - - /** - * Use `.toBeValidDate` when checking if a value is a `valid Date`. - */ - toBeValidDate(): R; - - /** - * Use `.toBeFunction` when checking if a value is a `Function`. - */ - toBeFunction(): R; - - /** - * Use `.toBeHexadecimal` when checking if a value is a valid HTML hex color. - * - * @param {String} string - */ - toBeHexadecimal(string: string): R; - - /** - * Use `.toHaveBeenCalledBefore` when checking if a `Mock` was called before another `Mock`. - * - * Note: Required Jest version >=23 - * - * @param {Mock} mock - */ - toHaveBeenCalledBefore(mock: jest.Mock): R; - - /** - * Use `.toHaveBeenCalledAfter` when checking if a `Mock` was called after another `Mock`. - * - * Note: Required Jest version >=23 - * - * @param {Mock} mock - */ - toHaveBeenCalledAfter(mock: jest.Mock): R; - - /** - * Use `.toBeNumber` when checking if a value is a `Number`. - */ - toBeNumber(): R; - - /** - * Use `.toBeNaN` when checking a value is `NaN`. - */ - toBeNaN(): R; - - /** - * Use `.toBeFinite` when checking if a value is a `Number`, not `NaN` or `Infinity`. - */ - toBeFinite(): R; - - /** - * Use `.toBePositive` when checking if a value is a positive `Number`. - */ - toBePositive(): R; - - /** - * Use `.toBeNegative` when checking if a value is a negative `Number`. - */ - toBeNegative(): R; - - /** - * Use `.toBeEven` when checking if a value is an even `Number`. - */ - toBeEven(): R; - - /** - * Use `.toBeOdd` when checking if a value is an odd `Number`. - */ - toBeOdd(): R; - - /** - * Use `.toBeWithin` when checking if a number is in between the given bounds of: start (inclusive) and end (exclusive). - * - * @param {Number} start - * @param {Number} end - */ - toBeWithin(start: number, end: number): R; - - /** - * Use `.toBeObject` when checking if a value is an `Object`. - */ - toBeObject(): R; - - /** - * Use `.toContainKey` when checking if an object contains the provided key. - * - * @param {String} key - */ - toContainKey(key: string): R; - - /** - * Use `.toContainKeys` when checking if an object has all of the provided keys. - * - * @param {Array.} keys - */ - toContainKeys(keys: string[]): R; - - /** - * Use `.toContainAllKeys` when checking if an object only contains all of the provided keys. - * - * @param {Array.} keys - */ - toContainAllKeys(keys: string[]): R; - - /** - * Use `.toContainAnyKeys` when checking if an object contains at least one of the provided keys. - * - * @param {Array.} keys - */ - toContainAnyKeys(keys: string[]): R; - - /** - * Use `.toContainValue` when checking if an object contains the provided value. - * - * @param {*} value - */ - toContainValue(value: any): R; - - /** - * Use `.toContainValues` when checking if an object contains all of the provided values. - * - * @param {Array.<*>} values - */ - toContainValues(values: any[]): R; - - /** - * Use `.toContainAllValues` when checking if an object only contains all of the provided values. - * - * @param {Array.<*>} values - */ - toContainAllValues(values: any[]): R; - - /** - * Use `.toContainAnyValues` when checking if an object contains at least one of the provided values. - * - * @param {Array.<*>} values - */ - toContainAnyValues(values: any[]): R; - - /** - * Use `.toContainEntry` when checking if an object contains the provided entry. - * - * @param {Array.} entry - */ - toContainEntry(entry: [keyof T, T[keyof T]]): R; - - /** - * Use `.toContainEntries` when checking if an object contains all of the provided entries. - * - * @param {Array.>} entries - */ - toContainEntries(entries: [keyof T, T[keyof T]][]): R; - - /** - * Use `.toContainAllEntries` when checking if an object only contains all of the provided entries. - * - * @param {Array.>} entries - */ - toContainAllEntries(entries: [keyof T, T[keyof T]][]): R; - - /** - * Use `.toContainAnyEntries` when checking if an object contains at least one of the provided entries. - * - * @param {Array.>} entries - */ - toContainAnyEntries(entries: [keyof T, T[keyof T]][]): R; - - /** - * Use `.toBeExtensible` when checking if an object is extensible. - */ - toBeExtensible(): R; - - /** - * Use `.toBeFrozen` when checking if an object is frozen. - */ - toBeFrozen(): R; - - /** - * Use `.toBeSealed` when checking if an object is sealed. - */ - toBeSealed(): R; - - /** - * Use `.toResolve` when checking if a promise resolves. - */ - toResolve(): R; - - /** - * Use `.toReject` when checking if a promise rejects. - */ - toReject(): R; - - /** - * Use `.toBeString` when checking if a value is a `String`. - */ - toBeString(): R; - - /** - * Use `.toEqualCaseInsensitive` when checking if a string is equal (===) to another ignoring the casing of both strings. - * - * @param {String} string - */ - toEqualCaseInsensitive(string: string): R; - - /** - * Use `.toStartWith` when checking if a `String` starts with a given `String` prefix. - * - * @param {String} prefix - */ - toStartWith(prefix: string): R; - - /** - * Use `.toEndWith` when checking if a `String` ends with a given `String` suffix. - * - * @param {String} suffix - */ - toEndWith(suffix: string): R; - - /** - * Use `.toInclude` when checking if a `String` includes the given `String` substring. - * - * @param {String} substring - */ - toInclude(substring: string): R; - - /** - * Use `.toIncludeRepeated` when checking if a `String` includes the given `String` substring the correct number of times. - * - * @param {String} substring - * @param {Number} times - */ - toIncludeRepeated(substring: string, times: number): R; - - /** - * Use `.toIncludeMultiple` when checking if a `String` includes all of the given substrings. - * - * @param {Array.} substring - */ - toIncludeMultiple(substring: string[]): R; - - /** - * Use `.toThrowWithMessage` when checking if a callback function throws an error of a given type with a given error message. - * - * @param {Function} type - * @param {String | RegExp} message - */ - toThrowWithMessage(type: Function, message: string | RegExp): R; - } -} diff --git a/packages/core/src/index.html b/packages/core/src/index.html deleted file mode 100755 index 2878dda7b..000000000 --- a/packages/core/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - IoT Application Kit - - - - - - diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index bb742ce2b..f63b2434b 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,3 +1,11 @@ +import { IoTSiteWiseClient } from '@aws-sdk/client-iotsitewise/dist-types/IoTSiteWiseClient'; +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, SiteWiseAssetTreeCallback, 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'; @@ -5,3 +13,45 @@ export * from './module-namespace'; export * from './query-namespace'; export * from './iotsitewise/time-series-data/provider'; export * from './testing'; // @todo: build as a separate bundle +export * from './data-module/types'; +export * from './iotsitewise/time-series-data/types'; + +export type IoTAppKitInitInputs = + | { + registerDataSources?: boolean; + iotSiteWiseClient: IoTSiteWiseClient; + } + | { + registerDataSources?: boolean; + awsCredentials: Credentials | AWSCredentialsProvider; + awsRegion: string; + }; + +export interface IoTAppKit { + session: (componentId: string) => IoTAppKitComponentSession; + registerTimeSeriesDataSource: (dataSource: DataSource) => void; + /** @todo: create asset provider */ + subscribeToAssetTree: (query: SiteWiseAssetTreeQuery, callback: SiteWiseAssetTreeCallback) => AssetTreeSubscription; +} + +export interface Closeable { + close(): void; +} + +export interface DataModuleSession extends Closeable {} + +export interface IoTAppKitComponentSession extends Closeable { + componentId: string; + attachDataModuleSession(session: DataModuleSession): void; +} + +export interface Query { + build(session: IoTAppKitComponentSession, params?: Params): Provider; +} + +export interface TimeSeriesQuery extends Query {} + +export interface Provider { + subscribe(callback: (data: DataType) => void): void; + unsubscribe(): void; +} diff --git a/packages/core/src/interface.d.ts b/packages/core/src/interface.d.ts deleted file mode 100755 index 814292f86..000000000 --- a/packages/core/src/interface.d.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { - DataModule, - DataModuleSubscription, - DataSource, - DataStreamCallback, - DataStreamQuery, - SubscriptionUpdate, -} from './data-module/types'; -import { IoTSiteWiseClient } from '@aws-sdk/client-iotsitewise/dist-types/IoTSiteWiseClient'; -import { Credentials, Provider } from '@aws-sdk/types'; -import { SiteWiseDataStreamQuery } from './iotsitewise/time-series-data/types'; -import { IotAppKitDataModule } from './data-module/IotAppKitDataModule'; -import { SiteWiseAssetModule } from './asset-modules'; -import { TimeSeriesData, TimeSeriesDataRequest } from './interface'; - -export * from './components.d'; -export * from './data-module/types.d'; -export * from './data-sources'; -export * from './index'; -export * from './data-module/data-cache/requestTypes'; -export * from './iotsitewise/time-series-data/types.d'; - -export type IoTAppKitInitInputs = - | { - registerDataSources?: boolean; - iotSiteWiseClient: IoTSiteWiseClient; - } - | { - registerDataSources?: boolean; - awsCredentials: Credentials | Provider; - awsRegion: string; - }; - -export interface IoTAppKit { - session: (componentId: string) => IoTAppKitComponentSession; - registerTimeSeriesDataSource: (dataSource: DataSource) => void; - /** @todo: create asset provider */ - subscribeToAssetTree: (query: SiteWiseAssetTreeQuery, callback: SiteWiseAssetTreeCallback) => AssetTreeSubscription; -} - -export interface Closeable { - close(): void; -} - -export interface DataModuleSession extends Closeable {} - -export interface IoTAppKitComponentSession extends Closeable { - componentId: string; - attachDataModuleSession(session: DataModuleSession): void; -} - -export interface Query { - build(session: IoTAppKitComponentSession, params: Params): Provider; -} - -export interface TimeSeriesQuery extends Query {} - -export interface Provider { - subscribe(callback: (data: DataType) => void): void; - unsubscribe(): void; -} diff --git a/packages/core/src/iotAppKit.ts b/packages/core/src/iotAppKit.ts index 20409b545..8c47d8c1b 100644 --- a/packages/core/src/iotAppKit.ts +++ b/packages/core/src/iotAppKit.ts @@ -3,7 +3,7 @@ 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, IoTAppKitComponentSession } from './interface.d'; +import { IoTAppKitInitInputs, IoTAppKitComponentSession } from './index'; import { createDataSource } from './iotsitewise/time-series-data'; import { subscribeToAssetTree } from './asset-modules/coordinator'; import { SiteWiseComponentSession } from './iotsitewise/component-session'; diff --git a/packages/core/src/iotsitewise/__mocks__/data-source.ts b/packages/core/src/iotsitewise/__mocks__/data-source.ts index 0d39bb8b9..fe570a98b 100644 --- a/packages/core/src/iotsitewise/__mocks__/data-source.ts +++ b/packages/core/src/iotsitewise/__mocks__/data-source.ts @@ -1,5 +1,5 @@ import { DataSource, DataSourceRequest, DataStream } from '../../data-module/types'; -import { SiteWiseDataStreamQuery } from '../../iotsitewise/time-series-data/types'; +import { SiteWiseDataStreamQuery } from '../time-series-data/types'; import { SITEWISE_DATA_SOURCE } from '../../iotsitewise/time-series-data'; import { toDataStreamId } from '../../iotsitewise/time-series-data/util/dataStreamId'; diff --git a/packages/core/src/iotsitewise/component-session.ts b/packages/core/src/iotsitewise/component-session.ts index aed9b13b2..c5ba1693b 100644 --- a/packages/core/src/iotsitewise/component-session.ts +++ b/packages/core/src/iotsitewise/component-session.ts @@ -1,6 +1,6 @@ import { SiteWiseAssetModule } from '..'; import { IotAppKitDataModule } from '../data-module/IotAppKitDataModule'; -import { IoTAppKitComponentSession, DataModuleSession } from '../interface.d'; +import { IoTAppKitComponentSession, DataModuleSession } from '../index'; /** * Component session to manage component data module sessions. diff --git a/packages/core/src/iotsitewise/time-series-data/client/getAggregatedPropertyDataPoints.ts b/packages/core/src/iotsitewise/time-series-data/client/getAggregatedPropertyDataPoints.ts index 6d7265a3d..63a24d83e 100644 --- a/packages/core/src/iotsitewise/time-series-data/client/getAggregatedPropertyDataPoints.ts +++ b/packages/core/src/iotsitewise/time-series-data/client/getAggregatedPropertyDataPoints.ts @@ -11,6 +11,7 @@ import { DataStreamCallback, ErrorCallback, RequestInformationAndRange } from '. import { isDefined } from '../../../common/predicates'; import { RESOLUTION_TO_MS_MAPPING } from '../util/resolution'; import { toDataStreamId } from '../util/dataStreamId'; +import { parseDuration } from '../../../common/time'; const getAggregatedPropertyDataPointsForProperty = ({ assetId, @@ -86,7 +87,7 @@ const getAggregatedPropertyDataPointsForProperty = ({ }) .catch((err) => { const id = toDataStreamId({ assetId, propertyId }); - onError({ id, resolution, error: err.message }); + onError({ id, resolution: parseDuration(resolution), error: err.message }); }); }; diff --git a/packages/core/src/iotsitewise/time-series-data/client/getHistoricalPropertyDataPoints.ts b/packages/core/src/iotsitewise/time-series-data/client/getHistoricalPropertyDataPoints.ts index ad228c923..7f3ad3417 100644 --- a/packages/core/src/iotsitewise/time-series-data/client/getHistoricalPropertyDataPoints.ts +++ b/packages/core/src/iotsitewise/time-series-data/client/getHistoricalPropertyDataPoints.ts @@ -39,28 +39,31 @@ const getHistoricalPropertyDataPointsForProperty = ({ nextToken: prevToken, }) ) - .then(({ assetPropertyValueHistory, nextToken }) => { - if (assetPropertyValueHistory) { - /** Report the page of data to the data-module */ - const dataPoints = assetPropertyValueHistory - .map((assetPropertyValue) => toDataPoint(assetPropertyValue)) - .filter(isDefined); + .then((response) => { + if (response) { + const { assetPropertyValueHistory, nextToken } = response; + if (assetPropertyValueHistory) { + /** Report the page of data to the data-module */ + const dataPoints = assetPropertyValueHistory + .map((assetPropertyValue) => toDataPoint(assetPropertyValue)) + .filter(isDefined); - onSuccess([dataStreamFromSiteWise({ assetId, propertyId, dataPoints })]); - } + onSuccess([dataStreamFromSiteWise({ assetId, propertyId, dataPoints })]); + } - if (nextToken) { - getHistoricalPropertyDataPointsForProperty({ - assetId, - propertyId, - start, - end, - maxResults, - onError, - onSuccess, - nextToken, - client, - }); + if (nextToken) { + getHistoricalPropertyDataPointsForProperty({ + assetId, + propertyId, + start, + end, + maxResults, + onError, + onSuccess, + nextToken, + client, + }); + } } }) .catch((err) => { diff --git a/packages/core/src/iotsitewise/time-series-data/data-source.spec.ts b/packages/core/src/iotsitewise/time-series-data/data-source.spec.ts index c0538ffd4..1d84af10c 100644 --- a/packages/core/src/iotsitewise/time-series-data/data-source.spec.ts +++ b/packages/core/src/iotsitewise/time-series-data/data-source.spec.ts @@ -15,7 +15,7 @@ import { TimeSeriesDataRequest } from '../../data-module/data-cache/requestTypes import Mock = jest.Mock; it('initializes', () => { - expect(() => createDataSource(new IoTSiteWiseClient({ region: 'us-east' }))).not.toThrowError(); + expect(() => createDataSource(createMockSiteWiseSDK())).not.toThrowError(); }); const noop = () => {}; @@ -397,7 +397,7 @@ describe('e2e through data-module', () => { const assetId = 'asset-id'; const propertyId = 'property-id'; - dataModule.subscribeToDataStreams( + const { unsubscribe } = dataModule.subscribeToDataStreams( { queries: [ { @@ -425,6 +425,8 @@ describe('e2e through data-module', () => { ], }) ); + + unsubscribe(); }); }); @@ -444,7 +446,7 @@ describe('e2e through data-module', () => { const assetId = 'asset-id'; const propertyId = 'property-id'; - dataModule.subscribeToDataStreams( + const { unsubscribe } = dataModule.subscribeToDataStreams( { queries: [ { @@ -475,6 +477,8 @@ describe('e2e through data-module', () => { ], }) ); + + unsubscribe(); }); }); }); @@ -898,7 +902,7 @@ it('only fetches uncached data for multiple properties', async () => { const END_2 = new Date(END_1.getTime() + MONTH_IN_MS); const dataStreamCallback = jest.fn(); - const { update } = dataModule.subscribeToDataStreams( + const { update, unsubscribe } = dataModule.subscribeToDataStreams( { queries: [query], request: { viewport: { start: START_1, end: END_1 }, settings: { fetchFromStartToEnd: true } }, @@ -966,6 +970,8 @@ it('only fetches uncached data for multiple properties', async () => { propertyId: updatedQuery.assets[0].properties[1].propertyId, }) ); + + unsubscribe(); }); it('requests buffered data', async () => { @@ -995,7 +1001,7 @@ it('requests buffered data', async () => { const BUFFERED_END = new Date(2000, 3, 6, 5, 46, 40); const dataStreamCallback = jest.fn(); - dataModule.subscribeToDataStreams( + const { unsubscribe } = dataModule.subscribeToDataStreams( { queries: [query], request: { viewport: { start: START, end: END }, settings: { fetchFromStartToEnd: true, requestBuffer: 1 } }, @@ -1015,4 +1021,6 @@ it('requests buffered data', async () => { propertyId: query.assets[0].properties[0].propertyId, }) ); + + unsubscribe(); }); 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 1442fb653..3ebd83bfc 100644 --- a/packages/core/src/iotsitewise/time-series-data/provider.spec.ts +++ b/packages/core/src/iotsitewise/time-series-data/provider.spec.ts @@ -6,9 +6,9 @@ import { DESCRIBE_ASSET_RESPONSE } from '../__mocks__/asset'; import { SiteWiseComponentSession } from '../component-session'; import { DATA_STREAM } from '../__mocks__/mockWidgetProperties'; import { SiteWiseDataStreamQuery } from './types'; -import { DataSource, DataStream } from '../../interface'; import { MINUTE_IN_MS } from '../../common/time'; import { createMockSiteWiseSDK } from '../__mocks__/iotsitewiseSDK'; +import { DataSource, DataStream } from '../../data-module/types'; const createMockSource = (dataStreams: DataStream[]): DataSource => ({ name: 'site-wise', diff --git a/packages/core/src/iotsitewise/time-series-data/provider.ts b/packages/core/src/iotsitewise/time-series-data/provider.ts index eca0a51b8..4bd48f5e8 100644 --- a/packages/core/src/iotsitewise/time-series-data/provider.ts +++ b/packages/core/src/iotsitewise/time-series-data/provider.ts @@ -1,6 +1,5 @@ -import { Provider, IoTAppKitComponentSession } from '../../interface'; import { AnyDataStreamQuery, DataModuleSubscription, SubscriptionUpdate } from '../../data-module/types'; -import { datamodule } from '../..'; +import { datamodule, IoTAppKitComponentSession, Provider } from '../..'; import { subscribeToTimeSeriesData } from './subscribeToTimeSeriesData'; import { TimeSeriesData } from './types'; import { MinimalViewPortConfig } from '@synchro-charts/core'; diff --git a/packages/core/src/iotsitewise/time-series-data/subscribeToTimeSeriesData.spec.ts b/packages/core/src/iotsitewise/time-series-data/subscribeToTimeSeriesData.spec.ts index edb134c80..f129fc490 100644 --- a/packages/core/src/iotsitewise/time-series-data/subscribeToTimeSeriesData.spec.ts +++ b/packages/core/src/iotsitewise/time-series-data/subscribeToTimeSeriesData.spec.ts @@ -24,11 +24,12 @@ const initializeSubscribeToTimeSeriesData = (client: IoTSiteWiseClient) => { it('does not emit any data streams when empty query is subscribed to', async () => { const subscribe = initializeSubscribeToTimeSeriesData(createMockSiteWiseSDK()); const cb = jest.fn(); - subscribe({ queries: [], request: { viewport: { duration: '5m' } } }, cb); + const { unsubscribe } = subscribe({ queries: [], request: { viewport: { duration: '5m' } } }, cb); await flushPromises(); expect(cb).not.toBeCalled(); + unsubscribe(); }); it('unsubscribes', () => { @@ -81,7 +82,7 @@ it('provides time series data from iotsitewise', async () => { ); const cb = jest.fn(); - subscribe( + const { unsubscribe } = subscribe( { queries: [ { @@ -135,6 +136,8 @@ it('provides time series data from iotsitewise', async () => { ], }) ); + + unsubscribe(); }); it('provides timeseries data from iotsitewise when subscription is updated', async () => { @@ -168,7 +171,7 @@ it('provides timeseries data from iotsitewise when subscription is updated', asy ); const cb = jest.fn(); - const { update } = subscribe( + const { update, unsubscribe } = subscribe( { queries: [], request: { viewport: { duration: '5m' } }, @@ -228,4 +231,6 @@ it('provides timeseries data from iotsitewise when subscription is updated', asy ], }) ); + + unsubscribe(); }); diff --git a/packages/core/src/iotsitewise/time-series-data/subscribeToTimeSeriesData.ts b/packages/core/src/iotsitewise/time-series-data/subscribeToTimeSeriesData.ts index 8bbfdfd80..ecd192894 100644 --- a/packages/core/src/iotsitewise/time-series-data/subscribeToTimeSeriesData.ts +++ b/packages/core/src/iotsitewise/time-series-data/subscribeToTimeSeriesData.ts @@ -1,15 +1,9 @@ -import { - DataModule, - DataModuleSubscription, - DataStream, - SiteWiseAssetSession, - SiteWiseDataStreamQuery, - SubscriptionUpdate, -} from '../../interface'; import { DescribeAssetModelResponse } from '@aws-sdk/client-iotsitewise'; import { completeDataStreams } from '../../completeDataStreams'; -import { TimeSeriesData } from './types'; +import { SiteWiseDataStreamQuery, TimeSeriesData } from './types'; import { MinimalViewPortConfig } from '@synchro-charts/core'; +import { SiteWiseAssetSession } from '../../asset-modules'; +import { DataModule, DataModuleSubscription, DataStream, SubscriptionUpdate } from '../../data-module/types'; export const subscribeToTimeSeriesData = (dataModule: DataModule, assetModuleSession: SiteWiseAssetSession) => diff --git a/packages/core/src/iotsitewise/time-series-data/types.d.ts b/packages/core/src/iotsitewise/time-series-data/types.ts similarity index 76% rename from packages/core/src/iotsitewise/time-series-data/types.d.ts rename to packages/core/src/iotsitewise/time-series-data/types.ts index b15ec73f8..26ffd5a53 100644 --- a/packages/core/src/iotsitewise/time-series-data/types.d.ts +++ b/packages/core/src/iotsitewise/time-series-data/types.ts @@ -1,7 +1,6 @@ import { MinimalViewPortConfig } from '@synchro-charts/core'; import { CacheSettings } from '../../data-module/data-cache/types'; -import { DataStreamQuery, SubscriptionUpdate } from '../../data-module/types'; -import { DataStream } from '../../interface'; +import { DataStream, DataStreamQuery, SubscriptionUpdate } from '../../data-module/types'; /** * Learn more about AWS IoT SiteWise assets at https://docs.aws.amazon.com/iot-sitewise/latest/userguide/industrial-asset-models.html @@ -28,18 +27,10 @@ export type AssetQuery = { properties: PropertyQuery[]; }; -type SiteWiseAssetDataStreamQuery = DataStreamQuery & { +export type SiteWiseAssetDataStreamQuery = DataStreamQuery & { assets: AssetQuery[]; }; -// TODO: Make the data stream query support property aliases for unmodeled data support -type SiteWisePropertyAliasDataStreamQuery = DataStreamQuery & { - propertyAliases: { - propertyAlias: PropertyAlias; - refId: RefId; - }; -}; - // Unused currently, this is what we want to work towards. export type SiteWiseDataStreamQuery = SiteWiseAssetDataStreamQuery; diff --git a/packages/core/src/module-namespace.ts b/packages/core/src/module-namespace.ts index 24a511c6e..b9aa08b74 100644 --- a/packages/core/src/module-namespace.ts +++ b/packages/core/src/module-namespace.ts @@ -1,4 +1,4 @@ -import { IoTAppKitComponentSession } from './interface'; +import { IoTAppKitComponentSession } 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 c726cb264..89e0ff4f0 100644 --- a/packages/core/src/query-namespace.ts +++ b/packages/core/src/query-namespace.ts @@ -1,6 +1,6 @@ -import { IoTAppKitComponentSession, TimeSeriesDataRequest, TimeSeriesQuery } from './interface'; import { AnyDataStreamQuery } from './data-module/types'; import { SiteWiseTimeSeriesDataProvider } from './iotsitewise/time-series-data/provider'; +import { IoTAppKitComponentSession, TimeSeriesDataRequest, TimeSeriesQuery } from './index'; /** * Extensible query namespace exposing methods that return Query implementations diff --git a/packages/core/stencil.config.ts b/packages/core/stencil.config.ts deleted file mode 100755 index cdd746b7e..000000000 --- a/packages/core/stencil.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Config } from '@stencil/core'; - -export const config: Config = { - namespace: 'iot-app-kit', - outputTargets: [ - { - type: 'dist', - }, - ], - testing: { - setupFilesAfterEnv: ['jest-extended'], - collectCoverageFrom: ['src/**/*.{ts,tsx}'], - coveragePathIgnorePatterns: ['/typings/', '/src/testing/', '/src/iotsitewise/__mocks__'], - testPathIgnorePatterns: ['/src/testing', '/dist'], - coverageReporters: ['text-summary', 'cobertura', 'html', 'json', 'json-summary'], - moduleNameMapper: { - '\\.(css|scss|svg)$': 'identity-obj-proxy', - }, - coverageThreshold: { - global: { - statements: 80, - branches: 80, - functions: 80, - lines: 80, - }, - }, - }, -}; diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index aefac0a67..b509e906f 100755 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -2,20 +2,21 @@ "compilerOptions": { "allowSyntheticDefaultImports": true, "allowUnreachableCode": false, - "declaration": false, + "declaration": true, + "declarationDir": ".", + "outDir": "dist", "experimentalDecorators": true, "lib": ["dom", "es2019"], "moduleResolution": "node", "module": "esnext", "target": "es2017", - "jsx": "react", - "jsxFactory": "h", "esModuleInterop": true, "strict": true, "strictPropertyInitialization": false, "skipLibCheck": true, "resolveJsonModule": true }, - "include": ["src", "types/jsx.d.ts"], - "exclude": ["node_modules"] + "include": ["src"], + "exclude": ["node_modules", "dist"], + "files": ["global.d.ts"] } diff --git a/packages/react-components/package.json b/packages/react-components/package.json new file mode 100644 index 000000000..e6d1c5967 --- /dev/null +++ b/packages/react-components/package.json @@ -0,0 +1,50 @@ +{ + "name": "@iot-app-kit/react-components", + "license": "Apache-2.0", + "sideEffects": false, + "version": "0.0.1", + "private": true, + "description": "React specific wrapper for IoT Application Kit", + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com/" + }, + "scripts": { + "build": "npm run clean && npm run compile", + "clean": "rm -rf dist", + "compile": "npm run tsc", + "tsc": "tsc", + "rollup": "rollup -c" + }, + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist/" + ], + "devDependencies": { + "@types/jest": "23.3.9", + "@types/node": "^15.12.2", + "jest": "^23.0.0", + "jest-dom": "^3.0.2", + "np": "^3.1.0", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "typescript": "^3.3.4000" + }, + "dependencies": { + "@iot-app-kit/components": "*" + }, + "peerDependencies": { + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, + "jest": { + "preset": "ts-jest", + "setupTestFrameworkScriptFile": "/jest.setup.js", + "testPathIgnorePatterns": [ + "node_modules", + "dist" + ] + } +} diff --git a/packages/react-components/src/components.ts b/packages/react-components/src/components.ts new file mode 100644 index 000000000..8348d15ef --- /dev/null +++ b/packages/react-components/src/components.ts @@ -0,0 +1,16 @@ +/* eslint-disable */ +/* tslint:disable */ +import { createReactComponent } from './react-component-lib'; + +import type { JSX } from '@iot-app-kit/components'; + + + +export const BarChart = /*@__PURE__*/createReactComponent('iot-bar-chart'); +export const Kpi = /*@__PURE__*/createReactComponent('iot-kpi'); +export const LineChart = /*@__PURE__*/createReactComponent('iot-line-chart'); +export const ResourceExplorer = /*@__PURE__*/createReactComponent('iot-resource-explorer'); +export const ScatterChart = /*@__PURE__*/createReactComponent('iot-scatter-chart'); +export const StatusGrid = /*@__PURE__*/createReactComponent('iot-status-grid'); +export const StatusTimeline = /*@__PURE__*/createReactComponent('iot-status-timeline'); +export const Table = /*@__PURE__*/createReactComponent('iot-table'); diff --git a/packages/react-components/src/components/index.ts b/packages/react-components/src/components/index.ts new file mode 100644 index 000000000..7d91a5868 --- /dev/null +++ b/packages/react-components/src/components/index.ts @@ -0,0 +1 @@ +export * from './stencil-generated/index'; diff --git a/packages/react-components/src/components/stencil-generated/index.ts b/packages/react-components/src/components/stencil-generated/index.ts new file mode 100644 index 000000000..9dc10da21 --- /dev/null +++ b/packages/react-components/src/components/stencil-generated/index.ts @@ -0,0 +1,30 @@ +/* + +auto-generated react proxies will replace this file +if you use "../your-react-library-name/src/components/stencil-generated/index.ts" for your proxies target: + +*/ + +/* SAMPLE: +import { reactOutputTarget as react } from '@stencil/react-output-target' + +export const config: Config = { + outputTargets: [ + react({ + componentCorePackage: 'your-stencil-library-name', + proxiesFile: '../your-react-library-name/src/components/stencil-generated/index.ts', + includeDefineCustomElements: true, + }); + { + type: 'dist', + esmLoaderPath: '../loader', + }, + { + type: 'dist-custom-elements', + dir: "./dist/custom-elements" + }, + ], +} +*/ + +export const object = {}; diff --git a/packages/react-components/src/index.ts b/packages/react-components/src/index.ts new file mode 100644 index 000000000..07635cbbc --- /dev/null +++ b/packages/react-components/src/index.ts @@ -0,0 +1 @@ +export * from './components'; diff --git a/packages/react-components/src/react-component-lib/createComponent.tsx b/packages/react-components/src/react-component-lib/createComponent.tsx new file mode 100644 index 000000000..fe1fb178a --- /dev/null +++ b/packages/react-components/src/react-component-lib/createComponent.tsx @@ -0,0 +1,106 @@ +import React, { createElement } from 'react'; + +import { attachProps, camelToDashCase, createForwardRef, dashToPascalCase, isCoveredByReact, mergeRefs } from './utils'; + +export interface HTMLStencilElement extends HTMLElement { + componentOnReady(): Promise; +} + +interface StencilReactInternalProps extends React.HTMLAttributes { + forwardedRef: React.RefObject; + ref?: React.Ref; +} + +export const createReactComponent = < + PropType, + ElementType extends HTMLStencilElement, + ContextStateType = {}, + ExpandedPropsTypes = {} +>( + tagName: string, + ReactComponentContext?: React.Context, + manipulatePropsFunction?: ( + originalProps: StencilReactInternalProps, + propsToPass: any + ) => ExpandedPropsTypes, + defineCustomElement?: () => void +) => { + if (defineCustomElement !== undefined) { + defineCustomElement(); + } + + const displayName = dashToPascalCase(tagName); + const ReactComponent = class extends React.Component> { + componentEl!: ElementType; + + setComponentElRef = (element: ElementType) => { + this.componentEl = element; + }; + + constructor(props: StencilReactInternalProps) { + super(props); + } + + componentDidMount() { + this.componentDidUpdate(this.props); + } + + componentDidUpdate(prevProps: StencilReactInternalProps) { + attachProps(this.componentEl, this.props, prevProps); + } + + render() { + const { children, forwardedRef, style, className, ref, ...cProps } = this.props; + + let propsToPass = Object.keys(cProps).reduce((acc: any, name) => { + const value = (cProps as any)[name]; + + if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) { + const eventName = name.substring(2).toLowerCase(); + if (typeof document !== 'undefined' && isCoveredByReact(eventName)) { + acc[name] = value; + } + } else { + // we should only render strings, booleans, and numbers as attrs in html. + // objects, functions, arrays etc get synced via properties on mount. + const type = typeof value; + + if (type === 'string' || type === 'boolean' || type === 'number') { + acc[camelToDashCase(name)] = value; + } + } + return acc; + }, {}); + + if (manipulatePropsFunction) { + propsToPass = manipulatePropsFunction(this.props, propsToPass); + } + + const newProps: Omit, 'forwardedRef'> = { + ...propsToPass, + ref: mergeRefs(forwardedRef, this.setComponentElRef), + style, + }; + + /** + * We use createElement here instead of + * React.createElement to work around a + * bug in Vite (https://github.com/vitejs/vite/issues/6104). + * React.createElement causes all elements to be rendered + * as instead of the actual Web Component. + */ + return createElement(tagName, newProps, children); + } + + static get displayName() { + return displayName; + } + }; + + // If context was passed to createReactComponent then conditionally add it to the Component Class + if (ReactComponentContext) { + ReactComponent.contextType = ReactComponentContext; + } + + return createForwardRef(ReactComponent, displayName); +}; diff --git a/packages/react-components/src/react-component-lib/createOverlayComponent.tsx b/packages/react-components/src/react-component-lib/createOverlayComponent.tsx new file mode 100644 index 000000000..288c38dd5 --- /dev/null +++ b/packages/react-components/src/react-component-lib/createOverlayComponent.tsx @@ -0,0 +1,142 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import { OverlayEventDetail } from './interfaces'; +import { StencilReactForwardedRef, attachProps, dashToPascalCase, defineCustomElement, setRef } from './utils'; + +interface OverlayElement extends HTMLElement { + present: () => Promise; + dismiss: (data?: any, role?: string | undefined) => Promise; +} + +export interface ReactOverlayProps { + children?: React.ReactNode; + isOpen: boolean; + onDidDismiss?: (event: CustomEvent) => void; + onDidPresent?: (event: CustomEvent) => void; + onWillDismiss?: (event: CustomEvent) => void; + onWillPresent?: (event: CustomEvent) => void; +} + +export const createOverlayComponent = ( + tagName: string, + controller: { create: (options: any) => Promise }, + customElement?: any +) => { + defineCustomElement(tagName, customElement); + + const displayName = dashToPascalCase(tagName); + const didDismissEventName = `on${displayName}DidDismiss`; + const didPresentEventName = `on${displayName}DidPresent`; + const willDismissEventName = `on${displayName}WillDismiss`; + const willPresentEventName = `on${displayName}WillPresent`; + + type Props = OverlayComponent & + ReactOverlayProps & { + forwardedRef?: StencilReactForwardedRef; + }; + + let isDismissing = false; + + class Overlay extends React.Component { + overlay?: OverlayType; + el!: HTMLDivElement; + + constructor(props: Props) { + super(props); + if (typeof document !== 'undefined') { + this.el = document.createElement('div'); + } + this.handleDismiss = this.handleDismiss.bind(this); + } + + static get displayName() { + return displayName; + } + + componentDidMount() { + if (this.props.isOpen) { + this.present(); + } + } + + componentWillUnmount() { + if (this.overlay) { + this.overlay.dismiss(); + } + } + + handleDismiss(event: CustomEvent>) { + if (this.props.onDidDismiss) { + this.props.onDidDismiss(event); + } + setRef(this.props.forwardedRef, null); + } + + shouldComponentUpdate(nextProps: Props) { + // Check if the overlay component is about to dismiss + if (this.overlay && nextProps.isOpen !== this.props.isOpen && nextProps.isOpen === false) { + isDismissing = true; + } + + return true; + } + + async componentDidUpdate(prevProps: Props) { + if (this.overlay) { + attachProps(this.overlay, this.props, prevProps); + } + + if (prevProps.isOpen !== this.props.isOpen && this.props.isOpen === true) { + this.present(prevProps); + } + if (this.overlay && prevProps.isOpen !== this.props.isOpen && this.props.isOpen === false) { + await this.overlay.dismiss(); + isDismissing = false; + + /** + * Now that the overlay is dismissed + * we need to render again so that any + * inner components will be unmounted + */ + this.forceUpdate(); + } + } + + async present(prevProps?: Props) { + const { children, isOpen, onDidDismiss, onDidPresent, onWillDismiss, onWillPresent, ...cProps } = this.props; + const elementProps = { + ...cProps, + ref: this.props.forwardedRef, + [didDismissEventName]: this.handleDismiss, + [didPresentEventName]: (e: CustomEvent) => this.props.onDidPresent && this.props.onDidPresent(e), + [willDismissEventName]: (e: CustomEvent) => this.props.onWillDismiss && this.props.onWillDismiss(e), + [willPresentEventName]: (e: CustomEvent) => this.props.onWillPresent && this.props.onWillPresent(e), + }; + + this.overlay = await controller.create({ + ...elementProps, + component: this.el, + componentProps: {}, + }); + + setRef(this.props.forwardedRef, this.overlay); + attachProps(this.overlay, elementProps, prevProps); + + await this.overlay.present(); + } + + render() { + /** + * Continue to render the component even when + * overlay is dismissing otherwise component + * will be hidden before animation is done. + */ + return ReactDOM.createPortal(this.props.isOpen || isDismissing ? this.props.children : null, this.el); + } + } + + return React.forwardRef((props, ref) => { + return ; + }); +}; diff --git a/packages/react-components/src/react-component-lib/index.ts b/packages/react-components/src/react-component-lib/index.ts new file mode 100644 index 000000000..85e81ad19 --- /dev/null +++ b/packages/react-components/src/react-component-lib/index.ts @@ -0,0 +1,2 @@ +export { createReactComponent } from './createComponent'; +export { createOverlayComponent } from './createOverlayComponent'; diff --git a/packages/react-components/src/react-component-lib/interfaces.ts b/packages/react-components/src/react-component-lib/interfaces.ts new file mode 100644 index 000000000..92e5389c8 --- /dev/null +++ b/packages/react-components/src/react-component-lib/interfaces.ts @@ -0,0 +1,34 @@ +// General types important to applications using stencil built components +export interface EventEmitter { + emit: (data?: T) => CustomEvent; +} + +export interface StyleReactProps { + class?: string; + className?: string; + style?: { [key: string]: any }; +} + +export interface OverlayEventDetail { + data?: T; + role?: string; +} + +export interface OverlayInterface { + el: HTMLElement; + animated: boolean; + keyboardClose: boolean; + overlayIndex: number; + presented: boolean; + + enterAnimation?: any; + leaveAnimation?: any; + + didPresent: EventEmitter; + willPresent: EventEmitter; + willDismiss: EventEmitter; + didDismiss: EventEmitter; + + present(): Promise; + dismiss(data?: any, role?: string): Promise; +} diff --git a/packages/react-components/src/react-component-lib/utils/attachProps.ts b/packages/react-components/src/react-component-lib/utils/attachProps.ts new file mode 100644 index 000000000..de2cc499b --- /dev/null +++ b/packages/react-components/src/react-component-lib/utils/attachProps.ts @@ -0,0 +1,114 @@ +import { camelToDashCase } from './case'; + +export const attachProps = (node: HTMLElement, newProps: any, oldProps: any = {}) => { + // some test frameworks don't render DOM elements, so we test here to make sure we are dealing with DOM first + if (node instanceof Element) { + // add any classes in className to the class list + const className = getClassName(node.classList, newProps, oldProps); + if (className !== '') { + node.className = className; + } + + Object.keys(newProps).forEach((name) => { + if ( + name === 'children' || + name === 'style' || + name === 'ref' || + name === 'class' || + name === 'className' || + name === 'forwardedRef' + ) { + return; + } + if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) { + const eventName = name.substring(2); + const eventNameLc = eventName[0].toLowerCase() + eventName.substring(1); + + if (!isCoveredByReact(eventNameLc)) { + syncEvent(node, eventNameLc, newProps[name]); + } + } else { + (node as any)[name] = newProps[name]; + const propType = typeof newProps[name]; + if (propType === 'string') { + node.setAttribute(camelToDashCase(name), newProps[name]); + } + } + }); + } +}; + +export const getClassName = (classList: DOMTokenList, newProps: any, oldProps: any) => { + const newClassProp: string = newProps.className || newProps.class; + const oldClassProp: string = oldProps.className || oldProps.class; + // map the classes to Maps for performance + const currentClasses = arrayToMap(classList); + const incomingPropClasses = arrayToMap(newClassProp ? newClassProp.split(' ') : []); + const oldPropClasses = arrayToMap(oldClassProp ? oldClassProp.split(' ') : []); + const finalClassNames: string[] = []; + // loop through each of the current classes on the component + // to see if it should be a part of the classNames added + currentClasses.forEach((currentClass) => { + if (incomingPropClasses.has(currentClass)) { + // add it as its already included in classnames coming in from newProps + finalClassNames.push(currentClass); + incomingPropClasses.delete(currentClass); + } else if (!oldPropClasses.has(currentClass)) { + // add it as it has NOT been removed by user + finalClassNames.push(currentClass); + } + }); + incomingPropClasses.forEach((s) => finalClassNames.push(s)); + return finalClassNames.join(' '); +}; + +/** + * Checks if an event is supported in the current execution environment. + * @license Modernizr 3.0.0pre (Custom Build) | MIT + */ +export const isCoveredByReact = (eventNameSuffix: string) => { + if (typeof document === 'undefined') { + return true; + } else { + const eventName = 'on' + eventNameSuffix; + let isSupported = eventName in document; + + if (!isSupported) { + const element = document.createElement('div'); + element.setAttribute(eventName, 'return;'); + isSupported = typeof (element as any)[eventName] === 'function'; + } + + return isSupported; + } +}; + +export const syncEvent = ( + node: Element & { __events?: { [key: string]: ((e: Event) => any) | undefined } }, + eventName: string, + newEventHandler?: (e: Event) => any +) => { + const eventStore = node.__events || (node.__events = {}); + const oldEventHandler = eventStore[eventName]; + + // Remove old listener so they don't double up. + if (oldEventHandler) { + node.removeEventListener(eventName, oldEventHandler); + } + + // Bind new listener. + node.addEventListener( + eventName, + (eventStore[eventName] = function handler(e: Event) { + if (newEventHandler) { + newEventHandler.call(this, e); + } + }) + ); +}; + +const arrayToMap = (arr: string[] | DOMTokenList) => { + const map = new Map(); + (arr as string[]).forEach((s: string) => map.set(s, s)); + return map; +}; diff --git a/packages/react-components/src/react-component-lib/utils/case.ts b/packages/react-components/src/react-component-lib/utils/case.ts new file mode 100644 index 000000000..786689dc9 --- /dev/null +++ b/packages/react-components/src/react-component-lib/utils/case.ts @@ -0,0 +1,7 @@ +export const dashToPascalCase = (str: string) => + str + .toLowerCase() + .split('-') + .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)) + .join(''); +export const camelToDashCase = (str: string) => str.replace(/([A-Z])/g, (m: string) => `-${m[0].toLowerCase()}`); diff --git a/packages/react-components/src/react-component-lib/utils/dev.ts b/packages/react-components/src/react-component-lib/utils/dev.ts new file mode 100644 index 000000000..cc6f9ed08 --- /dev/null +++ b/packages/react-components/src/react-component-lib/utils/dev.ts @@ -0,0 +1,14 @@ +export const isDevMode = () => { + return process && process.env && process.env.NODE_ENV === 'development'; +}; + +const warnings: { [key: string]: boolean } = {}; + +export const deprecationWarning = (key: string, message: string) => { + if (isDevMode()) { + if (!warnings[key]) { + console.warn(message); + warnings[key] = true; + } + } +}; diff --git a/packages/react-components/src/react-component-lib/utils/index.tsx b/packages/react-components/src/react-component-lib/utils/index.tsx new file mode 100644 index 000000000..a66bd02de --- /dev/null +++ b/packages/react-components/src/react-component-lib/utils/index.tsx @@ -0,0 +1,50 @@ +import React from 'react'; + +import type { StyleReactProps } from '../interfaces'; + +export type StencilReactExternalProps = PropType & + Omit, 'style'> & + StyleReactProps; + +// This will be replaced with React.ForwardedRef when react-output-target is upgraded to React v17 +export type StencilReactForwardedRef = ((instance: T | null) => void) | React.MutableRefObject | null; + +export const setRef = (ref: StencilReactForwardedRef | React.Ref | undefined, value: any) => { + if (typeof ref === 'function') { + ref(value); + } else if (ref != null) { + // Cast as a MutableRef so we can assign current + (ref as React.MutableRefObject).current = value; + } +}; + +export const mergeRefs = ( + ...refs: (StencilReactForwardedRef | React.Ref | undefined)[] +): React.RefCallback => { + return (value: any) => { + refs.forEach((ref) => { + setRef(ref, value); + }); + }; +}; + +export const createForwardRef = (ReactComponent: any, displayName: string) => { + const forwardRef = ( + props: StencilReactExternalProps, + ref: StencilReactForwardedRef + ) => { + return ; + }; + forwardRef.displayName = displayName; + + return React.forwardRef(forwardRef); +}; + +export const defineCustomElement = (tagName: string, customElement: any) => { + if (customElement !== undefined && typeof customElements !== 'undefined' && !customElements.get(tagName)) { + customElements.define(tagName, customElement); + } +}; + +export * from './attachProps'; +export * from './case'; diff --git a/packages/react-components/tsconfig.json b/packages/react-components/tsconfig.json new file mode 100644 index 000000000..0e0a6c26d --- /dev/null +++ b/packages/react-components/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "allowUnreachableCode": false, + "allowSyntheticDefaultImports": true, + "declaration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "lib": ["dom", "es2015"], + "module": "es2015", + "moduleResolution": "node", + "noImplicitAny": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "outDir": "dist", + "skipLibCheck": true, + "removeComments": false, + "sourceMap": true, + "jsx": "react", + "target": "es2015" + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx" + ], + "exclude": [ + "**/__tests__/**" + ], + "compileOnSave": false, + "buildOnSave": false + } diff --git a/packages/related-table/jest.config.ts b/packages/related-table/jest.config.ts index 5cab71e1a..d18cc66cf 100644 --- a/packages/related-table/jest.config.ts +++ b/packages/related-table/jest.config.ts @@ -4,202 +4,20 @@ */ export default { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - preset: 'ts-jest', - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "/private/var/folders/4g/t2qfg6rn6wg3wj5nbr4y44wmjz8_xs/T/jest_9z4rll", - - // Automatically clear mock calls and instances between every test clearMocks: true, - - // Indicates whether the coverage information should be collected while executing the test collectCoverage: true, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: undefined, - - // The directory where Jest should output its coverage files coverageDirectory: 'coverage', - - // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "/node_modules/" - // ], - - // Indicates which provider should be used to instrument code for coverage coverageProvider: 'v8', - - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: undefined, - - // A path to a custom dependency extractor - // dependencyExtractor: undefined, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: undefined, - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, - - // A set of global variables that need to be available in all test environments - // globals: {}, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - // An array of file extensions your modules use - // moduleFileExtensions: [ - // "js", - // "jsx", - // "ts", - // "tsx", - // "json", - // "node" - // ], - - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - // moduleNameMapper: {}, moduleNameMapper: { '\\.(css|less)$': '/config/jest/styleMock.js', }, - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - // preset: undefined, - - // Run tests from one or more projects - // projects: undefined, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state between every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: undefined, - - // Automatically restore mock state between every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - // rootDir: undefined, - - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], - - // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing testEnvironment: 'jsdom', - - // Options that will be passed to the testEnvironment - // testEnvironmentOptions: {}, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - // testMatch: [ - // "**/__tests__/**/*.[jt]s?(x)", - // "**/?(*.)+(spec|test).[tj]s?(x)" - // ], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "/node_modules/" - // ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, - - // This option allows use of a custom test runner - // testRunner: "jest-circus/runner", - - // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href - // testURL: "http://localhost", - - // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" - // timers: "real", - - // A map from regular expressions to paths to transformers - // transform: undefined, + setupFilesAfterEnv: ['mutationobserver-shim'], transform: { '.+\\.ts$': 'ts-jest', '^.+\\.tsx?$': 'ts-jest', '^.+\\.(js|jsx)$': 'babel-jest', }, - - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "/node_modules/", - // "\\.pnp\\.[^\\/]+$" - // ], transformIgnorePatterns: ['node_modules/(?!@awsui/components-react)/'], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: undefined, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, }; diff --git a/packages/related-table/package.json b/packages/related-table/package.json index 88ad858cd..6f65b009f 100644 --- a/packages/related-table/package.json +++ b/packages/related-table/package.json @@ -2,7 +2,7 @@ "name": "@iot-app-kit/related-table", "version": "1.0.0", "description": "IoT Application Kit - Related Table component", - "license": "Apache 2.0", + "license": "Apache-2.0", "main": "dist/index.js", "types": "dist/index.d.ts", "module": "dist/index.module.js", @@ -23,6 +23,7 @@ "build": "microbundle --no-compress --format modern,esm,cjs --jsx React.createElement", "generate-barrels": "barrelsby --config ./barrel-config.json", "test": "jest", + "test.watch": "TZ=UTC jest --watchAll", "storybook": "start-storybook -p 6006", "prepublishOnly": "npm run build", "copy:license": "cp ../../LICENSE LICENSE", @@ -34,8 +35,8 @@ "@awsui/collection-hooks": "^1.0.0", "@awsui/components-react": "^3.0.0", "@awsui/design-tokens": "^3.0.0", - "react": ">=16.14.0", - "react-dom": ">=16.14.0", + "react": ">=17.0.2", + "react-dom": ">=17.0.2", "styled-components": "^5.3.0" }, "devDependencies": { @@ -43,10 +44,9 @@ "@awsui/components-react": "^3.0.0", "@awsui/design-tokens": "^3.0.0", "@babel/core": "^7.10.6", - "@babel/preset-env": "^7.10.0", "@babel/plugin-transform-runtime": "^7.16.0", + "@babel/preset-env": "^7.10.0", "@storybook/addon-essentials": "^6.2.9", - "@storybook/addon-info": "^5.3.21", "@storybook/addon-links": "^6.2.9", "@storybook/addon-postcss": "^2.0.0", "@storybook/addons": "^6.2.9", @@ -54,8 +54,8 @@ "@storybook/react": "^6.2.9", "@testing-library/react": "^12.0.0", "@testing-library/react-hooks": "^7.0.0", - "@types/react": ">=16.9.0", - "@types/react-dom": ">=16.9.0", + "@types/react": ">=17.0.2", + "@types/react-dom": ">=17.0.2", "@types/styled-components": "^5.1.10", "autoprefixer": "^10.2.6", "babel-loader": "^8.2.2", @@ -65,16 +65,18 @@ "husky": "^6.0.0", "microbundle": "^0.13.3", "postcss": "^8.3.4", - "react": ">=16.14.0", - "react-dom": ">=16.14.0", + "react": ">=17.0.2", + "react-dom": ">=17.0.2", "rollup": "^2.52.2", "rollup-plugin-postcss": "^4.0.0", "sass": "^1.30.0", "sass-loader": "^10.2.0", - "styled-components": "^5.3.0", "style-loader": "^2.0.0", "ts-node": "^10.0.0", "tslib": "^2.3.0", "typescript": "^4.3.0" + }, + "dependencies": { + "mutationobserver-shim": "^0.3.7" } } diff --git a/packages/source-iotsitewise/README.md b/packages/source-iotsitewise/README.md new file mode 100644 index 000000000..9c163c1aa --- /dev/null +++ b/packages/source-iotsitewise/README.md @@ -0,0 +1,11 @@ +# `@iot-app-kit/source-iotsitewise` + +> TODO: description + +## Usage + +``` +const sourceIotsitewise = require('@iot-app-kit/source-iotsitewise'); + +// TODO: DEMONSTRATE API +``` diff --git a/packages/source-iotsitewise/lib/source-iotsitewise.js b/packages/source-iotsitewise/lib/source-iotsitewise.js new file mode 100644 index 000000000..8af260e1e --- /dev/null +++ b/packages/source-iotsitewise/lib/source-iotsitewise.js @@ -0,0 +1,7 @@ +'use strict'; + +module.exports = sourceIotsitewise; + +function sourceIotsitewise() { + // TODO +} diff --git a/packages/source-iotsitewise/package.json b/packages/source-iotsitewise/package.json new file mode 100644 index 000000000..9d1b12ff8 --- /dev/null +++ b/packages/source-iotsitewise/package.json @@ -0,0 +1,28 @@ +{ + "name": "@iot-app-kit/source-iotsitewise", + "version": "0.0.1", + "description": "AWS IoT SiteWise source for IoT Application Kit", + "homepage": "https://github.com/awslabs/iot-app-kit#readme", + "license": "Apache-2.0", + "main": "lib/source-iotsitewise.js", + "directories": { + "lib": "lib", + "test": "__tests__" + }, + "files": [ + "lib" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/awslabs/iot-app-kit.git" + }, + "scripts": { + "test": "echo \"Error: run tests from root\" && exit 0" + }, + "bugs": { + "url": "https://github.com/awslabs/iot-app-kit/issues" + } +}