Skip to content

Commit

Permalink
feat: improve error handling (#61)
Browse files Browse the repository at this point in the history
* add status to error callback for time series data
* add error handling in asset module
* fix skiped tests
* refactor subscribeToAssetTree to accept observer instead of next callback

Co-authored-by: Norbert Nader <nnader@amazon.com>
  • Loading branch information
NorbertNader and NorbertNader committed Feb 18, 2022
1 parent e62f44b commit 5016e41
Show file tree
Hide file tree
Showing 34 changed files with 590 additions and 222 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,36 @@ export class IotAssetDetails {

componentWillLoad() {
this.assetSession = getSiteWiseAssetModule().startSession();
this.assetSession.requestAssetSummary(this.query, (summary: AssetSummary) => {
this.assetSummary = summary;
const assetId = this.assetSummary?.id as string;
const modelQuery: AssetModelQuery = { assetModelId: this.assetSummary.assetModelId as string };
this.assetSession.requestAssetModel(modelQuery, (assetModel: DescribeAssetModelResponse) => {
this.assetModel = assetModel;
assetModel.assetModelProperties?.forEach((prop) => {
let propQuery: AssetPropertyValueQuery = { assetId: assetId, propertyId: prop.id as string };
this.assetSession.requestAssetPropertyValue(propQuery, (propValue: AssetPropertyValue) => {
const copy = new Map(this.assetPropertyValues);
copy.set(prop.id as string, this.convertToString(propValue));
this.assetPropertyValues = copy;
});
this.assetSession.requestAssetSummary(this.query, {
next: (summary: AssetSummary) => {
this.assetSummary = summary;
const assetId = this.assetSummary?.id as string;
const modelQuery: AssetModelQuery = { assetModelId: this.assetSummary.assetModelId as string };
this.assetSession.requestAssetModel(modelQuery, {
next: (assetModel: DescribeAssetModelResponse) => {
this.assetModel = assetModel;
assetModel.assetModelProperties?.forEach((prop) => {
let propQuery: AssetPropertyValueQuery = { assetId: assetId, propertyId: prop.id as string };
this.assetSession.requestAssetPropertyValue(propQuery, {
next: (propValue: AssetPropertyValue) => {
const copy = new Map(this.assetPropertyValues);
copy.set(prop.id as string, this.convertToString(propValue));
this.assetPropertyValues = copy;
},
error: (err) => {
// noop
},
});
});
},
error: (err) => {
// noop
},
});
});
},
error: (err) => {
// noop
},
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ export class IotAssetTreeDemo {
let session: SiteWiseAssetTreeSession = new SiteWiseAssetTreeModule(getSiteWiseAssetModule()).startSession(
this.query
);
this.subscription = session.subscribe((newTree) => {
this.roots = newTree;
// check the tree for any new unexpanded nodes and expand them:
this.expandNodes(newTree);
this.subscription = session.subscribe({
next: (newTree) => {
this.roots = newTree;
// check the tree for any new unexpanded nodes and expand them:
this.expandNodes(newTree);
},
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import {
IoTAppKit,
SiteWiseAssetTreeNode,
SiteWiseAssetTreeQuery,
ErrorDetails,
} from '@iot-app-kit/core';
import { SitewiseAssetResource } from './types';
import { SitewiseAssetResource, FilterTexts, ColumnDefinition } from './types';
import { EmptyStateProps, ITreeNode, UseTreeCollection } from '@iot-app-kit/related-table';
import { parseSitewiseAssetTree } from './utils';
import { TableProps } from '@awsui/components-react/table';
import { FilterTexts, ColumnDefinition } from './types';
import { NonCancelableCustomEvent } from '@awsui/components-react';

@Component({
Expand All @@ -33,6 +33,8 @@ export class SitewiseResourceExplorer {

@State() items: SitewiseAssetResource[] = [];

@State() errors: ErrorDetails[] = [];

defaults = {
selectionType: 'single' as TableProps.SelectionType,
loadingText: 'loading...',
Expand All @@ -50,9 +52,14 @@ export class SitewiseResourceExplorer {
subscription: AssetTreeSubscription;

componentWillLoad() {
this.subscription = this.appKit.subscribeToAssetTree(this.query, (newTree: SiteWiseAssetTreeNode[]) => {
this.items = parseSitewiseAssetTree(newTree);
});
this.subscription = this.appKit.subscribeToAssetTree(this.query, {
next: (newTree: SiteWiseAssetTreeNode[]) => {
this.items = parseSitewiseAssetTree(newTree);
},
error: (err: ErrorDetails[]) => {
this.errors = err;
},
}) as AssetTreeSubscription;
}

componentWillUnmount() {
Expand Down Expand Up @@ -87,6 +94,18 @@ export class SitewiseResourceExplorer {
if (this.paginationEnabled) {
collectionOptions.pagination = { pageSize: 20 };
}

let empty: EmptyStateProps = this.defaults.empty;

if (this.empty) {
empty = this.empty;
}

if (this.errors.length > 0) {
// TODO: Make use of all the errors
empty = { header: 'Error', description: this.errors[this.errors.length - 1]?.msg };
}

return (
<iot-tree-table
items={this.items}
Expand All @@ -97,7 +116,7 @@ export class SitewiseResourceExplorer {
filterPlaceholder={filtering?.placeholder}
onExpandChildren={this.expandNode}
onSelectionChange={this.onSelectionChange}
empty={this.empty || this.defaults.empty}
empty={empty}
sortingDisabled={!this.sortingEnabled}
wrapLines={this.wrapLines}
></iot-tree-table>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const STRING_ASSET_ID = 'f2f74fa8-625a-435f-b89c-d27b2d84f45b';
const STRING_PROPERTY_ID = '797482e4-692f-45a2-b3db-17979481e9c3';

export const DEMO_TURBINE_ASSET_1 = 'f2f74fa8-625a-435f-b89c-d27b2d84f45b';
export const DEMO_TURBINE_ASSET_1 = '00eeb4b1-5017-48d4-9f39-1066f080a822';

export const DEMO_TURBINE_ASSET_1_PROPERTY_1 = 'd0dc79be-0dc2-418c-ac23-26f33cdb4b8b';
export const DEMO_TURBINE_ASSET_1_PROPERTY_2 = '69607dc2-5fbe-416d-aac2-0382018626e4';
export const DEMO_TURBINE_ASSET_1_PROPERTY_3 = '26072fa0-e36e-489d-90b4-1774e7d12ac9';
export const DEMO_TURBINE_ASSET_1_PROPERTY_4 = '5c2b7401-57e0-4205-97f2-c4348f12da9a';
export const DEMO_TURBINE_ASSET_1_PROPERTY_1 = '8739b557-3e77-4df9-9862-130b29dee2b1';
export const DEMO_TURBINE_ASSET_1_PROPERTY_2 = '9701d7ad-c22e-43fd-b040-68bad00317e3';
export const DEMO_TURBINE_ASSET_1_PROPERTY_3 = 'bded202a-a436-46b8-85c1-21bb5b945f86';
export const DEMO_TURBINE_ASSET_1_PROPERTY_4 = 'd8937b65-5f03-4e40-93ac-c5513420ade7';

export const STRING_QUERY = {
source: 'site-wise',
Expand All @@ -27,9 +27,9 @@ export const NUMBER_QUERY = {
],
};

const AGGREGATED_DATA_ASSET = 'f2f74fa8-625a-435f-b89c-d27b2d84f45b';
const AGGREGATED_DATA_PROPERTY = 'd0dc79be-0dc2-418c-ac23-26f33cdb4b8b';
const AGGREGATED_DATA_PROPERTY_2 = '69607dc2-5fbe-416d-aac2-0382018626e4';
const AGGREGATED_DATA_ASSET = '099b1330-83ff-4fec-b165-c7186ec8eb23';
const AGGREGATED_DATA_PROPERTY = '05c5c47f-fd92-4823-828e-09ce63b90569';
const AGGREGATED_DATA_PROPERTY_2 = '11d2599a-2547-451d-ab79-a47f878dbbe3';

export const AGGREGATED_DATA_QUERY = {
assets: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export class TestingGround {
<iot-line-chart
appKit={this.appKit}
viewport={this.viewport}
settings={{ resolution: this.resolution, requestBuffer: 1 }}
queries={[query.iotsitewise.timeSeriesData(AGGREGATED_DATA_QUERY)]}
/>
</div>
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/asset-modules/coordinator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SiteWiseAssetSession } from './sitewise/session';
import { SiteWiseAssetTreeCallback, SiteWiseAssetTreeQuery } from './sitewise-asset-tree/types';
import { SiteWiseAssetTreeObserver, SiteWiseAssetTreeQuery } from './sitewise-asset-tree/types';
import { SiteWiseAssetTreeSession } from './sitewise-asset-tree/assetTreeSession';

export const subscribeToAssetTree =
(assetModuleSession: SiteWiseAssetSession) => (query: SiteWiseAssetTreeQuery, callback: SiteWiseAssetTreeCallback) =>
new SiteWiseAssetTreeSession(assetModuleSession, query).subscribe(callback);
(assetModuleSession: SiteWiseAssetSession) => (query: SiteWiseAssetTreeQuery, observer: SiteWiseAssetTreeObserver) =>
new SiteWiseAssetTreeSession(assetModuleSession, query).subscribe(observer);
52 changes: 44 additions & 8 deletions packages/core/src/asset-modules/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import {
} from './sitewise/types';
import { AssetPropertyValue, AssetSummary, DescribeAssetModelResponse } from '@aws-sdk/client-iotsitewise';
import { lastValueFrom, Observable, Subscription } from 'rxjs';
import { ErrorDetails } from '../common/types';

export class MockSiteWiseAssetsReplayData {
public models: Map<string, DescribeAssetModelResponse> = new Map<string, DescribeAssetModelResponse>();
public hierarchies: Map<string, HierarchyAssetSummaryList> = new Map<string, HierarchyAssetSummaryList>();
public properties: Map<string, AssetPropertyValue> = new Map<string, AssetPropertyValue>();
public assets: Map<string, AssetSummary> = new Map<string, AssetSummary>();
public errors: ErrorDetails[] = [];

public addAssetModels(newModels: DescribeAssetModelResponse[]) {
newModels.forEach((model) => this.models.set(model.assetModelId as string, model));
Expand All @@ -33,6 +35,10 @@ export class MockSiteWiseAssetsReplayData {
) {
this.hierarchies.set(assetHierarchyQueryKey(query), newHierarchyAssetSummaryList);
}

public addErrors(errors: ErrorDetails[]) {
this.errors = [...this.errors, ...errors];
}
}

export class MockSiteWiseAssetSession implements SiteWiseAssetSessionInterface {
Expand All @@ -44,10 +50,20 @@ export class MockSiteWiseAssetSession implements SiteWiseAssetSessionInterface {

private _requestAssetSummary(query: { assetId: string }): Observable<AssetSummary> {
return new Observable<AssetSummary>((observer) => {
observer.next(this.replayData.assets.get(query.assetId));
if (this.replayData.errors.length > 0) {
observer.error(this.replayData.errors);
} else {
observer.next(this.replayData.assets.get(query.assetId));
}
});
}
requestAssetSummary(query: { assetId: string }, observer: (assetSummary: AssetSummary) => void): Subscription {
requestAssetSummary(
query: { assetId: string },
observer: {
next: (assetSummary: AssetSummary) => void;
error?: (err: ErrorDetails[]) => void;
}
): Subscription {
return this._requestAssetSummary(query).subscribe(observer);
}
fetchAssetSummary(query: { assetId: string }): Promise<AssetSummary> {
Expand All @@ -61,7 +77,10 @@ export class MockSiteWiseAssetSession implements SiteWiseAssetSessionInterface {
}
requestAssetModel(
query: { assetModelId: string },
observer: (assetSummary: DescribeAssetModelResponse) => void
observer: {
next: (assetSummary: DescribeAssetModelResponse) => void;
error?: (err: ErrorDetails[]) => void;
}
): Subscription {
return this._requestAssetModel(query).subscribe(observer);
}
Expand All @@ -76,7 +95,10 @@ export class MockSiteWiseAssetSession implements SiteWiseAssetSessionInterface {
}
requestAssetPropertyValue(
query: { assetId: string; propertyId: string },
observer: (assetSummary: AssetPropertyValue) => void
observer: {
next: (assetSummary: AssetPropertyValue) => void;
error?: (err: ErrorDetails[]) => void;
}
): Subscription {
return this._requestAssetPropertyValue(query).subscribe(observer);
}
Expand All @@ -89,12 +111,19 @@ export class MockSiteWiseAssetSession implements SiteWiseAssetSessionInterface {
assetHierarchyId: string;
}): Observable<HierarchyAssetSummaryList> {
return new Observable<HierarchyAssetSummaryList>((observer) => {
observer.next(this.replayData.hierarchies.get(assetHierarchyQueryKey(query)));
if (this.replayData.errors.length > 0) {
observer.error(this.replayData.errors);
} else {
observer.next(this.replayData.hierarchies.get(assetHierarchyQueryKey(query)));
}
});
}
requestAssetHierarchy(
query: { assetId?: string | undefined; assetHierarchyId: string },
observer: (assetSummary: HierarchyAssetSummaryList) => void
observer: {
next: (assetSummary: HierarchyAssetSummaryList) => void;
error?: (err: ErrorDetails[]) => void;
}
): Subscription {
return this._requestAssetHierarchy(query).subscribe(observer);
}
Expand All @@ -107,10 +136,17 @@ export class MockSiteWiseAssetSession implements SiteWiseAssetSessionInterface {

_requestRootAssets(): Observable<HierarchyAssetSummaryList> {
return new Observable<HierarchyAssetSummaryList>((observer) => {
observer.next(this.replayData.hierarchies.get(assetHierarchyQueryKey({ assetHierarchyId: HIERARCHY_ROOT_ID })));
if (this.replayData.errors.length > 0) {
observer.error(this.replayData.errors);
} else {
observer.next(this.replayData.hierarchies.get(assetHierarchyQueryKey({ assetHierarchyId: HIERARCHY_ROOT_ID })));
}
});
}
requestRootAssets(observer: (assetSummary: HierarchyAssetSummaryList) => void): Subscription {
requestRootAssets(observer: {
next: (assetSummary: HierarchyAssetSummaryList) => void;
error?: (err: ErrorDetails[]) => void;
}): Subscription {
return this._requestRootAssets().subscribe(observer);
}
fetchRootAssets(): Promise<HierarchyAssetSummaryList> {
Expand Down

0 comments on commit 5016e41

Please sign in to comment.