diff --git a/src/plugins/workspace/public/application.tsx b/src/plugins/workspace/public/application.tsx index 87fcbc555264..a82f74ed9fb5 100644 --- a/src/plugins/workspace/public/application.tsx +++ b/src/plugins/workspace/public/application.tsx @@ -11,13 +11,20 @@ import { WorkspaceListApp } from './components/workspace_list_app'; import { WorkspaceFatalError } from './components/workspace_fatal_error'; import { WorkspaceCreatorApp } from './components/workspace_creator_app'; import { WorkspaceUpdaterApp } from './components/workspace_updater_app'; +import { WorkspaceUpdaterProps } from './components/workspace_updater'; import { Services } from './types'; import { WorkspaceOverviewApp } from './components/workspace_overview_app'; +import { WorkspaceCreatorProps } from './components/workspace_creator/workspace_creator'; +import { WorkspaceListProps } from './components/workspace_list'; -export const renderCreatorApp = ({ element }: AppMountParameters, services: Services) => { +export const renderCreatorApp = ( + { element }: AppMountParameters, + services: Services, + props: WorkspaceCreatorProps +) => { ReactDOM.render( - + , element ); @@ -27,10 +34,14 @@ export const renderCreatorApp = ({ element }: AppMountParameters, services: Serv }; }; -export const renderUpdaterApp = ({ element }: AppMountParameters, services: Services) => { +export const renderUpdaterApp = ( + { element }: AppMountParameters, + services: Services, + props: WorkspaceUpdaterProps +) => { ReactDOM.render( - + , element ); @@ -55,10 +66,14 @@ export const renderFatalErrorApp = (params: AppMountParameters, services: Servic }; }; -export const renderListApp = ({ element }: AppMountParameters, services: Services) => { +export const renderListApp = ( + { element }: AppMountParameters, + services: Services, + props: WorkspaceListProps +) => { ReactDOM.render( - + , element ); diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx index 114e72f177db..346995df354a 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx @@ -94,13 +94,21 @@ describe('WorkspaceCreator', () => { }); it('cannot create workspace when name empty', async () => { - const { getByTestId } = render(); + const { getByTestId } = render( + + ); fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); expect(workspaceClientCreate).not.toHaveBeenCalled(); }); it('cannot create workspace with invalid name', async () => { - const { getByTestId } = render(); + const { getByTestId } = render( + + ); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: '~' }, @@ -109,7 +117,11 @@ describe('WorkspaceCreator', () => { }); it('cannot create workspace with invalid description', async () => { - const { getByTestId } = render(); + const { getByTestId } = render( + + ); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -122,7 +134,11 @@ describe('WorkspaceCreator', () => { }); it('cancel create workspace', async () => { - const { findByText, getByTestId } = render(); + const { findByText, getByTestId } = render( + + ); fireEvent.click(getByTestId('workspaceForm-bottomBar-cancelButton')); await findByText('Discard changes?'); fireEvent.click(getByTestId('confirmModalConfirmButton')); @@ -130,7 +146,11 @@ describe('WorkspaceCreator', () => { }); it('create workspace with detailed information', async () => { - const { getByTestId } = render(); + const { getByTestId } = render( + + ); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -161,7 +181,11 @@ describe('WorkspaceCreator', () => { }); it('create workspace with customized features', async () => { - const { getByTestId } = render(); + const { getByTestId } = render( + + ); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx index d296ef5675a0..d15384ed0820 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx @@ -6,6 +6,10 @@ import React, { useCallback } from 'react'; import { EuiPage, EuiPageBody, EuiPageHeader, EuiPageContent, EuiSpacer } from '@elastic/eui'; import { i18n } from '@osd/i18n'; +import { useObservable } from 'react-use'; +import { BehaviorSubject, of } from 'rxjs'; + +import { PublicAppInfo } from 'opensearch-dashboards/public'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; import { WorkspaceForm, WorkspaceFormSubmitData, WorkspaceOperationType } from '../workspace_form'; import { WORKSPACE_OVERVIEW_APP_ID } from '../../../common/constants'; @@ -13,10 +17,18 @@ import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; import { WorkspaceClient } from '../../workspace_client'; import { convertPermissionSettingsToPermissions } from '../workspace_form'; -export const WorkspaceCreator = () => { +export interface WorkspaceCreatorProps { + workspaceConfigurableApps$?: BehaviorSubject; +} + +export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { const { services: { application, notifications, http, workspaceClient }, } = useOpenSearchDashboards<{ workspaceClient: WorkspaceClient }>(); + const workspaceConfigurableApps = useObservable( + props.workspaceConfigurableApps$ ?? of(undefined) + ); + const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled; const handleWorkspaceFormSubmit = useCallback( @@ -88,6 +100,7 @@ export const WorkspaceCreator = () => { operationType={WorkspaceOperationType.Create} permissionEnabled={isPermissionEnabled} permissionLastAdminItemDeletable + workspaceConfigurableApps={workspaceConfigurableApps} /> )} diff --git a/src/plugins/workspace/public/components/workspace_creator_app.tsx b/src/plugins/workspace/public/components/workspace_creator_app.tsx index b74359929352..e384f5d5bfed 100644 --- a/src/plugins/workspace/public/components/workspace_creator_app.tsx +++ b/src/plugins/workspace/public/components/workspace_creator_app.tsx @@ -8,8 +8,9 @@ import { I18nProvider } from '@osd/i18n/react'; import { i18n } from '@osd/i18n'; import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; import { WorkspaceCreator } from './workspace_creator'; +import { WorkspaceCreatorProps } from './workspace_creator/workspace_creator'; -export const WorkspaceCreatorApp = () => { +export const WorkspaceCreatorApp = (props: WorkspaceCreatorProps) => { const { services: { chrome }, } = useOpenSearchDashboards(); @@ -29,7 +30,7 @@ export const WorkspaceCreatorApp = () => { return ( - + ); }; diff --git a/src/plugins/workspace/public/components/workspace_form/types.ts b/src/plugins/workspace/public/components/workspace_form/types.ts index 95c96fa3e353..6cff2a1c909b 100644 --- a/src/plugins/workspace/public/components/workspace_form/types.ts +++ b/src/plugins/workspace/public/components/workspace_form/types.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { ApplicationStart } from '../../../../../core/public'; +import type { ApplicationStart, PublicAppInfo } from '../../../../../core/public'; import type { WorkspacePermissionMode } from '../../../common/constants'; import type { WorkspaceOperationType, WorkspacePermissionItemType } from './constants'; @@ -57,4 +57,5 @@ export interface WorkspaceFormProps { operationType?: WorkspaceOperationType; permissionEnabled?: boolean; permissionLastAdminItemDeletable?: boolean; + workspaceConfigurableApps?: PublicAppInfo[]; } diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_feature_selector.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_feature_selector.test.tsx index 0875b0d1ff10..565fc03ca4f2 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_feature_selector.test.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_feature_selector.test.tsx @@ -9,7 +9,7 @@ import { WorkspaceFeatureSelector, WorkspaceFeatureSelectorProps, } from './workspace_feature_selector'; -import { AppNavLinkStatus } from '../../../../../core/public'; +import { AppNavLinkStatus, AppStatus } from '../../../../../core/public'; const setup = (options?: Partial) => { const onChangeMock = jest.fn(); @@ -19,28 +19,36 @@ const setup = (options?: Partial) => { title: 'App 1', category: { id: 'category-1', label: 'Category 1' }, navLinkStatus: AppNavLinkStatus.visible, + status: AppStatus.accessible, + appRoute: '/', }, { id: 'app-2', title: 'App 2', category: { id: 'category-1', label: 'Category 1' }, navLinkStatus: AppNavLinkStatus.visible, + status: AppStatus.accessible, + appRoute: '/', }, { id: 'app-3', title: 'App 3', category: { id: 'category-2', label: 'Category 2' }, navLinkStatus: AppNavLinkStatus.visible, + status: AppStatus.accessible, + appRoute: '/', }, { id: 'app-4', title: 'App 4', navLinkStatus: AppNavLinkStatus.visible, + status: AppStatus.accessible, + appRoute: '/', }, ]; const renderResult = render( - >; selectedFeatures: string[]; onChange: (newFeatures: string[]) => void; + workspaceConfigurableApps?: PublicAppInfo[]; } export const WorkspaceFeatureSelector = ({ - applications, selectedFeatures, onChange, + workspaceConfigurableApps, }: WorkspaceFeatureSelectorProps) => { - const featuresOrGroups = useMemo(() => convertApplicationsToFeaturesOrGroups(applications), [ - applications, - ]); + const featuresOrGroups = useMemo( + () => convertApplicationsToFeaturesOrGroups(workspaceConfigurableApps ?? []), + [workspaceConfigurableApps] + ); const handleFeatureChange = useCallback( (featureId) => { diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx index be977578b412..e635e5b5544c 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx @@ -39,7 +39,6 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { formData, formErrors, selectedTab, - applications, numberOfErrors, handleFormSubmit, handleColorChange, @@ -154,9 +153,9 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { )} diff --git a/src/plugins/workspace/public/components/workspace_list/index.tsx b/src/plugins/workspace/public/components/workspace_list/index.tsx index f529524d797e..a1295bcc1e1f 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.tsx @@ -15,9 +15,9 @@ import { EuiSearchBarProps, } from '@elastic/eui'; import useObservable from 'react-use/lib/useObservable'; -import { of } from 'rxjs'; +import { BehaviorSubject, of } from 'rxjs'; import { i18n } from '@osd/i18n'; -import { debounce, WorkspaceObject } from '../../../../../core/public'; +import { debounce, PublicAppInfo, WorkspaceObject } from '../../../../../core/public'; import { WorkspaceAttribute } from '../../../../../core/public'; import { useOpenSearchDashboards } from '../../../../../plugins/opensearch_dashboards_react/public'; import { switchWorkspace, updateWorkspace } from '../utils/workspace'; @@ -26,17 +26,20 @@ import { WORKSPACE_CREATE_APP_ID } from '../../../common/constants'; import { cleanWorkspaceId } from '../../../../../core/public'; import { DeleteWorkspaceModal } from '../delete_workspace_modal'; -import { useApplications } from '././../../hooks'; import { getSelectedFeatureQuantities } from '../../utils'; -const WORKSPACE_LIST_PAGE_DESCRIPTIOIN = i18n.translate('workspace.list.description', { +export interface WorkspaceListProps { + workspaceConfigurableApps$?: BehaviorSubject; +} + +const WORKSPACE_LIST_PAGE_DESCRIPTION = i18n.translate('workspace.list.description', { defaultMessage: 'Workspace allow you to save and organize library items, such as index patterns, visualizations, dashboards, saved searches, and share them with other OpenSearch Dashboards users. You can control which features are visible in each workspace, and which users and groups have read and write access to the library items in the workspace.', }); const emptyWorkspaceList: WorkspaceObject[] = []; -export const WorkspaceList = () => { +export const WorkspaceList = (props: WorkspaceListProps) => { const { services: { workspaces, application, http }, } = useOpenSearchDashboards(); @@ -54,7 +57,7 @@ export const WorkspaceList = () => { pageSizeOptions: [5, 10, 20], }); const [deletedWorkspace, setDeletedWorkspace] = useState(null); - const applications = useApplications(application); + const applications = useObservable(props.workspaceConfigurableApps$ ?? of(undefined)); const handleSwitchWorkspace = useCallback( (id: string) => { @@ -115,7 +118,7 @@ export const WorkspaceList = () => { isExpander: true, hasActions: true, render: (features: string[]) => { - const { total, selected } = getSelectedFeatureQuantities(features, applications); + const { total, selected } = getSelectedFeatureQuantities(features, applications || []); return `${selected}/${total}`; }, }, @@ -189,7 +192,7 @@ export const WorkspaceList = () => { { +export const WorkspaceListApp = (props: WorkspaceListProps) => { const { services: { chrome }, } = useOpenSearchDashboards(); @@ -29,7 +29,7 @@ export const WorkspaceListApp = () => { return ( - + ); }; diff --git a/src/plugins/workspace/public/components/workspace_updater/index.tsx b/src/plugins/workspace/public/components/workspace_updater/index.tsx index 711f19fd25f6..b00065a00f64 100644 --- a/src/plugins/workspace/public/components/workspace_updater/index.tsx +++ b/src/plugins/workspace/public/components/workspace_updater/index.tsx @@ -3,4 +3,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -export { WorkspaceUpdater } from './workspace_updater'; +export { WorkspaceUpdater, WorkspaceUpdaterProps } from './workspace_updater'; diff --git a/src/plugins/workspace/public/components/workspace_updater/workspace_updater.test.tsx b/src/plugins/workspace/public/components/workspace_updater/workspace_updater.test.tsx index 2b56bf322388..7b1c365a80dc 100644 --- a/src/plugins/workspace/public/components/workspace_updater/workspace_updater.test.tsx +++ b/src/plugins/workspace/public/components/workspace_updater/workspace_updater.test.tsx @@ -116,12 +116,21 @@ describe('WorkspaceUpdater', () => { it('cannot render when the name of the current workspace is empty', async () => { const mockedWorkspacesService = workspacesServiceMock.createSetupContract(); - const { container } = render(); + const { container } = render( + + ); expect(container).toMatchInlineSnapshot(`
`); }); it('cannot create workspace with invalid name', async () => { - const { getByTestId } = render(); + const { getByTestId } = render( + + ); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: '~' }, @@ -130,7 +139,11 @@ describe('WorkspaceUpdater', () => { }); it('update workspace successfully', async () => { - const { getByTestId, getByText, getAllByText } = render(); + const { getByTestId, getByText, getAllByText } = render( + + ); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -186,7 +199,11 @@ describe('WorkspaceUpdater', () => { it('should show danger toasts after update workspace failed', async () => { workspaceClientUpdate.mockReturnValue({ result: false, success: false }); - const { getByTestId } = render(); + const { getByTestId } = render( + + ); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -203,7 +220,11 @@ describe('WorkspaceUpdater', () => { workspaceClientUpdate.mockImplementation(() => { throw new Error('update workspace failed'); }); - const { getByTestId } = render(); + const { getByTestId } = render( + + ); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, diff --git a/src/plugins/workspace/public/components/workspace_updater/workspace_updater.tsx b/src/plugins/workspace/public/components/workspace_updater/workspace_updater.tsx index 201175c11c8e..4114b4fc87cc 100644 --- a/src/plugins/workspace/public/components/workspace_updater/workspace_updater.tsx +++ b/src/plugins/workspace/public/components/workspace_updater/workspace_updater.tsx @@ -6,8 +6,9 @@ import React, { useCallback, useEffect, useState } from 'react'; import { EuiPage, EuiPageBody, EuiPageHeader, EuiPageContent } from '@elastic/eui'; import { i18n } from '@osd/i18n'; +import { PublicAppInfo } from 'opensearch-dashboards/public'; import { useObservable } from 'react-use'; -import { of } from 'rxjs'; +import { BehaviorSubject, of } from 'rxjs'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; import { WORKSPACE_OVERVIEW_APP_ID } from '../../../common/constants'; import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; @@ -21,6 +22,10 @@ import { convertPermissionSettingsToPermissions, } from '../workspace_form'; +export interface WorkspaceUpdaterProps { + workspaceConfigurableApps$?: BehaviorSubject; +} + function getFormDataFromWorkspace( currentWorkspace: WorkspaceAttributeWithPermission | null | undefined ) { @@ -35,13 +40,16 @@ function getFormDataFromWorkspace( }; } -export const WorkspaceUpdater = () => { +export const WorkspaceUpdater = (props: WorkspaceUpdaterProps) => { const { services: { application, workspaces, notifications, http, workspaceClient }, } = useOpenSearchDashboards<{ workspaceClient: WorkspaceClient }>(); const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled; const currentWorkspace = useObservable(workspaces ? workspaces.currentWorkspace$ : of(null)); + const workspaceConfigurableApps = useObservable( + props.workspaceConfigurableApps$ ?? of(undefined) + ); const [currentWorkspaceFormData, setCurrentWorkspaceFormData] = useState( getFormDataFromWorkspace(currentWorkspace) ); @@ -128,6 +136,7 @@ export const WorkspaceUpdater = () => { operationType={WorkspaceOperationType.Update} permissionEnabled={isPermissionEnabled} permissionLastAdminItemDeletable={false} + workspaceConfigurableApps={workspaceConfigurableApps} /> )} diff --git a/src/plugins/workspace/public/components/workspace_updater_app.tsx b/src/plugins/workspace/public/components/workspace_updater_app.tsx index e16c9ad72e0f..ab106b5c4b7a 100644 --- a/src/plugins/workspace/public/components/workspace_updater_app.tsx +++ b/src/plugins/workspace/public/components/workspace_updater_app.tsx @@ -7,9 +7,9 @@ import React, { useEffect } from 'react'; import { I18nProvider } from '@osd/i18n/react'; import { i18n } from '@osd/i18n'; import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; -import { WorkspaceUpdater } from './workspace_updater'; +import { WorkspaceUpdater, WorkspaceUpdaterProps } from './workspace_updater'; -export const WorkspaceUpdaterApp = () => { +export const WorkspaceUpdaterApp = (props: WorkspaceUpdaterProps) => { const { services: { chrome }, } = useOpenSearchDashboards(); @@ -29,7 +29,7 @@ export const WorkspaceUpdaterApp = () => { return ( - + ); }; diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 4b43c3438179..469432affb97 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -4,6 +4,7 @@ */ import { BehaviorSubject, Subscription } from 'rxjs'; +import { first } from 'rxjs/operators'; import { i18n } from '@osd/i18n'; import { SavedObjectsManagementPluginSetup } from 'src/plugins/saved_objects_management/public'; import { ManagementSetup } from 'src/plugins/management/public'; @@ -16,6 +17,7 @@ import { AppUpdater, AppStatus, WorkspaceAccessibility, + PublicAppInfo, } from '../../../core/public'; import { WORKSPACE_FATAL_ERROR_APP_ID, @@ -29,9 +31,13 @@ import { renderWorkspaceMenu } from './render_workspace_menu'; import { Services } from './types'; import { WorkspaceClient } from './workspace_client'; import { getWorkspaceColumn } from './components/workspace_column'; -import { isAppAccessibleInWorkspace } from './utils'; +import { filterWorkspaceConfigurableApps, isAppAccessibleInWorkspace } from './utils'; -type WorkspaceAppType = (params: AppMountParameters, services: Services) => () => void; +type WorkspaceAppType = ( + params: AppMountParameters, + services: Services, + props: Record +) => () => void; interface WorkspacePluginSetupDeps { savedObjectsManagement?: SavedObjectsManagementPluginSetup; @@ -44,6 +50,7 @@ export class WorkspacePlugin implements Plugin<{}, {}> { private currentWorkspaceSubscription?: Subscription; private managementCurrentWorkspaceIdSubscription?: Subscription; private appUpdater$ = new BehaviorSubject(() => undefined); + private workspaceConfigurableApps$ = new BehaviorSubject([]); private _changeSavedObjectCurrentWorkspace() { if (this.coreStart) { return this.coreStart.workspaces.currentWorkspaceId$.subscribe((currentWorkspaceId) => { @@ -58,7 +65,7 @@ export class WorkspacePlugin implements Plugin<{}, {}> { * Filter nav links by the current workspace, once the current workspace change, the nav links(left nav bar) * should also be updated according to the configured features of the current workspace */ - private filterNavLinks(core: CoreStart) { + private filterNavLinks = (core: CoreStart) => { const currentWorkspace$ = core.workspaces.currentWorkspace$; this.currentWorkspaceSubscription?.unsubscribe(); @@ -68,6 +75,11 @@ export class WorkspacePlugin implements Plugin<{}, {}> { if (isAppAccessibleInWorkspace(app, currentWorkspace)) { return; } + + if (app.status === AppStatus.inaccessible) { + return; + } + /** * Change the app to `inaccessible` if it is not configured in the workspace * If trying to access such app, an "Application Not Found" page will be displayed @@ -76,7 +88,20 @@ export class WorkspacePlugin implements Plugin<{}, {}> { }); } }); - } + }; + + /** + * Initiate an observable with the value of all applications which can be configured by workspace + */ + private setWorkspaceConfigurableApps = async (core: CoreStart) => { + const allApps = await new Promise((resolve) => { + core.application.applications$.pipe(first()).subscribe((apps) => { + resolve([...apps.values()]); + }); + }); + const availableApps = filterWorkspaceConfigurableApps(allApps); + this.workspaceConfigurableApps$.next(availableApps); + }; /** * If workspace is enabled and user has entered workspace, hide advance settings and dataSource menu and disable @@ -157,7 +182,9 @@ export class WorkspacePlugin implements Plugin<{}, {}> { workspaceClient, }; - return renderApp(params, services); + return renderApp(params, services, { + workspaceConfigurableApps$: this.workspaceConfigurableApps$, + }); }; // list @@ -246,8 +273,11 @@ export class WorkspacePlugin implements Plugin<{}, {}> { this.currentWorkspaceIdSubscription = this._changeSavedObjectCurrentWorkspace(); - // When starts, filter the nav links based on the current workspace - this.filterNavLinks(core); + this.setWorkspaceConfigurableApps(core).then(() => { + // filter the nav links based on the current workspace + this.filterNavLinks(core); + }); + return {}; } diff --git a/src/plugins/workspace/public/utils.test.ts b/src/plugins/workspace/public/utils.test.ts index d2b9909eb682..41b1829927c4 100644 --- a/src/plugins/workspace/public/utils.test.ts +++ b/src/plugins/workspace/public/utils.test.ts @@ -127,18 +127,18 @@ describe('workspace utils: getSelectedFeatureQuantities', () => { navLinkStatus: 1, }, ] as PublicAppInfo[]; - it('should support * rules and exclude management category', () => { + it('should support * rules', () => { const { total, selected } = getSelectedFeatureQuantities(['*'], defaultApplications); - expect(total).toBe(1); - expect(selected).toBe(1); + expect(total).toBe(2); + expect(selected).toBe(2); }); - it('should get quantity normally and exclude management category', () => { + it('should get quantity of selected app', () => { const { total, selected } = getSelectedFeatureQuantities( ['dev_tools', '!@management'], defaultApplications ); - expect(total).toBe(1); + expect(total).toBe(2); expect(selected).toBe(0); }); }); diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index e65d62a58396..c75a6b131e28 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -12,6 +12,7 @@ import { WorkspaceObject, WorkspaceAccessibility, } from '../../../core/public'; +import { DEFAULT_CHECKED_FEATURES_IDS } from '../common/constants'; /** * Checks if a given feature matches the provided feature configuration. @@ -69,25 +70,14 @@ export const featureMatchesConfig = (featureConfigs: string[]) => ({ return matched; }; -// Get all apps excluding management category -export const getAllExcludingManagementApps = (applications: PublicAppInfo[]): PublicAppInfo[] => { - return applications.filter( - ({ navLinkStatus, chromeless, category }) => - navLinkStatus !== AppNavLinkStatus.hidden && - !chromeless && - category?.id !== DEFAULT_APP_CATEGORIES.management.id - ); -}; - export const getSelectedFeatureQuantities = ( featuresConfig: string[], applications: PublicAppInfo[] ) => { - const visibleApplications = getAllExcludingManagementApps(applications); const featureFilter = featureMatchesConfig(featuresConfig); - const selectedApplications = visibleApplications.filter((app) => featureFilter(app)); + const selectedApplications = applications.filter((app) => featureFilter(app)); return { - total: visibleApplications.length, + total: applications.length, selected: selectedApplications.length, }; }; @@ -136,3 +126,16 @@ export function isAppAccessibleInWorkspace(app: App, workspace: WorkspaceObject) } return false; } + +export const filterWorkspaceConfigurableApps = (applications: PublicAppInfo[]) => { + const visibleApplications = applications.filter(({ navLinkStatus, chromeless, category, id }) => { + return ( + navLinkStatus !== AppNavLinkStatus.hidden && + !chromeless && + !DEFAULT_CHECKED_FEATURES_IDS.includes(id) && + category?.id !== DEFAULT_APP_CATEGORIES.management.id + ); + }); + + return visibleApplications; +};