Skip to content

Commit

Permalink
[navigation-next] feat: add recent works in new homepage (#7237) (#7362)
Browse files Browse the repository at this point in the history
* Changeset file for PR #7237 created/updated

* feat: remove the euispacer

* feat: update empty state

* feat: update i18n key

* feat: update

---------

(cherry picked from commit 46afb96)

Signed-off-by: SuZhou-Joe <[email protected]>
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
(cherry picked from commit d89447b)
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
1 parent d59e3ea commit 7d97386
Show file tree
Hide file tree
Showing 20 changed files with 479 additions and 10 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/7237.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- [navigation-next] add recent works in new homepage ([#7237](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7237))
7 changes: 6 additions & 1 deletion src/core/public/chrome/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ export {
ChromeHelpExtensionMenuDocumentationLink,
ChromeHelpExtensionMenuGitHubLink,
} from './ui/header/header_help_menu';
export { NavType, RightNavigationButton, RightNavigationButtonProps } from './ui';
export {
NavType,
RightNavigationButton,
RightNavigationButtonProps,
createRecentNavLink,
} from './ui';
export { ChromeNavLink, ChromeNavLinks, ChromeNavLinkUpdateableFields } from './nav_links';
export {
ChromeRecentlyAccessed,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ export interface ChromeRecentlyAccessedHistoryItem {
label: string;
id: string;
workspaceId?: string;
meta?: {
type?: string;
lastAccessedTime?: number;
};
}

interface StartDeps {
Expand All @@ -59,14 +63,20 @@ export class RecentlyAccessedService {

return {
/** Adds a new item to the history. */
add: (link: string, label: string, id: string) => {
add: (
link: string,
label: string,
id: string,
meta?: ChromeRecentlyAccessedHistoryItem['meta']
) => {
const currentWorkspaceId = workspaces.currentWorkspaceId$.getValue();

history.add({
link,
label,
id,
...(currentWorkspaceId && { workspaceId: currentWorkspaceId }),
...(meta && { meta: { lastAccessedTime: Date.now(), ...meta } }),
});
},

Expand Down Expand Up @@ -96,7 +106,12 @@ export interface ChromeRecentlyAccessed {
* @param label the label to display in the UI
* @param id a unique string used to de-duplicate the recently accessed list.
*/
add(link: string, label: string, id: string): void;
add(
link: string,
label: string,
id: string,
meta?: ChromeRecentlyAccessedHistoryItem['meta']
): void;

/**
* Gets an Array of the current recently accessed history.
Expand Down
1 change: 1 addition & 0 deletions src/core/public/chrome/ui/header/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ export {
ChromeHelpExtensionMenuGitHubLink,
} from './header_help_menu';
export { RightNavigationButton, RightNavigationButtonProps } from './right_navigation_button';
export { createRecentNavLink } from './nav_link';
1 change: 1 addition & 0 deletions src/core/public/chrome/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ export {
NavType,
RightNavigationButton,
RightNavigationButtonProps,
createRecentNavLink,
} from './header';
2 changes: 2 additions & 0 deletions src/core/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import {
PersistedLog,
NavGroupItemInMap,
fulfillRegistrationLinksToChromeNavLinks,
createRecentNavLink,
} from './chrome';
import { FatalErrorsSetup, FatalErrorsStart, FatalErrorInfo } from './fatal_errors';
import { HttpSetup, HttpStart } from './http';
Expand Down Expand Up @@ -379,6 +380,7 @@ export {
PersistedLog,
NavGroupItemInMap,
fulfillRegistrationLinksToChromeNavLinks,
createRecentNavLink,
};

export { __osdBootstrap__ } from './osd_bootstrap';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ describe('useSavedDashboardInstance', () => {
getFilters: () => dashboardAppStateStub.filters,
optionsJSON: JSON.stringify(dashboardAppStateStub.options),
getFullPath: () => `/${dashboardIdFromUrl}`,
getOpenSearchType: () => 'dashboard',
},
} as unknown) as SavedObjectDashboard;
dashboard = new Dashboard(convertToSerializedDashboard(savedDashboardInstance));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ export const useSavedDashboardInstance = ({
chrome.recentlyAccessed.add(
savedDashboard.getFullPath(),
savedDashboard.title,
dashboardIdFromUrl
dashboardIdFromUrl,
{ type: savedDashboard.getOpenSearchType() }
);
setSavedDashboardInstance(dashboardInstance);
} catch (error: any) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,10 @@ export const useSearch = (services: DiscoverViewServices) => {
chrome.recentlyAccessed.add(
savedSearchInstance.getFullPath(),
savedSearchInstance.title,
savedSearchInstance.id
savedSearchInstance.id,
{
type: savedSearchInstance.getOpenSearchType(),
}
);
}
})();
Expand Down
9 changes: 8 additions & 1 deletion src/plugins/discover/public/saved_searches/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,14 @@ export type SortOrder = [string, SortDirection];
export interface SavedSearch
extends Pick<
SavedObject,
'id' | 'title' | 'copyOnSave' | 'destroy' | 'lastSavedTitle' | 'save' | 'getFullPath'
| 'id'
| 'title'
| 'copyOnSave'
| 'destroy'
| 'lastSavedTitle'
| 'save'
| 'getFullPath'
| 'getOpenSearchType'
> {
searchSource: ISearchSource; // This is optional in SavedObject, but required for SavedSearch
description?: string;
Expand Down
14 changes: 13 additions & 1 deletion src/plugins/home/public/application/home_render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,19 @@ export const setupHome = (contentManagement: ContentManagementPluginSetup) => {
order: 2000,
title: 'Recently viewed',
kind: 'custom',
render: () => <></>,
render: (contents) => {
return (

Check warning on line 30 in src/plugins/home/public/application/home_render.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/home/public/application/home_render.tsx#L30

Added line #L30 was not covered by tests
<>
{contents.map((content) => {
if (content.kind === 'custom') {
return content.render();

Check warning on line 34 in src/plugins/home/public/application/home_render.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/home/public/application/home_render.tsx#L34

Added line #L34 was not covered by tests
}

return null;

Check warning on line 37 in src/plugins/home/public/application/home_render.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/home/public/application/home_render.tsx#L37

Added line #L37 was not covered by tests
})}
</>
);
},
},
{
id: SECTIONS.GET_STARTED,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ export async function saveSavedObject(
chrome.recentlyAccessed.add(
savedObject.getFullPath(),
savedObject.title,
String(savedObject.id)
String(savedObject.id),
{
type: savedObject.getOpenSearchType(),
}
);
}
savedObject.isSaving = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"visBuilder",
"visAugmenter",
"dataSource",
"dataSourceManagement"
"dataSourceManagement",
"contentManagement"
],
"extraPublicDirs": ["public/lib"],
"requiredBundles": ["opensearchDashboardsReact", "home"]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { BehaviorSubject } from 'rxjs';
import { fireEvent, render } from '@testing-library/react';
import { RecentWork } from './recent_work';
import { coreMock } from '../../../../core/public/mocks';
import { ChromeRecentlyAccessedHistoryItem } from 'opensearch-dashboards/public';
import { SavedObjectWithMetadata } from '../types';

const mockedRecentItems: ChromeRecentlyAccessedHistoryItem[] = [
{
link: '/app/visualize',
label: 'visualize',
id: 'visualize',
meta: {
type: 'visualize',
},
},
{
link: '/app/dashboard',
label: 'dashboard',
id: 'dashboard-in-workspace',
workspaceId: 'workspace-id',
meta: {
type: 'dashboard',
},
},
];

const savedObjectsFromServer: SavedObjectWithMetadata[] = [
{
type: 'visualize',
id: 'visualize',
attributes: {},
references: [],
updated_at: '2024-07-20T00:00:00.000Z',
meta: {},
},
{
type: 'dashboard',
id: 'dashboard-in-workspace',
attributes: {},
references: [],
updated_at: '2024-07-20T00:00:01.000Z',
meta: {},
},
];

const getStartMockForRecentWork = () => {
const coreStartMock = coreMock.createStart();
coreStartMock.chrome.recentlyAccessed.get$.mockReturnValue(new BehaviorSubject([]));
coreStartMock.chrome.navLinks.getNavLinks$.mockReturnValue(new BehaviorSubject([]));
return coreStartMock;
};

describe('<RecentWork />', () => {
it('render with emty recent work', async () => {
const { findByText } = render(<RecentWork core={getStartMockForRecentWork()} />);
await findByText('No recent work');
});

it('render with recent works', async () => {
const coreStartMock = getStartMockForRecentWork();
coreStartMock.http.get.mockImplementation((url) => {
if (typeof url === 'string') {
if ((url as string).includes(mockedRecentItems[0].id)) {
return Promise.resolve(savedObjectsFromServer[0]);
} else {
return Promise.resolve(savedObjectsFromServer[1]);
}
}

return Promise.reject({});
});

coreStartMock.chrome.recentlyAccessed.get$.mockReturnValue(
new BehaviorSubject(mockedRecentItems)
);

const { findAllByTestId, getByTestId } = render(<RecentWork core={coreStartMock} />);
const allCards = await findAllByTestId('recentlyCard');
expect(allCards.length).toBe(2);
expect(allCards[0].querySelector('.euiCard__titleAnchor')?.textContent).toEqual(
mockedRecentItems[0].label
);

// click the filter button
fireEvent.click(getByTestId('filterButton-recently%20updated'));
const allCardsAfterSort = await findAllByTestId('recentlyCard');
expect(allCardsAfterSort[0].querySelector('.euiCard__titleAnchor')?.textContent).toEqual(
mockedRecentItems[1].label
);
});
});
Loading

0 comments on commit 7d97386

Please sign in to comment.