From 15a19faa287fcf3bff1bce5b3a0d8eacad9e3803 Mon Sep 17 00:00:00 2001 From: Qxisylolo Date: Mon, 6 Jan 2025 10:03:10 +0800 Subject: [PATCH] [Workspace] fix:Prevent user from visiting dashboards / visualizations when out of a workspace (#9024) * add workspaceAvailability Signed-off-by: Qxisylolo * Changeset file for PR #9024 created/updated * add tests Signed-off-by: Qxisylolo * update test Signed-off-by: Qxisylolo * fix test use piple Signed-off-by: Qxisylolo * fix test new Signed-off-by: Qxisylolo --------- Signed-off-by: Qxisylolo Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/9024.yml | 2 ++ src/plugins/dashboard/public/plugin.tsx | 10 ++++--- src/plugins/visualize/public/plugin.ts | 2 ++ src/plugins/workspace/public/plugin.test.ts | 30 ++++++++++++++++++++- src/plugins/workspace/public/plugin.ts | 6 +++++ 5 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 changelogs/fragments/9024.yml diff --git a/changelogs/fragments/9024.yml b/changelogs/fragments/9024.yml new file mode 100644 index 000000000000..81be06a48fdd --- /dev/null +++ b/changelogs/fragments/9024.yml @@ -0,0 +1,2 @@ +fix: +- Prevent user from visiting dashboards / visualizations when out of a workspace ([#9024](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/9024)) \ No newline at end of file diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index c7951a955fde..55ed9a02d24d 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -34,6 +34,9 @@ import { filter, map } from 'rxjs/operators'; import { i18n } from '@osd/i18n'; import { FormattedMessage } from '@osd/i18n/react'; +import { UrlForwardingSetup, UrlForwardingStart } from 'src/plugins/url_forwarding/public'; +import { isEmpty } from 'lodash'; +import { createHashHistory } from 'history'; import { App, AppMountParameters, @@ -43,11 +46,9 @@ import { Plugin, PluginInitializerContext, SavedObjectsClientContract, + WorkspaceAvailability, ScopedHistory, -} from 'src/core/public'; -import { UrlForwardingSetup, UrlForwardingStart } from 'src/plugins/url_forwarding/public'; -import { isEmpty } from 'lodash'; -import { createHashHistory } from 'history'; +} from '../../../../src/core/public'; import { UsageCollectionSetup } from '../../usage_collection/public'; import { CONTEXT_MENU_TRIGGER, @@ -367,6 +368,7 @@ export class DashboardPlugin id: DashboardConstants.DASHBOARDS_ID, title: 'Dashboards', order: 2500, + workspaceAvailability: WorkspaceAvailability.insideWorkspace, euiIconType: 'inputOutput', defaultPath: `#${DashboardConstants.LANDING_PAGE_PATH}`, updater$: this.appStateUpdater, diff --git a/src/plugins/visualize/public/plugin.ts b/src/plugins/visualize/public/plugin.ts index 6df26eb08d42..1b1d20803aef 100644 --- a/src/plugins/visualize/public/plugin.ts +++ b/src/plugins/visualize/public/plugin.ts @@ -42,6 +42,7 @@ import { ScopedHistory, } from 'opensearch-dashboards/public'; +import { WorkspaceAvailability } from '../../../../src/core/public'; import { Storage, createOsdUrlTracker, @@ -158,6 +159,7 @@ export class VisualizePlugin title: 'Visualize', order: 8000, euiIconType: 'inputOutput', + workspaceAvailability: WorkspaceAvailability.insideWorkspace, defaultPath: '#/', category: DEFAULT_APP_CATEGORIES.opensearchDashboards, updater$: this.appStateUpdater.asObservable(), diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index a4ed941ad094..75959a3bde98 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -6,13 +6,14 @@ import { BehaviorSubject, Observable, Subscriber } from 'rxjs'; import { waitFor } from '@testing-library/dom'; import { first } from 'rxjs/operators'; - import { applicationServiceMock, chromeServiceMock, coreMock } from '../../../core/public/mocks'; import { ChromeBreadcrumb, NavGroupStatus, DEFAULT_NAV_GROUPS, AppNavLinkStatus, + WorkspaceAvailability, + AppStatus, } from '../../../core/public'; import { WORKSPACE_FATAL_ERROR_APP_ID, WORKSPACE_DETAIL_APP_ID } from '../common/constants'; import { savedObjectsManagementPluginMock } from '../../saved_objects_management/public/mocks'; @@ -509,6 +510,33 @@ describe('Workspace plugin', () => { }); }); + it('#start should not be able to access app of which workspaceAvailability is set to insideWorkspace when out of workspace', async () => { + const workspacePlugin = new WorkspacePlugin(); + const setupMock = getSetupMock(); + const coreStart = coreMock.createStart(); + await workspacePlugin.setup(setupMock, {}); + coreStart.workspaces.currentWorkspace$.next(null); + + coreStart.application.capabilities = { + ...coreStart.application.capabilities, + dashboard: { + isDashboardAdmin: false, + }, + }; + + workspacePlugin.start(coreStart, getMockDependencies()); + + const mockApp = { + id: 'dashboards', + workspaceAvailability: WorkspaceAvailability.insideWorkspace, + }; + + const appUpdater$ = setupMock.application.registerAppUpdater.mock.calls[0][0]; + + const appState = await appUpdater$.pipe(first()).toPromise(); + expect(appState(mockApp)).toEqual({ status: AppStatus.inaccessible }); + }); + it('#stop should call unregisterNavGroupUpdater', async () => { const workspacePlugin = new WorkspacePlugin(); const setupMock = getSetupMock(); diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 4ef84d302a7c..5d9bd9b6c2e0 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -162,6 +162,12 @@ export class WorkspacePlugin */ return { status: AppStatus.inaccessible }; }); + } else { + this.appUpdater$.next((app) => { + if (app.workspaceAvailability === WorkspaceAvailability.insideWorkspace) { + return { status: AppStatus.inaccessible }; + } + }); } });