Skip to content

Commit

Permalink
[Discover] Display Cache Time and Clear Cache Button (#8214)
Browse files Browse the repository at this point in the history
* initial commit for cache time and clearing cache

Signed-off-by: Sean Li <[email protected]>

* Changeset file for PR #8214 created/updated

* updating UI to address some comments

Signed-off-by: Sean Li <[email protected]>

* addressing comments, adding tests

Signed-off-by: Sean Li <[email protected]>

* removing dynamic default message, following i18n best practice

Signed-off-by: Sean Li <[email protected]>

---------

Signed-off-by: Sean Li <[email protected]>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
  • Loading branch information
sejli and opensearch-changeset-bot[bot] authored Oct 1, 2024
1 parent 0831c99 commit a7f3e9d
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 51 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/8214.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- Add last updated time and cache refresh button to Discover Advanced Dataset Selector ([#8214](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8214))
4 changes: 4 additions & 0 deletions src/plugins/data/common/storage/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ export class DataStorage {
if (ourKey != null) ours.push(ourKey);
});
}

clear(): void {
this.engine.clear();
}
}

export function createStorage(deps: { engine: IStorageEngine; prefix: string }) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,26 @@ describe('DatasetService', () => {
service = new DatasetService(uiSettings, sessionStorage);
});

test('registerType and getType', () => {
const mockType = {
id: 'test-type',
title: 'Test Type',
meta: { icon: { type: 'test' } },
toDataset: jest.fn(),
fetch: jest.fn(),
fetchFields: jest.fn(),
supportedLanguages: jest.fn(),
};
const mockResult = {
id: 'test-structure',
title: 'Test Structure',
type: 'test-type',
children: [{ id: 'child1', title: 'Child 1', type: 'test-type' }],
};

const mockPath: DataStructure[] = [{ id: 'root', title: 'Root', type: 'root' }];

const mockType = {
id: 'test-type',
title: 'Test Type',
meta: { icon: { type: 'test' } },
toDataset: jest.fn(),
fetch: jest.fn().mockResolvedValue(mockResult),
fetchFields: jest.fn(),
supportedLanguages: jest.fn(),
};

test('registerType and getType', () => {
service.registerType(mockType);
expect(service.getType('test-type')).toBe(mockType);
});
Expand All @@ -52,25 +61,9 @@ describe('DatasetService', () => {
});

test('fetchOptions caches and returns data structures', async () => {
const mockType = {
id: 'test-type',
title: 'Test Type',
meta: { icon: { type: 'test' } },
toDataset: jest.fn(),
fetch: jest.fn().mockResolvedValue({
id: 'test-structure',
title: 'Test Structure',
type: 'test-type',
children: [{ id: 'child1', title: 'Child 1', type: 'test-type' }],
}),
fetchFields: jest.fn(),
supportedLanguages: jest.fn(),
};

service.registerType(mockType);

const path: DataStructure[] = [{ id: 'root', title: 'Root', type: 'root' }];
const result = await service.fetchOptions(mockDataPluginServices, path, 'test-type');
const result = await service.fetchOptions(mockDataPluginServices, mockPath, 'test-type');

expect(result).toEqual({
id: 'test-structure',
Expand All @@ -79,8 +72,30 @@ describe('DatasetService', () => {
children: [{ id: 'child1', title: 'Child 1', type: 'test-type' }],
});

const cachedResult = await service.fetchOptions(mockDataPluginServices, path, 'test-type');
const cachedResult = await service.fetchOptions(mockDataPluginServices, mockPath, 'test-type');
expect(cachedResult).toEqual(result);
expect(mockType.fetch).toHaveBeenCalledTimes(2);
});

test('clear cache', async () => {
service.registerType(mockType);

await service.fetchOptions(mockDataPluginServices, mockPath, 'test-type');
expect(sessionStorage.keys().length === 1);

service.clearCache();
expect(sessionStorage.keys().length === 0);
});

test('caching object correctly sets last cache time', async () => {
service.registerType(mockType);

const time = Date.now();

Date.now = jest.fn(() => time);

await service.fetchOptions(mockDataPluginServices, mockPath, 'test-type');

expect(service.getLastCacheTime()).toEqual(time);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export class DatasetService {
}

private cacheDataStructure(dataType: string, dataStructure: DataStructure) {
this.setLastCacheTime(Date.now());
const cachedDataStructure: CachedDataStructure = {
id: dataStructure.id,
title: dataStructure.title,
Expand All @@ -164,6 +165,18 @@ export class DatasetService {
});
}

public clearCache(): void {
this.sessionStorage.clear();
}

public getLastCacheTime(): number | undefined {
return Number(this.sessionStorage.get('lastCacheTime')) || undefined;
}

private setLastCacheTime(time: number): void {
this.sessionStorage.set('lastCacheTime', time);
}

private async fetchDefaultDataset(): Promise<Dataset | undefined> {
const defaultIndexPatternId = this.uiSettings.get('defaultIndex');
if (!defaultIndexPatternId) {
Expand Down
91 changes: 68 additions & 23 deletions src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import React, { useState } from 'react';
import {
EuiButton,
EuiButtonEmpty,
EuiFlexGroup,
EuiFlexItem,
EuiIcon,
EuiLink,
EuiModalBody,
Expand All @@ -19,6 +21,7 @@ import {
EuiToolTip,
} from '@elastic/eui';
import { FormattedMessage } from '@osd/i18n/react';
import moment from 'moment';
import { BaseDataset, DATA_STRUCTURE_META_TYPES, DataStructure } from '../../../common';
import { QueryStringContract } from '../../query';
import { IDataPluginServices } from '../../types';
Expand All @@ -38,6 +41,7 @@ export const DatasetExplorer = ({
onNext: (dataset: BaseDataset) => void;
onCancel: () => void;
}) => {
const uiSettings = services.uiSettings;
const [explorerDataset, setExplorerDataset] = useState<BaseDataset | undefined>(undefined);
const [loading, setLoading] = useState<boolean>(false);

Expand Down Expand Up @@ -68,31 +72,72 @@ export const DatasetExplorer = ({
return (
<>
<EuiModalHeader>
<EuiModalHeaderTitle>
<h1>
<FormattedMessage
id="data.explorer.datasetSelector.advancedSelector.title.step1"
defaultMessage="Step 1: Select data"
/>
</h1>
<EuiText>
<p>
<FormattedMessage
id="data.explorer.datasetSelector.advancedSelector.description"
defaultMessage="Select from those available to you. "
/>
<EuiLink
href={`${services.http.basePath.get()}/app/management/opensearch-dashboards/dataSources`}
target="_blank"
>
<EuiFlexGroup alignItems="center" justifyContent="flexEnd" gutterSize="s">
<EuiFlexItem grow={true}>
<EuiModalHeaderTitle>
<h1>
<FormattedMessage
id="data.explorer.datasetSelector.advancedSelector.dataSourceManagement.title"
defaultMessage="Manage data sources"
id="data.explorer.datasetSelector.advancedSelector.title.step1"
defaultMessage="Step 1: Select data"
/>
</EuiLink>
</p>
</EuiText>
</EuiModalHeaderTitle>
</h1>
<EuiText>
<p>
<FormattedMessage
id="data.explorer.datasetSelector.advancedSelector.description"
defaultMessage="Select from those available to you. "
/>
<EuiLink
href={`${services.http.basePath.get()}/app/management/opensearch-dashboards/dataSources`}
target="_blank"
>
<FormattedMessage
id="data.explorer.datasetSelector.advancedSelector.dataSourceManagement.title"
defaultMessage="Manage data sources"
/>
</EuiLink>
</p>
</EuiText>
</EuiModalHeaderTitle>
</EuiFlexItem>
{queryString.getDatasetService().getLastCacheTime() && (
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs">
<EuiFlexItem grow={false}>
<EuiText size="s">
<FormattedMessage
id="data.explorer.datasetSelector.advancedSelector.lastUpdatedTime"
defaultMessage={'Last updated at: {timestamp}. '}
values={{
timestamp: moment(queryString.getDatasetService().getLastCacheTime())
.format(uiSettings.get('dateFormat'))
.toString(),
}}
/>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
onClick={() => {
queryString.getDatasetService().clearCache();
onCancel();
}}
size="xs"
iconSide="left"
iconType="refresh"
iconGap="s"
flush="both"
>
<FormattedMessage
id="data.explorer.datasetSelector.advancedSelector.refreshCacheButton"
defaultMessage="Refresh Cache"
/>
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
)}
</EuiFlexGroup>
</EuiModalHeader>
<EuiModalBody>
<div
Expand Down

0 comments on commit a7f3e9d

Please sign in to comment.