From 5ce834ebbc5661a7365afd9cb9e3e09165f5bb0c Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Thu, 24 Aug 2023 15:33:32 +0800 Subject: [PATCH] fix: make importing workspace-specific objects as copy (#62) * setup workspace plugin project skeleton Signed-off-by: Yulong Ruan * test: add unit tests add license header Signed-off-by: Yulong Ruan * workspace template init commit Signed-off-by: Hailong Cui * refacter workspace template into hooks Signed-off-by: Hailong Cui * refacter workspace template hooks Signed-off-by: Hailong Cui * update coverImage comments Signed-off-by: Hailong Cui * feature: add public/workspaces service Signed-off-by: SuZhoue-Joe * feat: add interfaces for workspaces client Signed-off-by: SuZhoue-Joe * feat: add interfaces for workspaces client Signed-off-by: SuZhoue-Joe * feat: add interfaces for workspaces client Signed-off-by: SuZhoue-Joe * feat: implement workspaces service Signed-off-by: SuZhoue-Joe * feat: changes to client type interface Signed-off-by: SuZhoue-Joe * feat: changes to client implement Signed-off-by: SuZhoue-Joe * feat: implement more for workspaces service Signed-off-by: SuZhoue-Joe * feat: implement more for workspaces service Signed-off-by: SuZhoue-Joe * feat: implement more for workspaces service Signed-off-by: SuZhoue-Joe * feat: add workspace creator page (#5) * feat: add workspace creator page Signed-off-by: Lin Wang * feat: integrate with application workspace template Signed-off-by: Lin Wang * feat: add max-width and remove image wrapper if not exists Signed-off-by: Lin Wang * feat: update filter condition to align with collapsible nav Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * Add validation when load page (#8) * fix: validation & query Signed-off-by: SuZhoue-Joe * feat: modify file name to reduce confusion Signed-off-by: SuZhoue-Joe * feat: add landing logic to retrive workspace id Signed-off-by: SuZhoue-Joe * feat: add worklist observable Signed-off-by: SuZhoue-Joe * feat: add worklist observable Signed-off-by: SuZhoue-Joe * feat: add worklist observable Signed-off-by: SuZhoue-Joe * fix: type error Signed-off-by: SuZhoue-Joe * fix: type error Signed-off-by: SuZhoue-Joe * feat: make client more robust Signed-off-by: SuZhoue-Joe * feat: use Subject Signed-off-by: SuZhoue-Joe --------- Signed-off-by: SuZhoue-Joe * feat: use BehaviorObject and optimize code (#14) Signed-off-by: SuZhoue-Joe * feat: integrate with workspace create API (#13) * feat: integrate with workspace create API Signed-off-by: Lin Wang * feat: update to i18n text for toast Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * Add currentWorkspace$ (#15) * feat: add currentWorkspace$ Signed-off-by: SuZhoue-Joe * fix: type error Signed-off-by: SuZhoue-Joe * feat: add emit on currentWorkspace$ Signed-off-by: SuZhoue-Joe --------- Signed-off-by: SuZhoue-Joe * register plugin with workspace template (#16) Signed-off-by: Hailong Cui * workspace dropdown list (#9) Add workspace dropdown list --------- Signed-off-by: zhichao-aws Signed-off-by: SuZhoue-Joe Signed-off-by: suzhou Co-authored-by: SuZhoue-Joe * init workspace menu stage 1 (#12) * feat: init workspace menu stage 1 Signed-off-by: tygao * fix: remove port diff Signed-off-by: tygao * feat: update menu logic Signed-off-by: tygao --------- Signed-off-by: tygao * Fix template registration import error (#21) * fix import error Signed-off-by: Hailong Cui * fix osd bootstrap failure Signed-off-by: Hailong Cui --------- Signed-off-by: Hailong Cui * Add workspace overview page (#19) * feat: add workspace overview page Signed-off-by: Lin Wang * refactor: move paths to common constants Signed-off-by: Lin Wang * feat: add workspace overview item by custom nav in start phase Signed-off-by: Lin Wang * refactor: change to currentWorkspace$ in workspace client Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * feat: navigate to workspace create page after button clicked (#23) Signed-off-by: Lin Wang * fix failed test snapshots (#22) fix failed test snapshots temporary fix: fetch functional test from main branch fixed git error which cannot find ref due to feature branch `workspace` not exists on repo opensearch-dashboards-functional-test Signed-off-by: Yulong Ruan --------- Signed-off-by: Yulong Ruan * change to currentWorkspace, wrap title using i18n (#20) * change to currentWorkspace, wrap title using i18n Signed-off-by: zhichao-aws * change import Signed-off-by: zhichao-aws * directly return [] if currentWorkspace is null Signed-off-by: zhichao-aws --------- Signed-off-by: zhichao-aws * add workspace switch (#17) * feat: update workspace switch Signed-off-by: tygao * fix: fix switch error Signed-off-by: tygao * fix: fix prettier after merge Signed-off-by: tygao * chore: remove extra code after merge Signed-off-by: tygao --------- Signed-off-by: tygao * Add update workspace page (#25) Signed-off-by: gaobinlong * Delete Workspace (#24) * add delete workspace modal Signed-off-by: yuye-aws * implement delete on workspace overview page Signed-off-by: yuye-aws * fix export on delete workspace modal Signed-off-by: yuye-aws * add try catch to handle errors for workspace delete Signed-off-by: yuye-aws * move visibility control to workspace overview page exlusively Signed-off-by: yuye-aws * remove unused import Signed-off-by: yuye-aws --------- Signed-off-by: yuye-aws * feat: redirect to overview page after workspace switch (#26) Signed-off-by: Lin Wang * update menu filter logic (#28) * feat: update menu logic Signed-off-by: tygao * fix: use navLinks to filter Signed-off-by: tygao --------- Signed-off-by: tygao * feat: redirect to workspace overview page after created success (#29) Signed-off-by: Lin Wang * [Feature] Complied saved_objects create/find (#18) * temp: save Signed-off-by: SuZhoue-Joe * feat: make create/find support workspaces Signed-off-by: SuZhoue-Joe * feat: extract management code Signed-off-by: SuZhoue-Joe * fix: type check Signed-off-by: SuZhoue-Joe * fix: build error Signed-off-by: SuZhoue-Joe * feat: enable workspaces on saved client server side Signed-off-by: SuZhoue-Joe * feat: some optimization Signed-off-by: SuZhoue-Joe * feat: extract management code Signed-off-by: SuZhoue-Joe * feat: merge fix Signed-off-by: SuZhoue-Joe * feat: optimize code Signed-off-by: SuZhoue-Joe * feat: reuse common function Signed-off-by: SuZhoue-Joe * feat: optimize code when create Signed-off-by: SuZhoue-Joe * feat: remove useless test code Signed-off-by: SuZhoue-Joe --------- Signed-off-by: SuZhoue-Joe * feat: redirect to workspace update page after workspace switch (#30) * Move delete button to update page (#27) * add delete workspace modal Signed-off-by: yuye-aws * implement delete on workspace overview page Signed-off-by: yuye-aws * fix export on delete workspace modal Signed-off-by: yuye-aws * add try catch to handle errors for workspace delete Signed-off-by: yuye-aws * move visibility control to workspace overview page exlusively Signed-off-by: yuye-aws * remove unused import Signed-off-by: yuye-aws * change workspace overview route to workspace update Signed-off-by: yuye-aws * move delete button from workspace overview page to update page Signed-off-by: yuye-aws * remove update button from workspace overview page Signed-off-by: yuye-aws * recover router to workspace overview page Signed-off-by: yuye-aws * change navigation url for workspace overview button on left side panel Signed-off-by: yuye-aws --------- Signed-off-by: yuye-aws * fix: linting error Signed-off-by: Yulong Ruan * remove duplicate EuiPage (#34) * remove duplicate EuiPage Signed-off-by: Hailong Cui * fix: remove duplicate workspace template Signed-off-by: Hailong Cui --------- Signed-off-by: Hailong Cui * remove clear button, add the width of create button (#33) Signed-off-by: zhichao-aws * rename OpenSearch Plugins to OpenSearch Features this is a temporary fix just for demo, should be reverted later Signed-off-by: Yulong Ruan * Add some logic check when overwrite a saved object (#32) * feat: add some logic check when overwrite a saved object Signed-off-by: SuZhoue-Joe * fix: type check Signed-off-by: SuZhoue-Joe * feat: update Signed-off-by: SuZhoue-Joe --------- Signed-off-by: SuZhoue-Joe * Add color, icon and defaultVISTheme for workspace (#36) * feat: add color, icon and defaultVISTheme field for workspace saved object Signed-off-by: Lin Wang * add new fields to workspace form Signed-off-by: Lin Wang * feat: remove feature or group name hack Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * feat: add workspace list (#39) Signed-off-by: tygao * Feature/menu change (#37) * feat: register library menus Signed-off-by: SuZhoue-Joe * feat: some update Signed-off-by: SuZhoue-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhoue-Joe Signed-off-by: SuZhou-Joe * feat: different left menu and exit workspace (#38) * Exit workspace from left menu Signed-off-by: yuye-aws * Show exit workspace button with small window size Signed-off-by: yuye-aws * Remove recently viewed and workspace overview on left menu Signed-off-by: yuye-aws * Add buttons for outside, inside workspace case Signed-off-by: yuye-aws * Implement home button and workspace over view button on left menu Signed-off-by: yuye-aws * Implement workspace dropdown list in left menu Signed-off-by: yuye-aws * Add props on recently accessed and custom nav link Signed-off-by: yuye-aws * Add three props to mock props for collapsible nav: exitWorkspace, getWorkspaceUrl, workspaceList$ Signed-off-by: yuye-aws * Add three props to mock props for header: exitWorkspace, getWorkspaceUrl, workspaceList$ Signed-off-by: yuye-aws * Fix bugs for function createWorkspaceNavLink Signed-off-by: yuye-aws * Remove unused constants Signed-off-by: yuye-aws * Reuse method getWorkspaceUrl Signed-off-by: yuye-aws * Remove recently accessed and custom nav props in test Signed-off-by: yuye-aws * Revert "Remove recently accessed and custom nav props in test" This reverts commit 7895e5c5dcde9e134f26b2d6a3df54a2d62e9274. * Wrap title with i18n Signed-off-by: yuye-aws * Add redirect for workspace app Signed-off-by: yuye-aws * Enable users to go to workspace lists page via see more under workspaces in left menu Signed-off-by: yuye-aws --------- Signed-off-by: yuye-aws * feat: make url stateful (#35) * feat: make url stateful Signed-off-by: SuZhoue-Joe * feat: optimize code Signed-off-by: SuZhoue-Joe * feat: remove useless change Signed-off-by: SuZhoue-Joe * feat: optimize url listener Signed-off-by: SuZhoue-Joe * feat: make formatUrlWithWorkspaceId extensible Signed-off-by: SuZhoue-Joe * feat: modify to related components Signed-off-by: SuZhoue-Joe * feat: modify the async format to be sync function Signed-off-by: SuZhoue-Joe * feat: modify the async format to be sync function Signed-off-by: SuZhoue-Joe * fix: type check Signed-off-by: SuZhoue-Joe * feat: use path to maintain workspace info Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhoue-Joe Signed-off-by: SuZhou-Joe * Fix build error and part of test error (#42) * fix: fix build error and some ut Signed-off-by: tygao * chore: remove saved object client test diff Signed-off-by: tygao --------- Signed-off-by: tygao * feat: optimize code (#40) Signed-off-by: SuZhou-Joe * fix: bootstrap error (#43) Signed-off-by: SuZhou-Joe * feat: add workspace permission control interface (#41) * feat: add workspace permission control interface Signed-off-by: Lin Wang * feat: add request parameter for workspace permission control Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * allow user to turn on/off workspace from advance settings (#46) return 404 if accessing a workspace path when workspace is disabled --------- Signed-off-by: Yulong Ruan * fix: unit test failure (#50) Signed-off-by: SuZhou-Joe * Add workspace column into saved objects table (#44) * Add workspace column into saved management page Signed-off-by: Hailong Cui * savedObjectsManagement as optional dependency Signed-off-by: Hailong Cui * i18n for column title Signed-off-by: Hailong Cui --------- Signed-off-by: Hailong Cui * fix missing mocks of workspacesSetup Signed-off-by: Yulong Ruan * Integrate workspace service into saved object management (#31) * setup workspace plugin project skeleton Signed-off-by: Yulong Ruan * test: add unit tests add license header Signed-off-by: Yulong Ruan * workspace template init commit Signed-off-by: Hailong Cui * refacter workspace template into hooks Signed-off-by: Hailong Cui * refacter workspace template hooks Signed-off-by: Hailong Cui * update coverImage comments Signed-off-by: Hailong Cui * feature: add public/workspaces service Signed-off-by: SuZhoue-Joe * feat: add interfaces for workspaces client Signed-off-by: SuZhoue-Joe * feat: add interfaces for workspaces client Signed-off-by: SuZhoue-Joe * feat: add interfaces for workspaces client Signed-off-by: SuZhoue-Joe * feat: implement workspaces service Signed-off-by: SuZhoue-Joe * feat: changes to client type interface Signed-off-by: SuZhoue-Joe * feat: changes to client implement Signed-off-by: SuZhoue-Joe * feat: implement more for workspaces service Signed-off-by: SuZhoue-Joe * feat: implement more for workspaces service Signed-off-by: SuZhoue-Joe * feat: implement more for workspaces service Signed-off-by: SuZhoue-Joe * feat: add workspace creator page (#5) * feat: add workspace creator page Signed-off-by: Lin Wang * feat: integrate with application workspace template Signed-off-by: Lin Wang * feat: add max-width and remove image wrapper if not exists Signed-off-by: Lin Wang * feat: update filter condition to align with collapsible nav Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * Add validation when load page (#8) * fix: validation & query Signed-off-by: SuZhoue-Joe * feat: modify file name to reduce confusion Signed-off-by: SuZhoue-Joe * feat: add landing logic to retrive workspace id Signed-off-by: SuZhoue-Joe * feat: add worklist observable Signed-off-by: SuZhoue-Joe * feat: add worklist observable Signed-off-by: SuZhoue-Joe * feat: add worklist observable Signed-off-by: SuZhoue-Joe * fix: type error Signed-off-by: SuZhoue-Joe * fix: type error Signed-off-by: SuZhoue-Joe * feat: make client more robust Signed-off-by: SuZhoue-Joe * feat: use Subject Signed-off-by: SuZhoue-Joe --------- Signed-off-by: SuZhoue-Joe * feat: use BehaviorObject and optimize code (#14) Signed-off-by: SuZhoue-Joe * feat: integrate with workspace create API (#13) * feat: integrate with workspace create API Signed-off-by: Lin Wang * feat: update to i18n text for toast Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * Add currentWorkspace$ (#15) * feat: add currentWorkspace$ Signed-off-by: SuZhoue-Joe * fix: type error Signed-off-by: SuZhoue-Joe * feat: add emit on currentWorkspace$ Signed-off-by: SuZhoue-Joe --------- Signed-off-by: SuZhoue-Joe * register plugin with workspace template (#16) Signed-off-by: Hailong Cui * workspace dropdown list (#9) Add workspace dropdown list --------- Signed-off-by: zhichao-aws Signed-off-by: SuZhoue-Joe Signed-off-by: suzhou Co-authored-by: SuZhoue-Joe * init workspace menu stage 1 (#12) * feat: init workspace menu stage 1 Signed-off-by: tygao * fix: remove port diff Signed-off-by: tygao * feat: update menu logic Signed-off-by: tygao --------- Signed-off-by: tygao * Fix template registration import error (#21) * fix import error Signed-off-by: Hailong Cui * fix osd bootstrap failure Signed-off-by: Hailong Cui --------- Signed-off-by: Hailong Cui * Add workspace overview page (#19) * feat: add workspace overview page Signed-off-by: Lin Wang * refactor: move paths to common constants Signed-off-by: Lin Wang * feat: add workspace overview item by custom nav in start phase Signed-off-by: Lin Wang * refactor: change to currentWorkspace$ in workspace client Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * feat: navigate to workspace create page after button clicked (#23) Signed-off-by: Lin Wang * fix failed test snapshots (#22) fix failed test snapshots temporary fix: fetch functional test from main branch fixed git error which cannot find ref due to feature branch `workspace` not exists on repo opensearch-dashboards-functional-test Signed-off-by: Yulong Ruan --------- Signed-off-by: Yulong Ruan * change to currentWorkspace, wrap title using i18n (#20) * change to currentWorkspace, wrap title using i18n Signed-off-by: zhichao-aws * change import Signed-off-by: zhichao-aws * directly return [] if currentWorkspace is null Signed-off-by: zhichao-aws --------- Signed-off-by: zhichao-aws * add workspace switch (#17) * feat: update workspace switch Signed-off-by: tygao * fix: fix switch error Signed-off-by: tygao * fix: fix prettier after merge Signed-off-by: tygao * chore: remove extra code after merge Signed-off-by: tygao --------- Signed-off-by: tygao * Add update workspace page (#25) Signed-off-by: gaobinlong * Delete Workspace (#24) * add delete workspace modal Signed-off-by: yuye-aws * implement delete on workspace overview page Signed-off-by: yuye-aws * fix export on delete workspace modal Signed-off-by: yuye-aws * add try catch to handle errors for workspace delete Signed-off-by: yuye-aws * move visibility control to workspace overview page exlusively Signed-off-by: yuye-aws * remove unused import Signed-off-by: yuye-aws --------- Signed-off-by: yuye-aws * feat: redirect to overview page after workspace switch (#26) Signed-off-by: Lin Wang * update menu filter logic (#28) * feat: update menu logic Signed-off-by: tygao * fix: use navLinks to filter Signed-off-by: tygao --------- Signed-off-by: tygao * feat: redirect to workspace overview page after created success (#29) Signed-off-by: Lin Wang * [Feature] Complied saved_objects create/find (#18) * temp: save Signed-off-by: SuZhoue-Joe * feat: make create/find support workspaces Signed-off-by: SuZhoue-Joe * feat: extract management code Signed-off-by: SuZhoue-Joe * fix: type check Signed-off-by: SuZhoue-Joe * fix: build error Signed-off-by: SuZhoue-Joe * feat: enable workspaces on saved client server side Signed-off-by: SuZhoue-Joe * feat: some optimization Signed-off-by: SuZhoue-Joe * feat: extract management code Signed-off-by: SuZhoue-Joe * feat: merge fix Signed-off-by: SuZhoue-Joe * feat: optimize code Signed-off-by: SuZhoue-Joe * feat: reuse common function Signed-off-by: SuZhoue-Joe * feat: optimize code when create Signed-off-by: SuZhoue-Joe * feat: remove useless test code Signed-off-by: SuZhoue-Joe --------- Signed-off-by: SuZhoue-Joe * feat: redirect to workspace update page after workspace switch (#30) * Move delete button to update page (#27) * add delete workspace modal Signed-off-by: yuye-aws * implement delete on workspace overview page Signed-off-by: yuye-aws * fix export on delete workspace modal Signed-off-by: yuye-aws * add try catch to handle errors for workspace delete Signed-off-by: yuye-aws * move visibility control to workspace overview page exlusively Signed-off-by: yuye-aws * remove unused import Signed-off-by: yuye-aws * change workspace overview route to workspace update Signed-off-by: yuye-aws * move delete button from workspace overview page to update page Signed-off-by: yuye-aws * remove update button from workspace overview page Signed-off-by: yuye-aws * recover router to workspace overview page Signed-off-by: yuye-aws * change navigation url for workspace overview button on left side panel Signed-off-by: yuye-aws --------- Signed-off-by: yuye-aws * fix: linting error Signed-off-by: Yulong Ruan * remove duplicate EuiPage (#34) * remove duplicate EuiPage Signed-off-by: Hailong Cui * fix: remove duplicate workspace template Signed-off-by: Hailong Cui --------- Signed-off-by: Hailong Cui * remove clear button, add the width of create button (#33) Signed-off-by: zhichao-aws * rename OpenSearch Plugins to OpenSearch Features this is a temporary fix just for demo, should be reverted later Signed-off-by: Yulong Ruan * Add some logic check when overwrite a saved object (#32) * feat: add some logic check when overwrite a saved object Signed-off-by: SuZhoue-Joe * fix: type check Signed-off-by: SuZhoue-Joe * feat: update Signed-off-by: SuZhoue-Joe --------- Signed-off-by: SuZhoue-Joe * Add color, icon and defaultVISTheme for workspace (#36) * feat: add color, icon and defaultVISTheme field for workspace saved object Signed-off-by: Lin Wang * add new fields to workspace form Signed-off-by: Lin Wang * feat: remove feature or group name hack Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * feat: add workspace list (#39) Signed-off-by: tygao * Feature/menu change (#37) * feat: register library menus Signed-off-by: SuZhoue-Joe * feat: some update Signed-off-by: SuZhoue-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhoue-Joe Signed-off-by: SuZhou-Joe * feat: different left menu and exit workspace (#38) * Exit workspace from left menu Signed-off-by: yuye-aws * Show exit workspace button with small window size Signed-off-by: yuye-aws * Remove recently viewed and workspace overview on left menu Signed-off-by: yuye-aws * Add buttons for outside, inside workspace case Signed-off-by: yuye-aws * Implement home button and workspace over view button on left menu Signed-off-by: yuye-aws * Implement workspace dropdown list in left menu Signed-off-by: yuye-aws * Add props on recently accessed and custom nav link Signed-off-by: yuye-aws * Add three props to mock props for collapsible nav: exitWorkspace, getWorkspaceUrl, workspaceList$ Signed-off-by: yuye-aws * Add three props to mock props for header: exitWorkspace, getWorkspaceUrl, workspaceList$ Signed-off-by: yuye-aws * Fix bugs for function createWorkspaceNavLink Signed-off-by: yuye-aws * Remove unused constants Signed-off-by: yuye-aws * Reuse method getWorkspaceUrl Signed-off-by: yuye-aws * Remove recently accessed and custom nav props in test Signed-off-by: yuye-aws * Revert "Remove recently accessed and custom nav props in test" This reverts commit 7895e5c5dcde9e134f26b2d6a3df54a2d62e9274. * Wrap title with i18n Signed-off-by: yuye-aws * Add redirect for workspace app Signed-off-by: yuye-aws * Enable users to go to workspace lists page via see more under workspaces in left menu Signed-off-by: yuye-aws --------- Signed-off-by: yuye-aws * feat: make url stateful (#35) * feat: make url stateful Signed-off-by: SuZhoue-Joe * feat: optimize code Signed-off-by: SuZhoue-Joe * feat: remove useless change Signed-off-by: SuZhoue-Joe * feat: optimize url listener Signed-off-by: SuZhoue-Joe * feat: make formatUrlWithWorkspaceId extensible Signed-off-by: SuZhoue-Joe * feat: modify to related components Signed-off-by: SuZhoue-Joe * feat: modify the async format to be sync function Signed-off-by: SuZhoue-Joe * feat: modify the async format to be sync function Signed-off-by: SuZhoue-Joe * fix: type check Signed-off-by: SuZhoue-Joe * feat: use path to maintain workspace info Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhoue-Joe Signed-off-by: SuZhou-Joe * Fix build error and part of test error (#42) * fix: fix build error and some ut Signed-off-by: tygao * chore: remove saved object client test diff Signed-off-by: tygao --------- Signed-off-by: tygao * feat: optimize code (#40) Signed-off-by: SuZhou-Joe * fix: bootstrap error (#43) Signed-off-by: SuZhou-Joe * feat: add workspace permission control interface (#41) * feat: add workspace permission control interface Signed-off-by: Lin Wang * feat: add request parameter for workspace permission control Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * temp: save Signed-off-by: SuZhoue-Joe * feat: make create/find support workspaces Signed-off-by: SuZhoue-Joe * feat: extract management code Signed-off-by: SuZhoue-Joe * fix: type check Signed-off-by: SuZhoue-Joe * fix: build error Signed-off-by: SuZhoue-Joe * feat: enable workspaces on saved client server side Signed-off-by: SuZhoue-Joe * feat: extract management code Signed-off-by: SuZhoue-Joe * feat: merge fix Signed-off-by: SuZhoue-Joe * feat: optimize code Signed-off-by: SuZhoue-Joe * feat: remove useless test code Signed-off-by: SuZhoue-Joe * feat: integrate with saved object management page Signed-off-by: SuZhoue-Joe * Revert "feat: extract management code" This reverts commit 9c765d23aeae8bb76ab35a897e4abef9cc9da860. * Revert "feat: extract management code" This reverts commit 526c28e01b2a6b80e4f8ee7170b740f5c452b97c. * fix: type check Signed-off-by: SuZhoue-Joe * feat: update Signed-off-by: SuZhoue-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: remove useless import Signed-off-by: SuZhou-Joe * feat: remove useless import Signed-off-by: SuZhou-Joe * feat: remove useless import Signed-off-by: SuZhou-Joe * feat: refractor workspacesServiceMock Signed-off-by: SuZhou-Joe * feat: make all test pass Signed-off-by: SuZhou-Joe --------- Signed-off-by: Yulong Ruan Signed-off-by: Hailong Cui Signed-off-by: SuZhoue-Joe Signed-off-by: Lin Wang Signed-off-by: zhichao-aws Signed-off-by: suzhou Signed-off-by: tygao Signed-off-by: gaobinlong Signed-off-by: yuye-aws Signed-off-by: SuZhou-Joe Co-authored-by: Yulong Ruan Co-authored-by: Hailong Cui Co-authored-by: Lin Wang Co-authored-by: zhichao-aws Co-authored-by: raintygao Co-authored-by: gaobinlong Co-authored-by: Yuye Zhu * Feature: hide workspace from saved objects management page. (#45) * setup workspace plugin project skeleton Signed-off-by: Yulong Ruan * test: add unit tests add license header Signed-off-by: Yulong Ruan * workspace template init commit Signed-off-by: Hailong Cui * refacter workspace template into hooks Signed-off-by: Hailong Cui * refacter workspace template hooks Signed-off-by: Hailong Cui * update coverImage comments Signed-off-by: Hailong Cui * feature: add public/workspaces service Signed-off-by: SuZhoue-Joe * feat: add interfaces for workspaces client Signed-off-by: SuZhoue-Joe * feat: add interfaces for workspaces client Signed-off-by: SuZhoue-Joe * feat: add interfaces for workspaces client Signed-off-by: SuZhoue-Joe * feat: implement workspaces service Signed-off-by: SuZhoue-Joe * feat: changes to client type interface Signed-off-by: SuZhoue-Joe * feat: changes to client implement Signed-off-by: SuZhoue-Joe * feat: implement more for workspaces service Signed-off-by: SuZhoue-Joe * feat: implement more for workspaces service Signed-off-by: SuZhoue-Joe * feat: implement more for workspaces service Signed-off-by: SuZhoue-Joe * feat: add workspace creator page (#5) * feat: add workspace creator page Signed-off-by: Lin Wang * feat: integrate with application workspace template Signed-off-by: Lin Wang * feat: add max-width and remove image wrapper if not exists Signed-off-by: Lin Wang * feat: update filter condition to align with collapsible nav Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * Add validation when load page (#8) * fix: validation & query Signed-off-by: SuZhoue-Joe * feat: modify file name to reduce confusion Signed-off-by: SuZhoue-Joe * feat: add landing logic to retrive workspace id Signed-off-by: SuZhoue-Joe * feat: add worklist observable Signed-off-by: SuZhoue-Joe * feat: add worklist observable Signed-off-by: SuZhoue-Joe * feat: add worklist observable Signed-off-by: SuZhoue-Joe * fix: type error Signed-off-by: SuZhoue-Joe * fix: type error Signed-off-by: SuZhoue-Joe * feat: make client more robust Signed-off-by: SuZhoue-Joe * feat: use Subject Signed-off-by: SuZhoue-Joe --------- Signed-off-by: SuZhoue-Joe * feat: use BehaviorObject and optimize code (#14) Signed-off-by: SuZhoue-Joe * feat: integrate with workspace create API (#13) * feat: integrate with workspace create API Signed-off-by: Lin Wang * feat: update to i18n text for toast Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * Add currentWorkspace$ (#15) * feat: add currentWorkspace$ Signed-off-by: SuZhoue-Joe * fix: type error Signed-off-by: SuZhoue-Joe * feat: add emit on currentWorkspace$ Signed-off-by: SuZhoue-Joe --------- Signed-off-by: SuZhoue-Joe * register plugin with workspace template (#16) Signed-off-by: Hailong Cui * workspace dropdown list (#9) Add workspace dropdown list --------- Signed-off-by: zhichao-aws Signed-off-by: SuZhoue-Joe Signed-off-by: suzhou Co-authored-by: SuZhoue-Joe * init workspace menu stage 1 (#12) * feat: init workspace menu stage 1 Signed-off-by: tygao * fix: remove port diff Signed-off-by: tygao * feat: update menu logic Signed-off-by: tygao --------- Signed-off-by: tygao * Fix template registration import error (#21) * fix import error Signed-off-by: Hailong Cui * fix osd bootstrap failure Signed-off-by: Hailong Cui --------- Signed-off-by: Hailong Cui * Add workspace overview page (#19) * feat: add workspace overview page Signed-off-by: Lin Wang * refactor: move paths to common constants Signed-off-by: Lin Wang * feat: add workspace overview item by custom nav in start phase Signed-off-by: Lin Wang * refactor: change to currentWorkspace$ in workspace client Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * feat: navigate to workspace create page after button clicked (#23) Signed-off-by: Lin Wang * fix failed test snapshots (#22) fix failed test snapshots temporary fix: fetch functional test from main branch fixed git error which cannot find ref due to feature branch `workspace` not exists on repo opensearch-dashboards-functional-test Signed-off-by: Yulong Ruan --------- Signed-off-by: Yulong Ruan * change to currentWorkspace, wrap title using i18n (#20) * change to currentWorkspace, wrap title using i18n Signed-off-by: zhichao-aws * change import Signed-off-by: zhichao-aws * directly return [] if currentWorkspace is null Signed-off-by: zhichao-aws --------- Signed-off-by: zhichao-aws * add workspace switch (#17) * feat: update workspace switch Signed-off-by: tygao * fix: fix switch error Signed-off-by: tygao * fix: fix prettier after merge Signed-off-by: tygao * chore: remove extra code after merge Signed-off-by: tygao --------- Signed-off-by: tygao * Add update workspace page (#25) Signed-off-by: gaobinlong * Delete Workspace (#24) * add delete workspace modal Signed-off-by: yuye-aws * implement delete on workspace overview page Signed-off-by: yuye-aws * fix export on delete workspace modal Signed-off-by: yuye-aws * add try catch to handle errors for workspace delete Signed-off-by: yuye-aws * move visibility control to workspace overview page exlusively Signed-off-by: yuye-aws * remove unused import Signed-off-by: yuye-aws --------- Signed-off-by: yuye-aws * feat: redirect to overview page after workspace switch (#26) Signed-off-by: Lin Wang * update menu filter logic (#28) * feat: update menu logic Signed-off-by: tygao * fix: use navLinks to filter Signed-off-by: tygao --------- Signed-off-by: tygao * feat: redirect to workspace overview page after created success (#29) Signed-off-by: Lin Wang * [Feature] Complied saved_objects create/find (#18) * temp: save Signed-off-by: SuZhoue-Joe * feat: make create/find support workspaces Signed-off-by: SuZhoue-Joe * feat: extract management code Signed-off-by: SuZhoue-Joe * fix: type check Signed-off-by: SuZhoue-Joe * fix: build error Signed-off-by: SuZhoue-Joe * feat: enable workspaces on saved client server side Signed-off-by: SuZhoue-Joe * feat: some optimization Signed-off-by: SuZhoue-Joe * feat: extract management code Signed-off-by: SuZhoue-Joe * feat: merge fix Signed-off-by: SuZhoue-Joe * feat: optimize code Signed-off-by: SuZhoue-Joe * feat: reuse common function Signed-off-by: SuZhoue-Joe * feat: optimize code when create Signed-off-by: SuZhoue-Joe * feat: remove useless test code Signed-off-by: SuZhoue-Joe --------- Signed-off-by: SuZhoue-Joe * feat: redirect to workspace update page after workspace switch (#30) * Move delete button to update page (#27) * add delete workspace modal Signed-off-by: yuye-aws * implement delete on workspace overview page Signed-off-by: yuye-aws * fix export on delete workspace modal Signed-off-by: yuye-aws * add try catch to handle errors for workspace delete Signed-off-by: yuye-aws * move visibility control to workspace overview page exlusively Signed-off-by: yuye-aws * remove unused import Signed-off-by: yuye-aws * change workspace overview route to workspace update Signed-off-by: yuye-aws * move delete button from workspace overview page to update page Signed-off-by: yuye-aws * remove update button from workspace overview page Signed-off-by: yuye-aws * recover router to workspace overview page Signed-off-by: yuye-aws * change navigation url for workspace overview button on left side panel Signed-off-by: yuye-aws --------- Signed-off-by: yuye-aws * fix: linting error Signed-off-by: Yulong Ruan * remove duplicate EuiPage (#34) * remove duplicate EuiPage Signed-off-by: Hailong Cui * fix: remove duplicate workspace template Signed-off-by: Hailong Cui --------- Signed-off-by: Hailong Cui * remove clear button, add the width of create button (#33) Signed-off-by: zhichao-aws * rename OpenSearch Plugins to OpenSearch Features this is a temporary fix just for demo, should be reverted later Signed-off-by: Yulong Ruan * Add some logic check when overwrite a saved object (#32) * feat: add some logic check when overwrite a saved object Signed-off-by: SuZhoue-Joe * fix: type check Signed-off-by: SuZhoue-Joe * feat: update Signed-off-by: SuZhoue-Joe --------- Signed-off-by: SuZhoue-Joe * Add color, icon and defaultVISTheme for workspace (#36) * feat: add color, icon and defaultVISTheme field for workspace saved object Signed-off-by: Lin Wang * add new fields to workspace form Signed-off-by: Lin Wang * feat: remove feature or group name hack Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * feat: add workspace list (#39) Signed-off-by: tygao * Feature/menu change (#37) * feat: register library menus Signed-off-by: SuZhoue-Joe * feat: some update Signed-off-by: SuZhoue-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhoue-Joe Signed-off-by: SuZhou-Joe * feat: different left menu and exit workspace (#38) * Exit workspace from left menu Signed-off-by: yuye-aws * Show exit workspace button with small window size Signed-off-by: yuye-aws * Remove recently viewed and workspace overview on left menu Signed-off-by: yuye-aws * Add buttons for outside, inside workspace case Signed-off-by: yuye-aws * Implement home button and workspace over view button on left menu Signed-off-by: yuye-aws * Implement workspace dropdown list in left menu Signed-off-by: yuye-aws * Add props on recently accessed and custom nav link Signed-off-by: yuye-aws * Add three props to mock props for collapsible nav: exitWorkspace, getWorkspaceUrl, workspaceList$ Signed-off-by: yuye-aws * Add three props to mock props for header: exitWorkspace, getWorkspaceUrl, workspaceList$ Signed-off-by: yuye-aws * Fix bugs for function createWorkspaceNavLink Signed-off-by: yuye-aws * Remove unused constants Signed-off-by: yuye-aws * Reuse method getWorkspaceUrl Signed-off-by: yuye-aws * Remove recently accessed and custom nav props in test Signed-off-by: yuye-aws * Revert "Remove recently accessed and custom nav props in test" This reverts commit 7895e5c5dcde9e134f26b2d6a3df54a2d62e9274. * Wrap title with i18n Signed-off-by: yuye-aws * Add redirect for workspace app Signed-off-by: yuye-aws * Enable users to go to workspace lists page via see more under workspaces in left menu Signed-off-by: yuye-aws --------- Signed-off-by: yuye-aws * feat: make url stateful (#35) * feat: make url stateful Signed-off-by: SuZhoue-Joe * feat: optimize code Signed-off-by: SuZhoue-Joe * feat: remove useless change Signed-off-by: SuZhoue-Joe * feat: optimize url listener Signed-off-by: SuZhoue-Joe * feat: make formatUrlWithWorkspaceId extensible Signed-off-by: SuZhoue-Joe * feat: modify to related components Signed-off-by: SuZhoue-Joe * feat: modify the async format to be sync function Signed-off-by: SuZhoue-Joe * feat: modify the async format to be sync function Signed-off-by: SuZhoue-Joe * fix: type check Signed-off-by: SuZhoue-Joe * feat: use path to maintain workspace info Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhoue-Joe Signed-off-by: SuZhou-Joe * Fix build error and part of test error (#42) * fix: fix build error and some ut Signed-off-by: tygao * chore: remove saved object client test diff Signed-off-by: tygao --------- Signed-off-by: tygao * feat: optimize code (#40) Signed-off-by: SuZhou-Joe * fix: bootstrap error (#43) Signed-off-by: SuZhou-Joe * feat: add workspace permission control interface (#41) * feat: add workspace permission control interface Signed-off-by: Lin Wang * feat: add request parameter for workspace permission control Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * allow user to turn on/off workspace from advance settings (#46) return 404 if accessing a workspace path when workspace is disabled --------- Signed-off-by: Yulong Ruan * fix: unit test failure (#50) Signed-off-by: SuZhou-Joe * Add workspace column into saved objects table (#44) * Add workspace column into saved management page Signed-off-by: Hailong Cui * savedObjectsManagement as optional dependency Signed-off-by: Hailong Cui * i18n for column title Signed-off-by: Hailong Cui --------- Signed-off-by: Hailong Cui * feat: make edit url clickable Signed-off-by: SuZhou-Joe * feat: add ui capability path Signed-off-by: SuZhou-Joe * feat: add ui capability path Signed-off-by: SuZhou-Joe * fet: remove useless jump code Signed-off-by: SuZhou-Joe * feat: hide workspace from saved objects management page Signed-off-by: SuZhou-Joe * feat: hide workspace from saved objects management page Signed-off-by: SuZhou-Joe --------- Signed-off-by: Yulong Ruan Signed-off-by: Hailong Cui Signed-off-by: SuZhoue-Joe Signed-off-by: Lin Wang Signed-off-by: zhichao-aws Signed-off-by: suzhou Signed-off-by: tygao Signed-off-by: gaobinlong Signed-off-by: yuye-aws Signed-off-by: SuZhou-Joe Co-authored-by: Yulong Ruan Co-authored-by: Hailong Cui Co-authored-by: Lin Wang Co-authored-by: zhichao-aws Co-authored-by: raintygao Co-authored-by: gaobinlong Co-authored-by: Yuye Zhu * Add copy saved objects among workspaces functionality (#53) * Add copy saved objects among workspaces functionality Signed-off-by: gaobinlong Signed-off-by: gaobinlong * Fix bug Signed-off-by: gaobinlong * Fix bug Signed-off-by: gaobinlong --------- Signed-off-by: gaobinlong * add workspace saved objects client wrapper (#51) * add workspace savedd objects client wrapper Signed-off-by: Lin Wang * feat: add more methods to saved objects client wrapper Signed-off-by: Lin Wang * feat: add findWithWorkspacePermissionControl in workspace saved objects client wrapper Signed-off-by: Lin Wang * feat: throw 451 instead of interval error Signed-off-by: Lin Wang * chore: fix workspace client init method type error Signed-off-by: Lin Wang * feat: fix workspaces attribute type error in client wrapper Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * Refactor navigation links from left menu hard code to workspace plugin register (#55) * feature: add public/workspaces service Signed-off-by: SuZhoue-Joe * Exit workspace from left menu Signed-off-by: yuye-aws * Show exit workspace button with small window size Signed-off-by: yuye-aws * Remove recently viewed and workspace overview on left menu Signed-off-by: yuye-aws * Add buttons for outside, inside workspace case Signed-off-by: yuye-aws * Implement home button and workspace over view button on left menu Signed-off-by: yuye-aws * Implement workspace dropdown list in left menu Signed-off-by: yuye-aws * Add props on recently accessed and custom nav link Signed-off-by: yuye-aws * Reuse method getWorkspaceUrl Signed-off-by: yuye-aws * Remove recently accessed and custom nav props in test Signed-off-by: yuye-aws * Revert "Remove recently accessed and custom nav props in test" This reverts commit 7895e5c5dcde9e134f26b2d6a3df54a2d62e9274. * Wrap title with i18n Signed-off-by: yuye-aws * Add redirect for workspace app Signed-off-by: yuye-aws * Enable users to go to workspace lists page via see more under workspaces in left menu Signed-off-by: yuye-aws * Fix build error and part of test error (#42) * fix: fix build error and some ut Signed-off-by: tygao * chore: remove saved object client test diff Signed-off-by: tygao --------- Signed-off-by: tygao * Comment Alerts and Favorites in left menu Signed-off-by: yuye-aws * Recover recently viewed items in left menu Signed-off-by: yuye-aws * Move exit workspace from left menu to update page Signed-off-by: yuye-aws * Remove unused import Signed-off-by: yuye-aws * Add workspace category info Signed-off-by: yuye-aws * Remove workspace nav link Signed-off-by: yuye-aws * Remove unused import Signed-off-by: yuye-aws * Add FilteredNavLinks props to chrome service mock Signed-off-by: yuye-aws * Remove workspace related constans from chrome Signed-off-by: yuye-aws * Remove workspace related props from chrome and core Signed-off-by: yuye-aws * Remove workspace related props from header Signed-off-by: yuye-aws * Shorten import path for workspace updater Signed-off-by: yuye-aws * Add euiIconType for workspace left menu category Signed-off-by: yuye-aws * Remove workspace related props for collapsible nav Signed-off-by: yuye-aws * Remove workspace related props for collapsible nav Signed-off-by: yuye-aws * Implement navigation for delete and exit workspace Signed-off-by: yuye-aws * Navigate external links through url change Signed-off-by: yuye-aws * Implement filteredNavLinks and sort ChromeNavLinks in nav link service Signed-off-by: yuye-aws * Add workspace list, see more, admin and overview into chromenavlinks Signed-off-by: yuye-aws * fix: unit test failure (#50) Signed-off-by: SuZhou-Joe * Fix osd bootstrap error Signed-off-by: yuye-aws * Check workspace enabled for left menu Signed-off-by: yuye-aws * Add home nav link to left menu when outside workspace Signed-off-by: yuye-aws * Fix unit test for collapsible nav Signed-off-by: yuye-aws * Fix unit test for header Signed-off-by: yuye-aws * Fix unit test for collapsible nav Signed-off-by: yuye-aws * Fix unit test for collapsible nav Signed-off-by: yuye-aws * Update snapshot for unit tests Signed-off-by: yuye-aws * fix osd bootstrap error Signed-off-by: yuye-aws * fix combinelatest import error Signed-off-by: yuye-aws * update snapshot for unit tests Signed-off-by: yuye-aws * variable rename Signed-off-by: yuye-aws * move custom nav link to mock props Signed-off-by: yuye-aws * move default filtered nav link to core Signed-off-by: yuye-aws * change navigation method in workspace updater Signed-off-by: yuye-aws * Update src/plugins/workspace/public/components/workspace_updater/workspace_updater.tsx Co-authored-by: SuZhou-Joe * revert some unncessary changes Signed-off-by: yuye-aws * fix navigation url bug Signed-off-by: yuye-aws * move default filtered nav link value setting from core to workspace plugin Signed-off-by: yuye-aws * move filter nav link to a new function Signed-off-by: yuye-aws * process filter nav links when workspace is disabled Signed-off-by: yuye-aws * change navigation method Signed-off-by: yuye-aws --------- Signed-off-by: SuZhoue-Joe Signed-off-by: yuye-aws Signed-off-by: tygao Signed-off-by: SuZhou-Joe Co-authored-by: SuZhoue-Joe Co-authored-by: raintygao * fix: osd bootstrap error (#57) * fix osd bootstrap error Signed-off-by: yuye-aws * fix build plugins error Signed-off-by: yuye-aws --------- Signed-off-by: yuye-aws * feat: filter out ADMIN application and add feature dependency logic (#49) * feat: filter out ADMIN application and add feature dependency logic Signed-off-by: Lin Wang * feat: separate feature utils function Signed-off-by: Lin Wang * feat: rename isFeatureDependBySelectedFeatures, separate generateFeatureDependencyMap and add annotation Signed-off-by: Lin Wang --------- Signed-off-by: Lin Wang * feat: do not register app when feature flag is off (#56) * feat: do not register app when feature flag is off Signed-off-by: SuZhou-Joe * feat: comply with the category name Signed-off-by: SuZhou-Joe * feat: opt according to PR Signed-off-by: SuZhou-Joe * feat: optimize the comment Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhou-Joe * Sort category and non-category nav link according to order in left menu (#60) * change order for home Signed-off-by: yuye-aws * Sort category and non-category navlink types in left menu Signed-off-by: yuye-aws * change order for overview when inside workspace Signed-off-by: yuye-aws * assign sorted unknowns to another variable Signed-off-by: yuye-aws * change annotation Signed-off-by: yuye-aws * refactor function getMergedNavLinks in left menu Signed-off-by: yuye-aws * fix zero order bug Signed-off-by: yuye-aws * add annotation Signed-off-by: yuye-aws --------- Signed-off-by: yuye-aws * Refactor: Assign default value for filtered nav links (#64) * remove default filtered nav link value set Signed-off-by: yuye-aws * default value for nav link Signed-off-by: yuye-aws * refactor currentworkspace logic Signed-off-by: yuye-aws --------- Signed-off-by: yuye-aws * Permission control service for saved objects (#63) * feat: move permission control to saved objects directory Signed-off-by: SuZhou-Joe * feat: use bulkGetObjects and fix unit test Signed-off-by: SuZhou-Joe * feat: add http routes for validate & list Signed-off-by: SuZhou-Joe * feat: move permissionModes to common place Signed-off-by: SuZhou-Joe * feat: rename routes Signed-off-by: SuZhou-Joe * feat: some side effects Signed-off-by: SuZhou-Joe * feat: some side effects Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhou-Joe * fix: make importing workspace-specific objects as copy Signed-off-by: SuZhou-Joe * feat: make unit test pass Signed-off-by: SuZhou-Joe * feat: revert the workspace change Signed-off-by: SuZhou-Joe * feat: make import support multiple workspaces Signed-off-by: SuZhou-Joe * feat: change logic Signed-off-by: SuZhou-Joe * feat: change logic Signed-off-by: SuZhou-Joe * fix: ci flow fail Signed-off-by: SuZhou-Joe * feat: copy to target workspace Signed-off-by: SuZhou-Joe * feat: revert changes Signed-off-by: SuZhou-Joe * feat: change public logic Signed-off-by: SuZhou-Joe * feat: update Signed-off-by: SuZhou-Joe * feat: revert some skipped test Signed-off-by: SuZhou-Joe * fix: type check Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: optimize logic Signed-off-by: SuZhou-Joe * feat: update logic Signed-off-by: SuZhou-Joe * temp: merge code Signed-off-by: SuZhou-Joe * fix: formatUrlWithWorkspaceId reference Signed-off-by: SuZhou-Joe * fix: remove useless export call Signed-off-by: SuZhou-Joe * fix: omitIds Signed-off-by: SuZhou-Joe --------- Signed-off-by: Yulong Ruan Signed-off-by: Hailong Cui Signed-off-by: SuZhoue-Joe Signed-off-by: Lin Wang Signed-off-by: zhichao-aws Signed-off-by: suzhou Signed-off-by: tygao Signed-off-by: gaobinlong Signed-off-by: yuye-aws Signed-off-by: SuZhou-Joe Co-authored-by: Yulong Ruan Co-authored-by: Hailong Cui Co-authored-by: Lin Wang Co-authored-by: zhichao-aws Co-authored-by: raintygao Co-authored-by: gaobinlong Co-authored-by: Yuye Zhu --- .../collapsible_nav.test.tsx.snap | 104 +++++------------ .../chrome/ui/header/collapsible_nav.test.tsx | 10 +- .../workspace/workspaces_service.mock.ts | 3 + .../public/workspace/workspaces_service.ts | 5 + .../saved_objects/import/check_conflicts.ts | 3 + .../import/import_saved_objects.ts | 9 +- .../saved_objects/import/regenerate_ids.ts | 39 ++++++- .../saved_objects/service/lib/repository.ts | 110 +++++++++++++----- .../server/saved_objects/service/lib/utils.ts | 7 ++ .../saved_objects_table.test.tsx.snap | 2 + .../__snapshots__/header.test.tsx.snap | 16 +++ src/plugins/workspace/common/constants.ts | 1 + src/plugins/workspace/public/application.tsx | 18 ++- .../components/workspace_fatal_error/index.ts | 6 + .../workspace_fatal_error.tsx | 67 +++++++++++ src/plugins/workspace/public/plugin.ts | 46 +++++++- .../workspace/public/workspace_client.ts | 46 ++++---- .../workspace_saved_objects_client_wrapper.ts | 15 ++- 18 files changed, 368 insertions(+), 139 deletions(-) create mode 100644 src/plugins/workspace/public/components/workspace_fatal_error/index.ts create mode 100644 src/plugins/workspace/public/components/workspace_fatal_error/workspace_fatal_error.tsx diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap index 7b88a0cac417..42aa2d4c596c 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap @@ -160,7 +160,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` "baseUrl": "/", "category": Object { "id": "opensearchDashboards", - "label": "Library", + "label": "OpenSearch Dashboards", "order": 1000, }, "data-test-subj": "discover", @@ -215,7 +215,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` "baseUrl": "/", "category": Object { "id": "opensearchDashboards", - "label": "Library", + "label": "OpenSearch Dashboards", "order": 1000, }, "data-test-subj": "visualize", @@ -228,7 +228,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` "baseUrl": "/", "category": Object { "id": "opensearchDashboards", - "label": "Library", + "label": "OpenSearch Dashboards", "order": 1000, }, "data-test-subj": "dashboard", @@ -1770,7 +1770,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` isCollapsible={true} key="opensearchDashboards" onToggle={[Function]} - title="Library" + title="OpenSearch Dashboards" > - Library + OpenSearch Dashboards @@ -1884,7 +1884,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` className="euiTitle euiTitle--xxsmall euiCollapsibleNavGroup__title" id="mockId__title" > - Library + OpenSearch Dashboards @@ -1912,7 +1912,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` className="euiCollapsibleNavGroup__children" >
    - Library + OpenSearch Dashboards @@ -4676,7 +4644,7 @@ exports[`CollapsibleNav with custom branding renders the nav bar in dark mode 1` className="euiTitle euiTitle--xxsmall euiCollapsibleNavGroup__title" id="mockId__title" > - Library + OpenSearch Dashboards
    @@ -4704,7 +4672,7 @@ exports[`CollapsibleNav with custom branding renders the nav bar in dark mode 1` className="euiCollapsibleNavGroup__children" >
      - Library + OpenSearch Dashboards @@ -6892,7 +6860,7 @@ exports[`CollapsibleNav without custom branding renders the nav bar in dark mode className="euiTitle euiTitle--xxsmall euiCollapsibleNavGroup__title" id="mockId__title" > - Library + OpenSearch Dashboards @@ -6920,7 +6888,7 @@ exports[`CollapsibleNav without custom branding renders the nav bar in dark mode className="euiCollapsibleNavGroup__children" >
        - Library + OpenSearch Dashboards @@ -7960,7 +7920,7 @@ exports[`CollapsibleNav without custom branding renders the nav bar in default m className="euiTitle euiTitle--xxsmall euiCollapsibleNavGroup__title" id="mockId__title" > - Library + OpenSearch Dashboards @@ -7988,7 +7948,7 @@ exports[`CollapsibleNav without custom branding renders the nav bar in default m className="euiCollapsibleNavGroup__children" >
          { }); it('remembers collapsible section state', () => { - /** - * TODO skip for workspace refractor, will revert once refractor the left menu part - */ - return; const navLinks = [ mockLink({ category: opensearchDashboards }), mockLink({ category: observability }), @@ -180,7 +176,7 @@ describe('CollapsibleNav', () => { recentlyAccessed$={new BehaviorSubject(recentNavLinks)} /> ); - expectShownNavLinksCount(component, 0); + expectShownNavLinksCount(component, 3); clickGroup(component, 'opensearchDashboards'); clickGroup(component, 'recentlyViewed'); expectShownNavLinksCount(component, 1); @@ -191,10 +187,6 @@ describe('CollapsibleNav', () => { }); it('closes the nav after clicking a link', () => { - /** - * TODO skip for workspace refractor, will revert once refractor the left menu part - */ - return; const onClose = sinon.spy(); const navLinks = [ mockLink({ category: opensearchDashboards }), diff --git a/src/core/public/workspace/workspaces_service.mock.ts b/src/core/public/workspace/workspaces_service.mock.ts index d9190c28176f..ee813fffa8f4 100644 --- a/src/core/public/workspace/workspaces_service.mock.ts +++ b/src/core/public/workspace/workspaces_service.mock.ts @@ -9,12 +9,14 @@ import { WorkspaceAttribute } from '..'; const currentWorkspaceId$ = new BehaviorSubject(''); const workspaceList$ = new BehaviorSubject([]); const currentWorkspace$ = new BehaviorSubject(null); +const hasFetchedWorkspaceList$ = new BehaviorSubject(false); const workspaceEnabled$ = new BehaviorSubject(false); const createWorkspacesSetupContractMock = () => ({ currentWorkspaceId$, workspaceList$, currentWorkspace$, + hasFetchedWorkspaceList$, workspaceEnabled$, registerWorkspaceMenuRender: jest.fn(), }); @@ -23,6 +25,7 @@ const createWorkspacesStartContractMock = () => ({ currentWorkspaceId$, workspaceList$, currentWorkspace$, + hasFetchedWorkspaceList$, workspaceEnabled$, renderWorkspaceMenu: jest.fn(), }); diff --git a/src/core/public/workspace/workspaces_service.ts b/src/core/public/workspace/workspaces_service.ts index 9a1504808551..9b386599cea0 100644 --- a/src/core/public/workspace/workspaces_service.ts +++ b/src/core/public/workspace/workspaces_service.ts @@ -23,6 +23,7 @@ export interface WorkspaceObservables { currentWorkspace$: BehaviorSubject; workspaceList$: BehaviorSubject; workspaceEnabled$: BehaviorSubject; + hasFetchedWorkspaceList$: BehaviorSubject; } /** @@ -40,6 +41,7 @@ export class WorkspaceService implements CoreService(''); private workspaceList$ = new BehaviorSubject([]); private currentWorkspace$ = new BehaviorSubject(null); + private hasFetchedWorkspaceList$ = new BehaviorSubject(false); private workspaceEnabled$ = new BehaviorSubject(false); private _renderWorkspaceMenu: WorkspaceMenuRenderFn | null = null; @@ -48,6 +50,7 @@ export class WorkspaceService implements CoreService (this._renderWorkspaceMenu = render), @@ -65,6 +68,7 @@ export class WorkspaceService implements CoreService @@ -56,6 +57,7 @@ export async function checkConflicts({ ignoreRegularConflicts, retries = [], createNewCopies, + workspaces, }: CheckConflictsParams) { const filteredObjects: Array> = []; const errors: SavedObjectsImportError[] = []; @@ -77,6 +79,7 @@ export async function checkConflicts({ }); const checkConflictsResult = await savedObjectsClient.checkConflicts(objectsToCheck, { namespace, + workspaces, }); const errorMap = checkConflictsResult.errors.reduce( (acc, { type, id, error }) => acc.set(`${type}:${id}`, error), diff --git a/src/core/server/saved_objects/import/import_saved_objects.ts b/src/core/server/saved_objects/import/import_saved_objects.ts index 68104db85e6f..9ef0c9209d62 100644 --- a/src/core/server/saved_objects/import/import_saved_objects.ts +++ b/src/core/server/saved_objects/import/import_saved_objects.ts @@ -38,7 +38,7 @@ import { validateReferences } from './validate_references'; import { checkOriginConflicts } from './check_origin_conflicts'; import { createSavedObjects } from './create_saved_objects'; import { checkConflicts } from './check_conflicts'; -import { regenerateIds } from './regenerate_ids'; +import { regenerateIds, regenerateIdsWithReference } from './regenerate_ids'; /** * Import saved objects from given stream. See the {@link SavedObjectsImportOptions | options} for more @@ -81,12 +81,19 @@ export async function importSavedObjectsFromStream({ if (createNewCopies) { importIdMap = regenerateIds(collectSavedObjectsResult.collectedObjects); } else { + importIdMap = await regenerateIdsWithReference({ + savedObjects: collectSavedObjectsResult.collectedObjects, + savedObjectsClient, + workspaces, + objectLimit, + }); // Check single-namespace objects for conflicts in this namespace, and check multi-namespace objects for conflicts across all namespaces const checkConflictsParams = { objects: collectSavedObjectsResult.collectedObjects, savedObjectsClient, namespace, ignoreRegularConflicts: overwrite, + workspaces, }; const checkConflictsResult = await checkConflicts(checkConflictsParams); errorAccumulator = [...errorAccumulator, ...checkConflictsResult.errors]; diff --git a/src/core/server/saved_objects/import/regenerate_ids.ts b/src/core/server/saved_objects/import/regenerate_ids.ts index 672a8f030620..1d998008b210 100644 --- a/src/core/server/saved_objects/import/regenerate_ids.ts +++ b/src/core/server/saved_objects/import/regenerate_ids.ts @@ -29,7 +29,8 @@ */ import { v4 as uuidv4 } from 'uuid'; -import { SavedObject } from '../types'; +import { SavedObject, SavedObjectsClientContract } from '../types'; +import { SavedObjectsUtils } from '../service'; /** * Takes an array of saved objects and returns an importIdMap of randomly-generated new IDs. @@ -42,3 +43,39 @@ export const regenerateIds = (objects: SavedObject[]) => { }, new Map()); return importIdMap; }; + +export const regenerateIdsWithReference = async (props: { + savedObjects: SavedObject[]; + savedObjectsClient: SavedObjectsClientContract; + workspaces?: string[]; + objectLimit: number; +}): Promise> => { + const { savedObjects, savedObjectsClient, workspaces } = props; + if (!workspaces || !workspaces.length) { + return savedObjects.reduce((acc, object) => { + return acc.set(`${object.type}:${object.id}`, { id: object.id, omitOriginId: false }); + }, new Map()); + } + + const bulkGetResult = await savedObjectsClient.bulkGet( + savedObjects.map((item) => ({ type: item.type, id: item.id })) + ); + + return bulkGetResult.saved_objects.reduce((acc, object) => { + if (object.error?.statusCode === 404) { + acc.set(`${object.type}:${object.id}`, { id: object.id, omitOriginId: true }); + return acc; + } + + const filteredWorkspaces = SavedObjectsUtils.filterWorkspacesAccordingToBaseWorkspaces( + workspaces, + object.workspaces + ); + if (filteredWorkspaces.length) { + acc.set(`${object.type}:${object.id}`, { id: uuidv4(), omitOriginId: true }); + } else { + acc.set(`${object.type}:${object.id}`, { id: object.id, omitOriginId: false }); + } + return acc; + }, new Map()); +}; diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index e479b1e95bc1..fcfe6eed0d91 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -378,15 +378,28 @@ export class SavedObjectsRepository { const method = object.id && overwrite ? 'index' : 'create'; const requiresNamespacesCheck = object.id && this._registry.isMultiNamespace(object.type); + /** + * Only when importing an object to a target workspace should we check if the object is workspace-specific. + */ + const requiresWorkspaceCheck = object.id; if (object.id == null) object.id = uuid.v1(); + let opensearchRequestIndexPayload = {}; + + if (requiresNamespacesCheck || requiresWorkspaceCheck) { + opensearchRequestIndexPayload = { + opensearchRequestIndex: bulkGetRequestIndexCounter, + }; + bulkGetRequestIndexCounter++; + } + return { tag: 'Right' as 'Right', value: { method, object, - ...(requiresNamespacesCheck && { opensearchRequestIndex: bulkGetRequestIndexCounter++ }), + ...opensearchRequestIndexPayload, }, }; }); @@ -397,7 +410,7 @@ export class SavedObjectsRepository { .map(({ value: { object: { type, id } } }) => ({ _id: this._serializer.generateRawId(namespace, type, id), _index: this.getIndexForType(type), - _source: ['type', 'namespaces'], + _source: ['type', 'namespaces', 'workspaces'], })); const bulkGetResponse = bulkGetDocs.length ? await this.client.mget( @@ -426,15 +439,8 @@ export class SavedObjectsRepository { method, } = expectedBulkGetResult.value; let savedObjectWorkspaces: string[] | undefined; - if (expectedBulkGetResult.value.method === 'create') { - if (options.workspaces) { - savedObjectWorkspaces = Array.from(new Set([...(options.workspaces || [])])); - } - } else if (object.workspaces) { - savedObjectWorkspaces = Array.from( - new Set([...object.workspaces, ...(options.workspaces || [])]) - ); - } + let finalMethod = method; + let finalObjectId = object.id; if (opensearchRequestIndex !== undefined) { const indexFound = bulkGetResponse?.statusCode !== 404; const actualResult = indexFound @@ -471,12 +477,57 @@ export class SavedObjectsRepository { versionProperties = getExpectedVersionProperties(version); } + if (expectedBulkGetResult.value.method === 'create') { + savedObjectWorkspaces = options.workspaces; + } else { + const changeToCreate = () => { + finalMethod = 'create'; + finalObjectId = object.id; + savedObjectWorkspaces = options.workspaces; + versionProperties = {}; + }; + /** + * When overwrite, need to check if the object is workspace-specific + * if so, copy object to target workspace instead of refering it. + */ + const rawId = this._serializer.generateRawId(namespace, object.type, object.id); + const findObject = + bulkGetResponse?.statusCode !== 404 + ? bulkGetResponse?.body.docs?.find((item) => item._id === rawId) + : null; + if (findObject && findObject.found) { + const transformedObject = this._serializer.rawToSavedObject( + findObject as SavedObjectsRawDoc + ) as SavedObject; + const filteredWorkspaces = SavedObjectsUtils.filterWorkspacesAccordingToBaseWorkspaces( + options.workspaces, + transformedObject.workspaces + ); + /** + * We need to create a new object when the object + * is about to import into workspaces it is not belong to + */ + if (filteredWorkspaces.length) { + /** + * Create a new object but only belong to the set of (target workspaces - original workspace) + */ + changeToCreate(); + finalObjectId = uuid.v1(); + savedObjectWorkspaces = filteredWorkspaces; + } else { + savedObjectWorkspaces = transformedObject.workspaces; + } + } else { + savedObjectWorkspaces = options.workspaces; + } + } + const expectedResult = { opensearchRequestIndex: bulkRequestIndexCounter++, - requestedId: object.id, + requestedId: finalObjectId, rawMigratedDoc: this._serializer.savedObjectToRaw( this._migrator.migrateDocument({ - id: object.id, + id: finalObjectId, type: object.type, attributes: object.attributes, migrationVersion: object.migrationVersion, @@ -492,7 +543,7 @@ export class SavedObjectsRepository { bulkCreateParams.push( { - [method]: { + [finalMethod]: { _id: expectedResult.rawMigratedDoc._id, _index: this.getIndexForType(object.type), ...(overwrite && versionProperties), @@ -583,7 +634,7 @@ export class SavedObjectsRepository { const bulkGetDocs = expectedBulkGetResults.filter(isRight).map(({ value: { type, id } }) => ({ _id: this._serializer.generateRawId(namespace, type, id), _index: this.getIndexForType(type), - _source: ['type', 'namespaces'], + _source: ['type', 'namespaces', 'workspaces'], })); const bulkGetResponse = bulkGetDocs.length ? await this.client.mget( @@ -606,17 +657,24 @@ export class SavedObjectsRepository { const { type, id, opensearchRequestIndex } = expectedResult.value; const doc = bulkGetResponse?.body.docs[opensearchRequestIndex]; if (doc?.found) { - errors.push({ - id, - type, - error: { - ...errorContent(SavedObjectsErrorHelpers.createConflictError(type, id)), - // @ts-expect-error MultiGetHit._source is optional - ...(!this.rawDocExistsInNamespace(doc!, namespace) && { - metadata: { isNotOverwritable: true }, - }), - }, - }); + const transformedObject = this._serializer.rawToSavedObject(doc as SavedObjectsRawDoc); + const filteredWorkspaces = SavedObjectsUtils.filterWorkspacesAccordingToBaseWorkspaces( + options.workspaces, + transformedObject.workspaces + ); + if (!filteredWorkspaces.length) { + errors.push({ + id, + type, + error: { + ...errorContent(SavedObjectsErrorHelpers.createConflictError(type, id)), + // @ts-expect-error MultiGetHit._source is optional + ...(!this.rawDocExistsInNamespace(doc!, namespace) && { + metadata: { isNotOverwritable: true }, + }), + }, + }); + } } }); diff --git a/src/core/server/saved_objects/service/lib/utils.ts b/src/core/server/saved_objects/service/lib/utils.ts index 4823e52d77c9..490c2b7083d2 100644 --- a/src/core/server/saved_objects/service/lib/utils.ts +++ b/src/core/server/saved_objects/service/lib/utils.ts @@ -80,4 +80,11 @@ export class SavedObjectsUtils { total: 0, saved_objects: [], }); + + public static filterWorkspacesAccordingToBaseWorkspaces( + targetWorkspaces?: string[], + baseWorkspaces?: string[] + ): string[] { + return targetWorkspaces?.filter((item) => !baseWorkspaces?.includes(item)) || []; + } } diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap index f4d98f644c11..5f33fe812f36 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap @@ -209,9 +209,11 @@ exports[`SavedObjectsTable should render normally 1`] = ` >
          + + + + + diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index ed48d8b11ec4..dc04cd6bb96b 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -10,6 +10,7 @@ export const WORKSPACE_CREATE_APP_ID = 'workspace_create'; export const WORKSPACE_LIST_APP_ID = 'workspace_list'; export const WORKSPACE_UPDATE_APP_ID = 'workspace_update'; export const WORKSPACE_OVERVIEW_APP_ID = 'workspace_overview'; +export const WORKSPACE_FATAL_ERROR_APP_ID = 'workspace_fatal_error'; export const PATHS = { create: '/create', overview: '/overview', diff --git a/src/plugins/workspace/public/application.tsx b/src/plugins/workspace/public/application.tsx index 000b89e5caeb..db83d8eeaacf 100644 --- a/src/plugins/workspace/public/application.tsx +++ b/src/plugins/workspace/public/application.tsx @@ -5,12 +5,13 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { AppMountParameters } from '../../../core/public'; +import { AppMountParameters, ScopedHistory } from '../../../core/public'; import { OpenSearchDashboardsContextProvider } from '../../opensearch_dashboards_react/public'; import { WorkspaceListApp } from './components/workspace_list_app'; import { WorkspaceCreatorApp } from './components/workspace_creator_app'; import { WorkspaceUpdaterApp } from './components/workspace_updater_app'; import { WorkspaceOverviewApp } from './components/workspace_overview_app'; +import { WorkspaceFatalError } from './components/workspace_fatal_error'; import { Services } from './types'; export const renderListApp = ( @@ -75,3 +76,18 @@ export const renderOverviewApp = ( ReactDOM.unmountComponentAtNode(element); }; }; + +export const renderFatalErrorApp = (params: AppMountParameters, services: Services) => { + const { element } = params; + const history = params.history as ScopedHistory<{ error?: string }>; + ReactDOM.render( + + + , + element + ); + + return () => { + ReactDOM.unmountComponentAtNode(element); + }; +}; diff --git a/src/plugins/workspace/public/components/workspace_fatal_error/index.ts b/src/plugins/workspace/public/components/workspace_fatal_error/index.ts new file mode 100644 index 000000000000..afb34b10d913 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_fatal_error/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { WorkspaceFatalError } from './workspace_fatal_error'; diff --git a/src/plugins/workspace/public/components/workspace_fatal_error/workspace_fatal_error.tsx b/src/plugins/workspace/public/components/workspace_fatal_error/workspace_fatal_error.tsx new file mode 100644 index 000000000000..0509eb095bce --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_fatal_error/workspace_fatal_error.tsx @@ -0,0 +1,67 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiButton, + EuiEmptyPrompt, + EuiPage, + EuiPageBody, + EuiPageContent, + EuiCallOut, +} from '@elastic/eui'; +import React from 'react'; +import { FormattedMessage } from '@osd/i18n/react'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { formatUrlWithWorkspaceId } from '../../utils'; + +export function WorkspaceFatalError(props: { error?: string }) { + const { + services: { application, http }, + } = useOpenSearchDashboards(); + const goBackToHome = () => { + window.location.href = formatUrlWithWorkspaceId( + application?.getUrlForApp('home') || '', + '', + http?.basePath + ); + }; + return ( + + + + + + + } + body={ +

          + +

          + } + actions={[ + + + , + ]} + /> + {props.error ? : null} +
          +
          +
          + ); +} diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 68342ee36c0b..529714026c37 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -23,6 +23,7 @@ import { WORKSPACE_CREATE_APP_ID, WORKSPACE_OVERVIEW_APP_ID, WORKSPACE_NAV_CATEGORY, + WORKSPACE_FATAL_ERROR_APP_ID, } from '../common/constants'; import { mountDropdownList } from './mount'; import { SavedObjectsManagementPluginSetup } from '../../saved_objects_management/public'; @@ -63,12 +64,34 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> if (workspaceId) { const result = await workspaceClient.enterWorkspace(workspaceId); if (!result.success) { - core.fatalErrors.add( - result.error || - i18n.translate('workspace.error.setup', { - defaultMessage: 'Workspace init failed', - }) - ); + /** + * Fatal error service does not support customized actions + * So we have to use a self-hosted page to show the errors and redirect. + */ + (async () => { + const [{ application, chrome }] = await core.getStartServices(); + chrome.setIsVisible(false); + application.navigateToApp(WORKSPACE_FATAL_ERROR_APP_ID, { + replace: true, + state: { + error: result.error, + }, + }); + })(); + } else { + /** + * If the workspace id is valid and user is currently on workspace_fatal_error page, + * we should redirect user to overview page of workspace. + */ + (async () => { + const [{ application }] = await core.getStartServices(); + const currentAppIdSubscription = application.currentAppId$.subscribe((currentAppId) => { + if (currentAppId === WORKSPACE_FATAL_ERROR_APP_ID) { + application.navigateToApp(WORKSPACE_OVERVIEW_APP_ID); + } + currentAppIdSubscription.unsubscribe(); + }); + })(); } } /** @@ -148,6 +171,17 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> }, }); + // workspace fatal error + core.application.register({ + id: WORKSPACE_FATAL_ERROR_APP_ID, + title: '', + navLinkStatus: AppNavLinkStatus.hidden, + async mount(params: AppMountParameters) { + const { renderFatalErrorApp } = await import('./application'); + return mountWorkspaceApp(params, renderFatalErrorApp); + }, + }); + return {}; } diff --git a/src/plugins/workspace/public/workspace_client.ts b/src/plugins/workspace/public/workspace_client.ts index 5e8080cba3f0..ab0b50c2b795 100644 --- a/src/plugins/workspace/public/workspace_client.ts +++ b/src/plugins/workspace/public/workspace_client.ts @@ -67,32 +67,34 @@ export class WorkspaceClient { this.http = http; this.workspaces = workspaces; - combineLatest([workspaces.workspaceList$, workspaces.currentWorkspaceId$]).subscribe( - ([workspaceList, currentWorkspaceId]) => { - if (workspaceList.length) { - const currentWorkspace = this.findWorkspace([workspaceList, currentWorkspaceId]); + combineLatest([ + workspaces.hasFetchedWorkspaceList$, + workspaces.workspaceList$, + workspaces.currentWorkspaceId$, + ]).subscribe(([hasFetchedWorkspaceList, workspaceList, currentWorkspaceId]) => { + if (hasFetchedWorkspaceList) { + const currentWorkspace = this.findWorkspace([workspaceList, currentWorkspaceId]); + + /** + * Do a simple idempotent verification here + */ + if (!isEqual(currentWorkspace, workspaces.currentWorkspace$.getValue())) { + workspaces.currentWorkspace$.next(currentWorkspace); + } + if (currentWorkspaceId && !currentWorkspace?.id) { /** - * Do a simple idempotent verification here + * Current workspace is staled */ - if (!isEqual(currentWorkspace, workspaces.currentWorkspace$.getValue())) { - workspaces.currentWorkspace$.next(currentWorkspace); - } - - if (currentWorkspaceId && !currentWorkspace?.id) { - /** - * Current workspace is staled - */ - workspaces.currentWorkspaceId$.error({ - reason: WORKSPACE_ERROR_REASON_MAP.WORKSPACE_STALED, - }); - workspaces.currentWorkspace$.error({ - reason: WORKSPACE_ERROR_REASON_MAP.WORKSPACE_STALED, - }); - } + workspaces.currentWorkspaceId$.error({ + reason: WORKSPACE_ERROR_REASON_MAP.WORKSPACE_STALED, + }); + workspaces.currentWorkspace$.error({ + reason: WORKSPACE_ERROR_REASON_MAP.WORKSPACE_STALED, + }); } } - ); + }); } /** @@ -160,6 +162,8 @@ export class WorkspaceClient { if (result?.success) { this.workspaces.workspaceList$.next(result.result.workspaces); } + + this.workspaces.hasFetchedWorkspaceList$.next(true); } public async enterWorkspace(id: string): Promise> { diff --git a/src/plugins/workspace/server/saved_objects/workspace_saved_objects_client_wrapper.ts b/src/plugins/workspace/server/saved_objects/workspace_saved_objects_client_wrapper.ts index 1c353e597af4..543fcdadae94 100644 --- a/src/plugins/workspace/server/saved_objects/workspace_saved_objects_client_wrapper.ts +++ b/src/plugins/workspace/server/saved_objects/workspace_saved_objects_client_wrapper.ts @@ -307,12 +307,23 @@ export class WorkspaceSavedObjectsClientWrapper { ] ); if (options.workspaces) { - const isEveryWorkspaceIsPermitted = options.workspaces.every((item) => + const permittedWorkspaces = options.workspaces.filter((item) => (permittedWorkspaceIds || []).includes(item) ); - if (!isEveryWorkspaceIsPermitted) { + if (!permittedWorkspaces.length) { + /** + * If user does not have any one workspace access + * deny the request + */ throw generateWorkspacePermissionError(); } + + /** + * Overwrite the options.workspaces when user has the access of partial workspaces. + * This mainly solve the problem that public workspace's ACL may be modified by dashboard_admin. + * And in custom workspace, we will fetch objects from public workspace and current custom workspace. + */ + options.workspaces = permittedWorkspaces; } else { const queryDSL = ACL.genereateGetPermittedSavedObjectsQueryDSL( [WorkspacePermissionMode.Read, WorkspacePermissionMode.Write],