diff --git a/changelogs/fragments/7636.yml b/changelogs/fragments/7636.yml new file mode 100644 index 00000000000..e154dc07a59 --- /dev/null +++ b/changelogs/fragments/7636.yml @@ -0,0 +1,2 @@ +fix: +- [Workspace] Move set default source order to avoid dev server crash ([#7636](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7636)) \ No newline at end of file diff --git a/src/plugins/workspace/server/workspace_client.test.ts b/src/plugins/workspace/server/workspace_client.test.ts index 4339d938034..f6e341603aa 100644 --- a/src/plugins/workspace/server/workspace_client.test.ts +++ b/src/plugins/workspace/server/workspace_client.test.ts @@ -181,6 +181,24 @@ describe('#WorkspaceClient', () => { expect(mockCheckAndSetDefaultDataSource).toHaveBeenCalledWith(uiSettingsClient, ['id1'], true); }); + it('update# should log error when failed set default data source', async () => { + const client = new WorkspaceClient(coreSetup, logger); + await client.setup(coreSetup); + client?.setSavedObjects(savedObjects); + client?.setUiSettings(uiSettings); + mockCheckAndSetDefaultDataSource.mockRejectedValueOnce(new Error()); + + await client.update(mockRequestDetail, mockWorkspaceId, { + name: mockWorkspaceName, + permissions: {}, + dataSources: ['id1'], + }); + + expect(logger.error).toHaveBeenLastCalledWith( + 'Set default data source error during workspace updating' + ); + }); + it('delete# should unassign data source before deleting related saved objects', async () => { const client = new WorkspaceClient(coreSetup, logger); await client.setup(coreSetup); diff --git a/src/plugins/workspace/server/workspace_client.ts b/src/plugins/workspace/server/workspace_client.ts index 7cc8bcec6ba..06476f5e23d 100644 --- a/src/plugins/workspace/server/workspace_client.ts +++ b/src/plugins/workspace/server/workspace_client.ts @@ -220,7 +220,7 @@ export class WorkspaceClient implements IWorkspaceClientImpl { const { permissions, dataSources: newDataSources, ...attributes } = payload; try { const client = this.getSavedObjectClientsFromRequestDetail(requestDetail); - const workspaceInDB: SavedObject = await client.get(WORKSPACE_TYPE, id); + let workspaceInDB: SavedObject = await client.get(WORKSPACE_TYPE, id); if (workspaceInDB.attributes.name !== attributes.name) { const existingWorkspaceRes = await this.getScopedClientWithoutPermission( requestDetail @@ -265,6 +265,22 @@ export class WorkspaceClient implements IWorkspaceClientImpl { } } + /** + * When the workspace owner unassign themselves, ensure the default data source is set before + * updating the workspace permissions. This prevents a lack of write permission on saved objects + * after the user is removed from the workspace. + **/ + if (newDataSources && this.uiSettings && client) { + const uiSettingsClient = this.uiSettings.asScopedToClient(client); + try { + await checkAndSetDefaultDataSource(uiSettingsClient, newDataSources, true); + // Doc version may changed after default data source updated. + workspaceInDB = await client.get(WORKSPACE_TYPE, id); + } catch (error) { + this.logger.error('Set default data source error during workspace updating'); + } + } + await client.create>( WORKSPACE_TYPE, { ...workspaceInDB.attributes, ...attributes }, @@ -276,11 +292,6 @@ export class WorkspaceClient implements IWorkspaceClientImpl { } ); - if (newDataSources && this.uiSettings && client) { - const uiSettingsClient = this.uiSettings.asScopedToClient(client); - checkAndSetDefaultDataSource(uiSettingsClient, newDataSources, true); - } - return { success: true, result: true,