Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: updated the date time to support timezone #2820

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 11 additions & 2 deletions packages/dashboard/e2e/tests/trendCursors/trendCursors.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { test, expect, Page, Locator } from '@playwright/test';
import { parse } from 'date-fns';
import {
ADD_TREND_CURSOR,
ASSET_MODEL_TAB,
Expand Down Expand Up @@ -185,8 +186,16 @@ test('can drag a trend cursor', async ({ page }) => {
expect(initialTrendCursorDateString).not.toEqual(
updatedTrendCursorDateString
);
const initialDate = new Date(initialTrendCursorDateString);
const updatedDate = new Date(updatedTrendCursorDateString);
const initialDate = parse(
`${initialTrendCursorDateString.split('\n').join(' ')}`,
'dd/MM/yyyy HH:mm:ss',
new Date()
);
const updatedDate = parse(
`${updatedTrendCursorDateString.split('\n').join(' ')}`,
'dd/MM/yyyy HH:mm:ss',
new Date()
);
expect(initialDate.getTime()).toBeGreaterThan(updatedDate.getTime());

// trend cursor should have some value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { AssetSummary } from '@aws-sdk/client-iotsitewise';
import { type TableProps } from '@cloudscape-design/components/table';
import React from 'react';

import { DateTime } from '@iot-app-kit/react-components';
import type { AssetTableNameLinkProps } from './assetTableNameLink';
import { getFormattedDateTime } from '~/components/util/dateTimeUtil';

type AssetTableColumnDefinitions =
TableProps<AssetSummary>['columnDefinitions'];
Expand Down Expand Up @@ -87,7 +87,7 @@ export class AssetTableColumnDefinitionsFactory {
id: 'creationDate',
header: 'Creation Date',
cell: ({ creationDate }) =>
creationDate ? getFormattedDateTime(creationDate) : '-',
creationDate ? <DateTime dateTime={creationDate.getTime()} /> : '-',
sortingField: 'creationDate',
};
}
Expand All @@ -97,7 +97,7 @@ export class AssetTableColumnDefinitionsFactory {
id: 'lastUpdateDate',
header: 'Last Update Date',
cell: ({ lastUpdateDate }) =>
lastUpdateDate ? getFormattedDateTime(lastUpdateDate) : '-',
lastUpdateDate ? <DateTime dateTime={lastUpdateDate.getTime()} /> : '-',
sortingField: 'lastUpdateDate',
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import { isNumeric, round } from '@iot-app-kit/core-util';
import { DateTime } from '@iot-app-kit/react-components';
import { type TableProps } from '@cloudscape-design/components/table';
import type { ModeledDataStream } from '../types';
import { getFormattedDateTimeFromEpoch } from '~/components/util/dateTimeUtil';

export function createModeledDataStreamColumnDefinitions(
significantDigits: number
Expand Down Expand Up @@ -33,12 +34,17 @@ export function createModeledDataStreamColumnDefinitions(
id: 'latestValueTime',
header: 'Latest value time',
cell: ({ latestValueTime }) => {
if (!latestValueTime) return '-';
if (latestValueTime && isNumeric(latestValueTime)) {
return getFormattedDateTimeFromEpoch(
Number(round(latestValueTime, significantDigits))
return (
<DateTime
dateTime={
Number(round(latestValueTime, significantDigits)) * 1000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're rounding the date?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes.

}
/>
);
}
return getFormattedDateTimeFromEpoch(latestValueTime);
return <DateTime dateTime={latestValueTime * 1000} />;
},
sortingField: 'latestValueTime',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from 'react';
import { useSelector } from 'react-redux';
import { type IoTSiteWiseClient } from '@aws-sdk/client-iotsitewise';
import { isNumeric, round } from '@iot-app-kit/core-util';
import { getPlugin } from '@iot-app-kit/core';
import { DateTime } from '@iot-app-kit/react-components';

import { useCollection } from '@cloudscape-design/collection-hooks';
import Box from '@cloudscape-design/components/box';
Expand All @@ -16,10 +18,8 @@ import { useExplorerPreferences } from '../../useExplorerPreferences';
import { SUPPORTED_PAGE_SIZES } from '../../constants';
import { useLatestValues } from '../../useLatestValues';
import { DashboardState } from '~/store/state';
import { getFormattedDateTimeFromEpoch } from '~/components/util/dateTimeUtil';
import { ResourceExplorerFooter } from '../../footer/footer';
import { getPlugin } from '@iot-app-kit/core';
import { disableAdd } from '~/components/queryEditor/iotSiteWiseQueryEditor/footer/disableAdd';
import { ResourceExplorerFooter } from '../../footer/footer';

export interface UnmodeledDataStreamTableProps {
onClickAdd: (unmodeledDataStreams: UnmodeledDataStream[]) => void;
Expand Down Expand Up @@ -162,12 +162,17 @@ export function UnmodeledDataStreamTable({
id: 'latestValueTime',
header: 'Latest value time',
cell: ({ latestValueTime }) => {
if (!latestValueTime) return '-';
if (latestValueTime && isNumeric(latestValueTime)) {
return getFormattedDateTimeFromEpoch(
Number(round(latestValueTime, significantDigits))
return (
<DateTime
dateTime={
Number(round(latestValueTime, significantDigits)) * 1000
}
/>
);
}
return getFormattedDateTimeFromEpoch(latestValueTime);
return <DateTime dateTime={latestValueTime * 1000} />;
},
sortingField: 'latestValueTime',
},
Expand Down
1 change: 1 addition & 0 deletions packages/react-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
"d3-format": "^3.1.0",
"d3-shape": "^3.2.0",
"date-fns": "^3.4.0",
"date-fns-tz": "^2.0.1",
"dompurify": "3.0.5",
"echarts": "^5.4.3",
"is-hotkey": "^0.2.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react';
import { format } from 'date-fns';
import { fontWeightHeadingS } from '@cloudscape-design/design-tokens';
import { FULL_DATE } from '../../../../utils/time';
import { DateTime } from '../../../timeZone';

export type XYPlotTooltipTimeOptions = {
time?: number;
};
export const XYPlotTooltipTime = ({ time }: XYPlotTooltipTimeOptions) => (
<span style={{ fontWeight: fontWeightHeadingS }}>
{time ? format(new Date(time), FULL_DATE) : ''}
{time ? <DateTime dateTime={time} pattern={FULL_DATE} /> : ''}
</span>
);
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const createTrendCursorColumnDefinition = ({
date,
}: TrendCursor): LegendTableColumnDefinitions[number] => ({
id: trendCursorId,
header: <TrendCursorColumnHeader color={color} date={new Date(date)} />,
header: <TrendCursorColumnHeader color={color} date={date} />,
sortingComparator: (a, b) => {
const aValue = a.trendCursorValues[trendCursorId] ?? 0;
const bValue = b.trendCursorValues[trendCursorId] ?? 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import React from 'react';
import { parse, format } from 'date-fns';
import { useDateTime } from '../../../../../timeZone';
import { FULL_DATE_TIME } from '../../../../../../utils/time';

type TrendCursorColumnHeaderOptions = {
date: Date;
date: number;
color?: string;
};

export const TrendCursorColumnHeader = ({
date,
color,
}: TrendCursorColumnHeaderOptions) => {
const dateTime = useDateTime(date, FULL_DATE_TIME.replace(',', ''));
const parsedDate = parse(dateTime, 'dd/MM/yyyy HH:mm:ss', new Date());
return (
<div className='base-chart-legend-tc-header-container'>
<div>
<span>{date.toLocaleDateString()}</span>
<span>{format(parsedDate, 'dd/MM/yyyy')}</span>
<br />
<span>{date.toLocaleTimeString()}</span>
<span>{format(parsedDate, 'hh:mm:ss')}</span>
</div>
<div
className='base-chart-legend-tc-header-color'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { render, renderHook, screen } from '@testing-library/react';
import { format } from 'date-fns-tz';
import { ChartLegendTable } from './table';
import { DataStreamInformation, TrendCursor } from './types';
import { useChartStore } from '../../store';
Expand Down Expand Up @@ -90,10 +91,12 @@ describe('legend table', () => {

expect(table).not.toBeNull();
expect(
screen.getByText(new Date(trendCursors[0].date).toLocaleTimeString())
screen
.getAllByText(format(new Date(trendCursors[0].date), 'dd/MM/yyyy'))
.at(0)
).not.toBeNull();
expect(
screen.getByText(new Date(trendCursors[1].date).toLocaleTimeString())
screen.getByText(format(new Date(trendCursors[1].date), 'hh:mm:ss'))
).not.toBeNull();

expect(screen.getByText('111')).not.toBeNull();
Expand Down
4 changes: 3 additions & 1 deletion packages/react-components/src/components/kpi/kpi.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { mockTimeSeriesDataQuery } from '@iot-app-kit/testing-util';
import { format } from 'date-fns-tz';
import { KPI } from './kpi';
import { FULL_DATE_TIME } from '../../utils/time';

const VIEWPORT = { duration: '5m' };

Expand Down Expand Up @@ -35,6 +37,6 @@ it('renders', async () => {
`${DATA_STREAM.data[0].y} `
);
expect(screen.getByTestId('kpi-timestamp').textContent).toContain(
new Date(DATA_STREAM.data[0].x).toLocaleString()
format(new Date(DATA_STREAM.data[0].x), FULL_DATE_TIME)
);
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from 'react';
import { format } from 'date-fns-tz';
import { render, screen } from '@testing-library/react';
import { KpiBase } from './kpiBase';
import type { DataPoint } from '@iot-app-kit/core';
import { FULL_DATE_TIME } from '../../utils/time';

describe('name', () => {
it('renders name when showName is true', () => {
Expand Down Expand Up @@ -149,7 +151,7 @@ describe('timestamp', () => {
);

expect(
screen.queryByText(PROPERTY_POINT_DATE.toLocaleString())
screen.queryByText(format(PROPERTY_POINT_DATE, FULL_DATE_TIME))
).not.toBeNull();
});

Expand Down
3 changes: 2 additions & 1 deletion packages/react-components/src/components/kpi/kpiBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
fontSizeBodyS,
} from '@cloudscape-design/design-tokens';
import { DataQualityText } from '../data-quality/data-quality-text';
import { DateTime } from '../timeZone';

export const KpiBase: React.FC<KPIBaseProperties> = ({
propertyPoint,
Expand Down Expand Up @@ -138,7 +139,7 @@ export const KpiBase: React.FC<KPIBaseProperties> = ({
}}
/>
<div className='timestamp' data-testid='kpi-timestamp'>
{isLoading ? '-' : new Date(point.x).toLocaleString()}
{isLoading ? '-' : <DateTime dateTime={point.x} />}
</div>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export function InternalAssetExplorer({
const tableResourceDefinition =
customTableResourceDefinition ??
createDefaultAssetTableDefinition((asset) => {
if ((asset.hierarchies ?? []).length > 0) {
if ((asset.hierarchies ?? []).length > 0 && parameters === undefined) {
return (
<Link onFollow={() => onClickAssetName(asset)}>{asset.name}</Link>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ export function useAssets({
const shouldRequestAssetModelAssets =
!shouldRequestChildAssets && isEveryAssetModelAssetsParameters(parameters);
const shouldRequestRootAssets =
!shouldRequestAssetModelAssets && !shouldRequestChildAssets;
!shouldRequestAssetModelAssets &&
!shouldRequestChildAssets &&
parameters === undefined;

const assetSearchResult = useAssetSearch({
parameters: shouldRequestSearchedAssets ? parameters : [],
Expand Down Expand Up @@ -85,7 +87,15 @@ export function useAssets({
? assetModelAssetsQueryResult
: shouldRequestChildAssets
? childAssetsQueryResult
: rootAssetsQueryResult;
: shouldRequestRootAssets
? rootAssetsQueryResult
: {
assets: [],
isLoading: false,
error: undefined,
hasNextPage: false,
nextPage: () => {},
};

return queryResult;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { DEFAULT_TIME_SERIES_DROP_DOWN_DEFINITION } from '../../constants/drop-d

export function InternalTimeSeriesExplorer({
requestFns,
parameters = [],
parameters = [{}],
resourceName = DEFAULT_TIME_SERIES_RESOURCE_NAME,
pluralResourceName = DEFAULT_PLURAL_TIME_SERIES_RESOURCE_NAME,
isTimeSeriesDisabled = DEFAULT_IS_RESOURCE_DISABLED,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type Parameters = readonly unknown[];

export type QueryKey = readonly [
{
resourceId: string;
allParameters: Parameters;
currentParameters: Parameters[number];
}
];
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import { useQueryClient } from '@tanstack/react-query';

import type { QueryKey } from './types';
import { resourceExplorerQueryClient } from '../resource-explorer-query-client';

export interface UseCachedResourcesOptions {
resourceId: string;
allParameters: readonly unknown[];
}

export type UseCachedResourcesResult<Resource> = Resource[];

/** Use resources loaded into the cache. */
export function useCachedResources<Resource>({
resourceId,
allParameters,
}: UseCachedResourcesOptions): UseCachedResourcesResult<Resource> {
const queryClient = useQueryClient(resourceExplorerQueryClient);

const resourcePages = queryClient.getQueriesData<Resource[]>({
queryKey: [{ allParameters }],
queryKey: [{ resourceId, allParameters }],
// Further filter the data to prevent partial matching on allParameters
predicate: (query) => {
return (
JSON.stringify((query.queryKey as QueryKey)[0].allParameters) ===
JSON.stringify(allParameters)
);
},
});

const resources = resourcePages.flatMap(([_, resources = []]) => resources);

return resources;
Expand Down
Loading
Loading