diff --git a/changelogs/fragments/8900.yml b/changelogs/fragments/8900.yml
new file mode 100644
index 000000000000..78ae369755a7
--- /dev/null
+++ b/changelogs/fragments/8900.yml
@@ -0,0 +1,2 @@
+feat:
+- Optimize recent items and filter out items whose workspace is deleted ([#8900](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8900))
\ No newline at end of file
diff --git a/src/core/public/chrome/ui/header/recent_items.test.tsx b/src/core/public/chrome/ui/header/recent_items.test.tsx
index d01912e9c27f..28bae880fcfa 100644
--- a/src/core/public/chrome/ui/header/recent_items.test.tsx
+++ b/src/core/public/chrome/ui/header/recent_items.test.tsx
@@ -18,7 +18,7 @@ jest.mock('./nav_link', () => ({
}),
}));
-const mockRecentlyAccessed = new BehaviorSubject([
+const mockRecentlyAccessed$ = new BehaviorSubject([
{
id: '6ef856c0-5f86-11ef-b7df-1bb1cf26ce5b',
label: 'visualizeMock',
@@ -28,7 +28,7 @@ const mockRecentlyAccessed = new BehaviorSubject([
},
]);
-const mockWorkspaceList = new BehaviorSubject([
+const mockWorkspaceList$ = new BehaviorSubject([
{
id: 'workspace_1',
name: 'WorkspaceMock_1',
@@ -49,7 +49,14 @@ const defaultMockProps = {
navigateToUrl: applicationServiceMock.createStartContract().navigateToUrl,
workspaceList$: new BehaviorSubject([]),
recentlyAccessed$: new BehaviorSubject([]),
- navLinks$: new BehaviorSubject([]),
+ navLinks$: new BehaviorSubject([
+ {
+ id: '',
+ title: '',
+ baseUrl: '',
+ href: '',
+ },
+ ]),
basePath: httpServiceMock.createStartContract().basePath,
http: httpServiceMock.createSetupContract(),
renderBreadcrumbs: <>>,
@@ -85,7 +92,8 @@ describe('Recent items', () => {
it('should be able to render recent works', async () => {
const mockProps = {
...defaultMockProps,
- recentlyAccessed$: mockRecentlyAccessed,
+ recentlyAccessed$: mockRecentlyAccessed$,
+ workspaceList$: mockWorkspaceList$,
};
await act(async () => {
@@ -97,11 +105,11 @@ describe('Recent items', () => {
expect(screen.getByText('visualizeMock')).toBeInTheDocument();
});
- it('shoulde be able to display workspace name if the asset is attched to a workspace and render it with brackets wrapper ', async () => {
+ it('should be able to display workspace name if the asset is attched to a workspace and render it with brackets wrapper ', async () => {
const mockProps = {
...defaultMockProps,
- recentlyAccessed$: mockRecentlyAccessed,
- workspaceList$: mockWorkspaceList,
+ recentlyAccessed$: mockRecentlyAccessed$,
+ workspaceList$: mockWorkspaceList$,
};
await act(async () => {
@@ -116,8 +124,8 @@ describe('Recent items', () => {
it('should call navigateToUrl with link generated from createRecentNavLink when clicking a recent item', async () => {
const mockProps = {
...defaultMockProps,
- recentlyAccessed$: mockRecentlyAccessed,
- workspaceList$: mockWorkspaceList,
+ recentlyAccessed$: mockRecentlyAccessed$,
+ workspaceList$: mockWorkspaceList$,
};
const navigateToUrl = jest.fn();
@@ -137,7 +145,7 @@ describe('Recent items', () => {
it('should be able to display the preferences popover setting when clicking Preferences button', async () => {
const mockProps = {
...defaultMockProps,
- recentlyAccessed$: mockRecentlyAccessed,
+ recentlyAccessed$: mockRecentlyAccessed$,
};
await act(async () => {
@@ -158,4 +166,9 @@ describe('Recent items', () => {
);
expect(baseElement).toMatchSnapshot();
});
+
+ it('should show not display item if it is in a workspace which is not available', () => {
+ render();
+ expect(screen.queryByText('visualizeMock')).not.toBeInTheDocument();
+ });
});
diff --git a/src/core/public/chrome/ui/header/recent_items.tsx b/src/core/public/chrome/ui/header/recent_items.tsx
index 7efd276b8fa9..298bf51d2bc6 100644
--- a/src/core/public/chrome/ui/header/recent_items.tsx
+++ b/src/core/public/chrome/ui/header/recent_items.tsx
@@ -143,7 +143,9 @@ export const RecentItems = ({
setIsPreferencesPopoverOpen((IsPreferencesPopoverOpe) => !IsPreferencesPopoverOpe);
}}
>
- Preferences
+ {i18n.translate('core.header.recent.preferences', {
+ defaultMessage: 'Preferences',
+ })}
}
isOpen={isPreferencesPopoverOpen}
@@ -152,7 +154,11 @@ export const RecentItems = ({
setIsPreferencesPopoverOpen(false);
}}
>
- Preferences
+
+ {i18n.translate('core.header.recent.preferences.title', {
+ defaultMessage: 'Preferences',
+ })}
+
Recents,
+ children: (
+
+ {i18n.translate('core.header.recent.preferences.legend', {
+ defaultMessage: 'Recents',
+ })}
+
+ ),
}}
/>
@@ -208,15 +220,20 @@ export const RecentItems = ({
useEffect(() => {
const savedObjects = recentlyAccessedItems
- .filter((item) => item.meta?.type)
+ .filter(
+ (item) =>
+ item.meta?.type &&
+ (!item.workspaceId ||
+ // If the workspace id is existing but the workspace is deleted, filter the item
+ (item.workspaceId &&
+ !!workspaceList.find((workspace) => workspace.id === item.workspaceId)))
+ )
.map((item) => ({
type: item.meta?.type || '',
id: item.id,
}));
-
if (savedObjects.length) {
bulkGetDetail(savedObjects, http).then((res) => {
- const filteredNavLinks = navLinks.filter((link) => !link.hidden);
const formatDetailedSavedObjects = res.map((obj) => {
const recentAccessItem = recentlyAccessedItems.find(
(item) => item.id === obj.id
@@ -225,33 +242,21 @@ export const RecentItems = ({
const findWorkspace = workspaceList.find(
(workspace) => workspace.id === recentAccessItem.workspaceId
);
+
return {
...recentAccessItem,
...obj,
...recentAccessItem.meta,
updatedAt: moment(obj?.updated_at).valueOf(),
workspaceName: findWorkspace?.name,
- link: createRecentNavLink(recentAccessItem, filteredNavLinks, basePath, navigateToUrl)
- .href,
};
});
- // here I write this argument to avoid Unnecessary re-rendering
- if (JSON.stringify(formatDetailedSavedObjects) !== JSON.stringify(detailedSavedObjects)) {
- setDetailedSavedObjects(formatDetailedSavedObjects);
- }
+ setDetailedSavedObjects(formatDetailedSavedObjects);
});
}
- }, [
- navLinks,
- basePath,
- navigateToUrl,
- recentlyAccessedItems,
- http,
- workspaceList,
- detailedSavedObjects,
- ]);
+ }, [recentlyAccessedItems, http, workspaceList]);
- const selectedRecentsItems = useMemo(() => {
+ const selectedRecentItems = useMemo(() => {
return detailedSavedObjects.slice(0, Number(recentsRadioIdSelected));
}, [detailedSavedObjects, recentsRadioIdSelected]);
@@ -283,11 +288,20 @@ export const RecentItems = ({
- {selectedRecentsItems.length > 0 ? (
+ {selectedRecentItems.length > 0 ? (
- {selectedRecentsItems.map((item) => (
+ {selectedRecentItems.map((item) => (
handleItemClick(item.link)}
+ onClick={() =>
+ handleItemClick(
+ createRecentNavLink(
+ item,
+ navLinks.filter((link) => !link.hidden),
+ basePath,
+ navigateToUrl
+ ).href
+ )
+ }
key={item.link}
style={{ padding: '1px' }}
label={
@@ -309,7 +323,9 @@ export const RecentItems = ({
) : (
- No recently viewed items
+ {i18n.translate('core.header.recent.no.recents', {
+ defaultMessage: 'No recently viewed items',
+ })}
)}