From f32a0864abb1e92e184b03d563a18f9d3fe466e7 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Mon, 9 Sep 2024 12:23:27 +0200 Subject: [PATCH 01/20] CB-4461 replaces includeMetaParameters concept for resource in Team feature --- .../src/TeamInfoMetaParametersResource.ts | 62 +++++++++++++++++++ .../core-authentication/src/TeamsResource.ts | 21 +++---- .../packages/core-authentication/src/index.ts | 1 + .../core-authentication/src/manifest.ts | 1 + .../authentication/teams/createTeam.gql | 4 +- .../authentication/teams/getTeamsList.gql | 6 +- .../teams/getTeamsListMetaParameters.gql | 5 ++ .../authentication/teams/updateTeam.gql | 4 +- .../src/queries/fragments/AdminTeamInfo.gql | 3 +- .../fragments/AdminTeamInfoMetaParameters.gql | 3 + .../Users/Teams/Contexts/teamContext.ts | 4 +- .../Users/Teams/CreateTeamService.ts | 5 +- .../Users/Teams/ITeamFormProps.ts | 10 ++- .../Teams/Options/TeamOptionsTabService.ts | 8 +-- .../Users/Teams/TeamFormState.ts | 25 +++++--- .../Users/Teams/TeamsTable/TeamEdit.tsx | 5 +- .../Users/Teams/useTeamFormState.ts | 10 ++- 17 files changed, 133 insertions(+), 44 deletions(-) create mode 100644 webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts create mode 100644 webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsListMetaParameters.gql create mode 100644 webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfoMetaParameters.gql diff --git a/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts b/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts new file mode 100644 index 0000000000..21987208d3 --- /dev/null +++ b/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts @@ -0,0 +1,62 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { injectable } from '@cloudbeaver/core-di'; +import { CachedMapAllKey, CachedMapResource, isResourceAlias, ResourceKey, resourceKeyList, ResourceKeyUtils } from '@cloudbeaver/core-resource'; +import { GraphQLService } from '@cloudbeaver/core-sdk'; + +import { TeamMetaParameter } from './TeamMetaParametersResource'; +import { TeamsResource } from './TeamsResource'; + +@injectable() +export class TeamInfoMetaParametersResource extends CachedMapResource { + constructor( + private readonly graphQLService: GraphQLService, + private readonly teamsResource: TeamsResource, + ) { + super(); + + this.sync(this.teamsResource); + } + + protected async loader(param: ResourceKey): Promise> { + const all = this.aliases.isAlias(param, CachedMapAllKey); + const teamsList: [string, TeamMetaParameter][] = []; + + await ResourceKeyUtils.forEachAsync(param, async key => { + let teamId: string | undefined; + + if (!isResourceAlias(key)) { + teamId = key; + } + + const { teams } = await this.graphQLService.sdk.getTeamsListMetaParameters({ + teamId, + }); + const metaParameters = teams[0].metaParameters; + + if (teamId) { + teamsList.push([teamId, metaParameters]); + } + }); + + const key = resourceKeyList(teamsList.map(([teamId]) => teamId)); + const value = teamsList.map(([_, metaParameters]) => metaParameters); + + if (all) { + this.replace(key, value); + } else { + this.set(key, value); + } + + return this.data; + } + + protected validateKey(key: string): boolean { + return typeof key === 'string'; + } +} diff --git a/webapp/packages/core-authentication/src/TeamsResource.ts b/webapp/packages/core-authentication/src/TeamsResource.ts index 08373dfec0..23dbdd4fc3 100644 --- a/webapp/packages/core-authentication/src/TeamsResource.ts +++ b/webapp/packages/core-authentication/src/TeamsResource.ts @@ -24,6 +24,8 @@ import { } from '@cloudbeaver/core-sdk'; import { isArraysEqual, UndefinedToNull } from '@cloudbeaver/core-utils'; +import { TeamMetaParameter } from './TeamMetaParametersResource'; + const NEW_TEAM_SYMBOL = Symbol('new-team'); export type TeamInfo = AdminTeamInfoFragment; @@ -38,12 +40,14 @@ export class TeamsResource extends CachedMapResource { + async createTeam( + { teamId, teamPermissions, teamName, description }: TeamInfo, + metaParameters: Record, + ): Promise { const response = await this.graphQLService.sdk.createTeam({ teamId, teamName, description, - ...this.getDefaultIncludes(), ...this.getIncludesMap(teamId), }); @@ -61,12 +65,14 @@ export class TeamsResource extends CachedMapResource { + async updateTeam( + { teamId, teamPermissions, teamName, description }: TeamInfo, + metaParameters: Record, + ): Promise { const { team } = await this.graphQLService.sdk.updateTeam({ teamId, teamName, description, - ...this.getDefaultIncludes(), ...this.getIncludesMap(teamId), }); @@ -136,7 +142,6 @@ export class TeamsResource extends CachedMapResource import('./TeamMetaParametersResource').then(m => m.TeamMetaParametersResource), () => import('./TeamsManagerService').then(m => m.TeamsManagerService), () => import('./TeamsResource').then(m => m.TeamsResource), + () => import('./TeamInfoMetaParametersResource').then(m => m.TeamInfoMetaParametersResource), () => import('./TeamRolesResource').then(m => m.TeamRolesResource), () => import('./UserConfigurationBootstrap').then(m => m.UserConfigurationBootstrap), () => import('./UserDataService').then(m => m.UserDataService), diff --git a/webapp/packages/core-sdk/src/queries/authentication/teams/createTeam.gql b/webapp/packages/core-sdk/src/queries/authentication/teams/createTeam.gql index 7654ea781e..27e14f972c 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/teams/createTeam.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/createTeam.gql @@ -1,5 +1,5 @@ -query createTeam($teamId: ID!, $teamName: String, $description: String, $includeMetaParameters: Boolean!) { +query createTeam($teamId: ID!, $teamName: String, $description: String) { team: createTeam(teamId: $teamId, teamName: $teamName, description: $description) { ...AdminTeamInfo } -} \ No newline at end of file +} diff --git a/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsList.gql b/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsList.gql index fbbb425072..9286991546 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsList.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsList.gql @@ -1,5 +1,5 @@ -query getTeamsList($teamId: ID, $includeMetaParameters: Boolean!) { +query getTeamsList($teamId: ID) { teams: listTeams(teamId: $teamId) { ...AdminTeamInfo - } -} \ No newline at end of file + } +} diff --git a/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsListMetaParameters.gql b/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsListMetaParameters.gql new file mode 100644 index 0000000000..ee62bb6314 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsListMetaParameters.gql @@ -0,0 +1,5 @@ +query getTeamsListMetaParameters($teamId: ID) { + teams: listTeams(teamId: $teamId) { + ...AdminTeamInfoMetaParameters + } +} diff --git a/webapp/packages/core-sdk/src/queries/authentication/teams/updateTeam.gql b/webapp/packages/core-sdk/src/queries/authentication/teams/updateTeam.gql index 20bafa082b..a249d83c36 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/teams/updateTeam.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/updateTeam.gql @@ -1,5 +1,5 @@ -query updateTeam($teamId: ID!, $teamName: String, $description: String, $includeMetaParameters: Boolean!) { +query updateTeam($teamId: ID!, $teamName: String, $description: String) { team: updateTeam(teamId: $teamId, teamName: $teamName, description: $description) { ...AdminTeamInfo } -} \ No newline at end of file +} diff --git a/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfo.gql b/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfo.gql index 29bfda19d0..35fa371b29 100644 --- a/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfo.gql +++ b/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfo.gql @@ -3,5 +3,4 @@ fragment AdminTeamInfo on AdminTeamInfo { teamName description teamPermissions - metaParameters @include(if: $includeMetaParameters) -} \ No newline at end of file +} diff --git a/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfoMetaParameters.gql b/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfoMetaParameters.gql new file mode 100644 index 0000000000..6c66ffa7d0 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfoMetaParameters.gql @@ -0,0 +1,3 @@ +fragment AdminTeamInfoMetaParameters on AdminTeamInfo { + metaParameters +} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts index f48293450b..846e214eab 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts @@ -5,9 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import type { TeamInfo } from '@cloudbeaver/core-authentication'; +import { TeamInfoConfig } from '../ITeamFormProps'; -export function teamContext(): TeamInfo { +export function teamContext(): TeamInfoConfig { return { teamId: '', teamPermissions: [], diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/CreateTeamService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/CreateTeamService.ts index 4638430ebe..73ede56bfb 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/CreateTeamService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/CreateTeamService.ts @@ -7,7 +7,7 @@ */ import { makeObservable, observable } from 'mobx'; -import { TeamsResource } from '@cloudbeaver/core-authentication'; +import { TeamInfoMetaParametersResource, TeamsResource } from '@cloudbeaver/core-authentication'; import { injectable } from '@cloudbeaver/core-di'; import type { ITeamFormState } from './ITeamFormProps'; @@ -24,6 +24,7 @@ export class CreateTeamService { private readonly teamsAdministrationNavService: TeamsAdministrationNavService, private readonly teamFormService: TeamFormService, private readonly teamsResource: TeamsResource, + private readonly teamInfoMetaParametersResource: TeamInfoMetaParametersResource, ) { this.data = null; @@ -41,7 +42,7 @@ export class CreateTeamService { } fillData(): void { - this.data = new TeamFormState(this.teamFormService, this.teamsResource); + this.data = new TeamFormState(this.teamFormService, this.teamsResource, this.teamInfoMetaParametersResource); } create(): void { diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/ITeamFormProps.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/ITeamFormProps.ts index 4f186c39dd..46575e9df8 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/ITeamFormProps.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/ITeamFormProps.ts @@ -5,18 +5,22 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import type { TeamInfo, TeamsResource } from '@cloudbeaver/core-authentication'; +import type { TeamInfo, TeamMetaParameter, TeamsResource } from '@cloudbeaver/core-authentication'; import type { IExecutorHandlersCollection } from '@cloudbeaver/core-executor'; import type { MetadataMap } from '@cloudbeaver/core-utils'; export type TeamFormMode = 'edit' | 'create'; +export interface TeamInfoConfig extends TeamInfo { + metaParameters: Record; +} + export interface ITeamFormState { mode: TeamFormMode; - config: TeamInfo; + config: TeamInfoConfig; partsState: MetadataMap; - readonly info: TeamInfo | undefined; + readonly info: TeamInfoConfig | undefined; readonly statusMessage: string | null; readonly disabled: boolean; readonly readonly: boolean; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts index d5578fcdec..ff02edc114 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts @@ -74,7 +74,7 @@ export class TeamOptionsTabService extends Bootstrap { for (const key of Object.keys(config.metaParameters)) { if (typeof config.metaParameters[key] === 'string') { - config.metaParameters[key] = config.metaParameters[key].trim(); + config.metaParameters[key] = (config.metaParameters[key] as any).trim(); } } } @@ -102,17 +102,17 @@ export class TeamOptionsTabService extends Bootstrap { private async save({ state }: ITeamFormSubmitData, contexts: IExecutionContextProvider) { const status = contexts.getContext(this.teamFormService.configurationStatusContext); - const config = contexts.getContext(teamContext); + const { metaParameters, ...config } = contexts.getContext(teamContext); const create = state.mode === 'create'; try { if (create) { - const team = await this.teamResource.createTeam(config); + const team = await this.teamResource.createTeam(config, metaParameters); status.info('administration_teams_team_info_created'); status.info(team.teamId); } else { - const team = await this.teamResource.updateTeam(config); + const team = await this.teamResource.updateTeam(config, metaParameters); status.info('administration_teams_team_info_updated'); status.info(team.teamId); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts index bf6e39ca9c..fdf936bdd7 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts @@ -7,27 +7,33 @@ */ import { computed, makeObservable, observable } from 'mobx'; -import type { TeamInfo, TeamsResource } from '@cloudbeaver/core-authentication'; +import type { TeamInfo, TeamInfoMetaParametersResource, TeamsResource } from '@cloudbeaver/core-authentication'; import { Executor, IExecutionContextProvider, IExecutor } from '@cloudbeaver/core-executor'; import { MetadataMap } from '@cloudbeaver/core-utils'; import { teamFormConfigureContext } from './Contexts/teamFormConfigureContext'; import { ITeamFormStateInfo, teamFormStateContext } from './Contexts/teamFormStateContext'; -import type { ITeamFormState, ITeamFormSubmitData, TeamFormMode } from './ITeamFormProps'; +import type { ITeamFormState, ITeamFormSubmitData, TeamFormMode, TeamInfoConfig } from './ITeamFormProps'; import type { TeamFormService } from './TeamFormService'; export class TeamFormState implements ITeamFormState { mode: TeamFormMode; - config: TeamInfo; + config: TeamInfoConfig; statusMessage: string | null; configured: boolean; partsState: MetadataMap; - get info(): TeamInfo | undefined { + get info(): TeamInfoConfig | undefined { if (!this.config.teamId) { return undefined; } - return this.resource.get(this.config.teamId); + const info = this.resource.get(this.config.teamId) ?? {}; + const meta = this.teamInfoMetaParametersResource.get(this.config.teamId) ?? {}; + + return { + ...info, + metaParameters: meta, + } as TeamInfoConfig; } get loading(): boolean { @@ -43,6 +49,7 @@ export class TeamFormState implements ITeamFormState { } readonly resource: TeamsResource; + readonly teamInfoMetaParametersResource: TeamInfoMetaParametersResource; readonly service: TeamFormService; readonly submittingTask: IExecutor; @@ -51,8 +58,9 @@ export class TeamFormState implements ITeamFormState { private readonly loadTeamTask: IExecutor; private readonly formStateTask: IExecutor; - constructor(service: TeamFormService, resource: TeamsResource) { + constructor(service: TeamFormService, resource: TeamsResource, teamInfoMetaParametersResource: TeamInfoMetaParametersResource) { this.resource = resource; + this.teamInfoMetaParametersResource = teamInfoMetaParametersResource; this.config = { teamId: '', teamPermissions: [], @@ -110,7 +118,7 @@ export class TeamFormState implements ITeamFormState { return this; } - setConfig(config: TeamInfo): this { + setConfig(config: TeamInfoConfig): this { this.config = config; return this; } @@ -142,6 +150,7 @@ export class TeamFormState implements ITeamFormState { return; } - await this.resource.load(data.config.teamId, ['includeMetaParameters']); + await this.resource.load(data.config.teamId); + await this.teamInfoMetaParametersResource.load(data.config.teamId); } } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx index 967117c7ea..55604c7fe5 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx @@ -8,7 +8,7 @@ import { observer } from 'mobx-react-lite'; import { useCallback, useContext } from 'react'; -import { TeamsResource } from '@cloudbeaver/core-authentication'; +import { TeamInfoMetaParametersResource, TeamsResource } from '@cloudbeaver/core-authentication'; import { Container, s, TableContext, useS } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; @@ -23,13 +23,14 @@ interface Props { export const TeamEdit = observer(function TeamEdit({ item }) { const styles = useS(style); const resource = useService(TeamsResource); + const teamInfoMetaParametersResource = useService(TeamInfoMetaParametersResource); const tableContext = useContext(TableContext); const collapse = useCallback(() => { tableContext?.setItemExpand(item, false); }, [tableContext, item]); - const data = useTeamFormState(resource, state => state.setOptions('edit')); + const data = useTeamFormState(resource, teamInfoMetaParametersResource, state => state.setOptions('edit')); data.config.teamId = item; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/useTeamFormState.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/useTeamFormState.ts index 7a68826065..9874649b40 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/useTeamFormState.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/useTeamFormState.ts @@ -7,17 +7,21 @@ */ import { useState } from 'react'; -import type { TeamsResource } from '@cloudbeaver/core-authentication'; +import type { TeamInfoMetaParametersResource, TeamsResource } from '@cloudbeaver/core-authentication'; import { useService } from '@cloudbeaver/core-di'; import type { ITeamFormState } from './ITeamFormProps'; import { TeamFormService } from './TeamFormService'; import { TeamFormState } from './TeamFormState'; -export function useTeamFormState(resource: TeamsResource, configure?: (state: ITeamFormState) => any): ITeamFormState { +export function useTeamFormState( + resource: TeamsResource, + teamInfoMetaParametersResource: TeamInfoMetaParametersResource, + configure?: (state: ITeamFormState) => any, +): ITeamFormState { const service = useService(TeamFormService); const [state] = useState(() => { - const state = new TeamFormState(service, resource); + const state = new TeamFormState(service, resource, teamInfoMetaParametersResource); configure?.(state); state.load(); From 05093a5238e386af8535cca985286992f3471c29 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Wed, 11 Sep 2024 13:03:03 +0200 Subject: [PATCH 02/20] CB-4461 removes includeMetaParameters for users resources --- .../src/UserInfoMetaParametersResource.ts | 35 ++++++ .../src/UserInfoResource.ts | 1 - .../src/UsersMetaDataResource.ts | 112 ++++++++++++++++++ .../core-authentication/src/UsersResource.ts | 5 - .../packages/core-authentication/src/index.ts | 2 + .../core-authentication/src/manifest.ts | 2 + .../queries/authentication/getActiveUser.gql | 3 +- .../getActiveUserMetaParameters.gql | 5 + .../authentication/updateUserPreferences.gql | 8 +- .../authentication/users/createUser.gql | 16 +-- .../users/getAdminUserMetaParameters.gql | 5 + .../authentication/users/getUserById.gql | 2 +- .../authentication/users/getUsersList.gql | 2 +- .../users/getUsersMetaParametersList.gql | 6 + .../src/queries/fragments/AdminUserInfo.gql | 5 +- .../UserForm/Info/UserFormInfoCredentials.tsx | 7 +- .../Users/UserForm/Info/UserFormInfoPart.ts | 26 ++-- .../UserForm/Info/getUserFormInfoPart.ts | 5 +- .../UserProfileFormAuthenticationPart.ts | 11 +- .../getUserProfileFormAuthenticationPart.ts | 5 +- .../UserInfoPart/UserProfileFormInfoPart.ts | 18 ++- .../getUserProfileFormInfoPart.ts | 5 +- 22 files changed, 213 insertions(+), 73 deletions(-) create mode 100644 webapp/packages/core-authentication/src/UserInfoMetaParametersResource.ts create mode 100644 webapp/packages/core-authentication/src/UsersMetaDataResource.ts create mode 100644 webapp/packages/core-sdk/src/queries/authentication/getActiveUserMetaParameters.gql create mode 100644 webapp/packages/core-sdk/src/queries/authentication/users/getAdminUserMetaParameters.gql create mode 100644 webapp/packages/core-sdk/src/queries/authentication/users/getUsersMetaParametersList.gql diff --git a/webapp/packages/core-authentication/src/UserInfoMetaParametersResource.ts b/webapp/packages/core-authentication/src/UserInfoMetaParametersResource.ts new file mode 100644 index 0000000000..38cc888f18 --- /dev/null +++ b/webapp/packages/core-authentication/src/UserInfoMetaParametersResource.ts @@ -0,0 +1,35 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { injectable } from '@cloudbeaver/core-di'; +import { CachedDataResource, ResourceKey } from '@cloudbeaver/core-resource'; +import { GraphQLService } from '@cloudbeaver/core-sdk'; + +import { UserInfoResource } from './UserInfoResource'; +import { UserMetaParameter } from './UserMetaParametersResource'; + +@injectable() +export class UserInfoMetaParametersResource extends CachedDataResource { + constructor( + private readonly graphQLService: GraphQLService, + private readonly userInfoResource: UserInfoResource, + ) { + super(() => null, undefined); + + this.sync(this.userInfoResource); + } + + protected async loader(param: ResourceKey): Promise { + try { + const { user } = await this.graphQLService.sdk.getActiveUserMetaParameters(); + + return user?.metaParameters; + } catch (exception: any) { + return null; + } + } +} diff --git a/webapp/packages/core-authentication/src/UserInfoResource.ts b/webapp/packages/core-authentication/src/UserInfoResource.ts index 132327173a..b0af056c03 100644 --- a/webapp/packages/core-authentication/src/UserInfoResource.ts +++ b/webapp/packages/core-authentication/src/UserInfoResource.ts @@ -283,7 +283,6 @@ export class UserInfoResource extends CachedDataResource { + constructor( + private readonly graphQLService: GraphQLService, + private readonly usersResource: UsersResource, + ) { + super(); + + this.sync(this.usersResource); + } + + async setMetaParameters(userId: string, parameters: Record): Promise { + await this.graphQLService.sdk.saveUserMetaParameters({ userId, parameters }); + this.markOutdated(userId); + } + + // TODO after CB-5511 is merged. fix the logic according to the UsersResource loader + protected async loader(originalKey: ResourceKey): Promise> { + const all = this.aliases.isAlias(originalKey, CachedMapAllKey); + const keys: string[] = []; + + if (all) { + throw new Error('Loading all users is prohibited'); + } + + const userMetaParametersList: UserMetaParameter[] = []; + + await ResourceKeyUtils.forEachAsync(originalKey, async key => { + let userId: string | undefined; + + if (!isResourceAlias(key)) { + userId = key; + } + + if (userId !== undefined) { + const { user } = await this.graphQLService.sdk.getAdminUserMetaParameters({ + userId, + }); + + keys.push(userId); + userMetaParametersList.push(user.metaParameters); + } else { + const pageKey = + this.aliases.isAlias(originalKey, CachedResourceOffsetPageKey) || this.aliases.isAlias(originalKey, CachedResourceOffsetPageListKey); + const filterKey = this.aliases.isAlias(originalKey, UsersResourceFilterKey); + let offset = CACHED_RESOURCE_DEFAULT_PAGE_OFFSET; + let limit = CACHED_RESOURCE_DEFAULT_PAGE_LIMIT; + let userIdMask: string | undefined; + let enabledState: boolean | undefined; + + if (pageKey) { + offset = pageKey.options.offset; + limit = pageKey.options.limit; + } + + if (filterKey) { + userIdMask = filterKey.options.userId; + enabledState = filterKey.options.enabledState; + } + + const { users } = await this.graphQLService.sdk.getUsersMetaParametersList({ + page: { + offset, + limit, + }, + filter: { + userIdMask, + enabledState, + }, + }); + + userMetaParametersList.push(...users.map(user => user.metaParameters)); + keys.push(...users.map(user => user.userId)); + + this.offsetPagination.setPageEnd(CachedResourceOffsetPageListKey(offset, users.length).setTarget(filterKey), users.length === limit); + } + }); + + this.set(resourceKeyList(keys), userMetaParametersList); + + return this.data; + } + + protected validateKey(key: string): boolean { + return typeof key === 'string'; + } +} diff --git a/webapp/packages/core-authentication/src/UsersResource.ts b/webapp/packages/core-authentication/src/UsersResource.ts index a28b2571aa..eb09e4a13e 100644 --- a/webapp/packages/core-authentication/src/UsersResource.ts +++ b/webapp/packages/core-authentication/src/UsersResource.ts @@ -130,10 +130,6 @@ export class UsersResource extends CachedMapResource): Promise { - await this.graphQLService.sdk.saveUserMetaParameters({ userId, parameters }); - } - async create({ userId, authRole }: UserCreateOptions): Promise { const { user } = await this.graphQLService.sdk.createUser({ userId, @@ -303,7 +299,6 @@ export class UsersResource extends CachedMapResource import('./UserDataService').then(m => m.UserDataService), () => import('./UserInfoResource').then(m => m.UserInfoResource), () => import('./UserMetaParametersResource').then(m => m.UserMetaParametersResource), + () => import('./UserInfoMetaParametersResource').then(m => m.UserInfoMetaParametersResource), + () => import('./UsersMetaDataResource').then(m => m.UsersMetaParametersResource), () => import('./UsersResource').then(m => m.UsersResource), ], }; diff --git a/webapp/packages/core-sdk/src/queries/authentication/getActiveUser.gql b/webapp/packages/core-sdk/src/queries/authentication/getActiveUser.gql index 6e8bca4484..a0d4c9ac9e 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/getActiveUser.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/getActiveUser.gql @@ -1,10 +1,9 @@ -query getActiveUser($includeMetaParameters: Boolean!, $includeConfigurationParameters: Boolean!, $customIncludeOriginDetails: Boolean!) { +query getActiveUser($includeConfigurationParameters: Boolean!, $customIncludeOriginDetails: Boolean!) { user: activeUser { userId displayName authRole linkedAuthProviders - metaParameters @include(if: $includeMetaParameters) configurationParameters @include(if: $includeConfigurationParameters) teams { teamId diff --git a/webapp/packages/core-sdk/src/queries/authentication/getActiveUserMetaParameters.gql b/webapp/packages/core-sdk/src/queries/authentication/getActiveUserMetaParameters.gql new file mode 100644 index 0000000000..4476f11be2 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/getActiveUserMetaParameters.gql @@ -0,0 +1,5 @@ +query getActiveUserMetaParameters { + user: activeUser { + metaParameters + } +} diff --git a/webapp/packages/core-sdk/src/queries/authentication/updateUserPreferences.gql b/webapp/packages/core-sdk/src/queries/authentication/updateUserPreferences.gql index 51e93b791e..acfe93a0d9 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/updateUserPreferences.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/updateUserPreferences.gql @@ -1,15 +1,9 @@ -mutation updateUserPreferences( - $preferences: Object! - $includeMetaParameters: Boolean! - $includeConfigurationParameters: Boolean! - $customIncludeOriginDetails: Boolean! -) { +mutation updateUserPreferences($preferences: Object!, $includeConfigurationParameters: Boolean!, $customIncludeOriginDetails: Boolean!) { user: setUserPreferences(preferences: $preferences) { userId displayName authRole linkedAuthProviders - metaParameters @include(if: $includeMetaParameters) configurationParameters @include(if: $includeConfigurationParameters) teams { teamId diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/createUser.gql b/webapp/packages/core-sdk/src/queries/authentication/users/createUser.gql index d17b1a6f21..8165ba7e46 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/users/createUser.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/users/createUser.gql @@ -1,15 +1,5 @@ -query createUser( - $userId: ID! - $enabled: Boolean! - $authRole: String - $includeMetaParameters: Boolean! - $customIncludeOriginDetails: Boolean! - ) { - user: createUser( - userId: $userId - enabled: $enabled - authRole: $authRole - ) { +query createUser($userId: ID!, $enabled: Boolean!, $authRole: String, $customIncludeOriginDetails: Boolean!) { + user: createUser(userId: $userId, enabled: $enabled, authRole: $authRole) { ...AdminUserInfo } -} \ No newline at end of file +} diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/getAdminUserMetaParameters.gql b/webapp/packages/core-sdk/src/queries/authentication/users/getAdminUserMetaParameters.gql new file mode 100644 index 0000000000..2078d1678d --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/users/getAdminUserMetaParameters.gql @@ -0,0 +1,5 @@ +query getAdminUserMetaParameters($userId: ID!) { + user: adminUserInfo(userId: $userId) { + metaParameters + } +} diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/getUserById.gql b/webapp/packages/core-sdk/src/queries/authentication/users/getUserById.gql index b4ff8c390e..1f009a27c4 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/users/getUserById.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/users/getUserById.gql @@ -1,4 +1,4 @@ -query getAdminUserInfo($userId: ID!, $includeMetaParameters: Boolean!, $customIncludeOriginDetails: Boolean!) { +query getAdminUserInfo($userId: ID!, $customIncludeOriginDetails: Boolean!) { user: adminUserInfo(userId: $userId) { ...AdminUserInfo } diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/getUsersList.gql b/webapp/packages/core-sdk/src/queries/authentication/users/getUsersList.gql index fd0f1c5eeb..fa4772904a 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/users/getUsersList.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/users/getUsersList.gql @@ -1,4 +1,4 @@ -query getUsersList($page: PageInput!, $filter: AdminUserFilterInput!, $includeMetaParameters: Boolean!, $customIncludeOriginDetails: Boolean!) { +query getUsersList($page: PageInput!, $filter: AdminUserFilterInput!, $customIncludeOriginDetails: Boolean!) { users: listUsers(page: $page, filter: $filter) { ...AdminUserInfo } diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/getUsersMetaParametersList.gql b/webapp/packages/core-sdk/src/queries/authentication/users/getUsersMetaParametersList.gql new file mode 100644 index 0000000000..9e1d01be5e --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/users/getUsersMetaParametersList.gql @@ -0,0 +1,6 @@ +query getUsersMetaParametersList($page: PageInput!, $filter: AdminUserFilterInput!) { + users: listUsers(page: $page, filter: $filter) { + userId + metaParameters + } +} diff --git a/webapp/packages/core-sdk/src/queries/fragments/AdminUserInfo.gql b/webapp/packages/core-sdk/src/queries/fragments/AdminUserInfo.gql index 11cf7871dc..ef1ced7fef 100644 --- a/webapp/packages/core-sdk/src/queries/fragments/AdminUserInfo.gql +++ b/webapp/packages/core-sdk/src/queries/fragments/AdminUserInfo.gql @@ -2,11 +2,10 @@ fragment AdminUserInfo on AdminUserInfo { userId grantedTeams linkedAuthProviders - metaParameters @include(if: $includeMetaParameters) - + origins { ...ObjectOriginInfo } enabled authRole -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoCredentials.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoCredentials.tsx index 5a7458ab63..e1c71df681 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoCredentials.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoCredentials.tsx @@ -34,12 +34,7 @@ interface Props extends UserFormProps { export const UserFormInfoCredentials = observer(function UserFormInfoCredentials({ formState, tabState, tabSelected, disabled }) { const translate = useTranslate(); const editing = formState.mode === FormMode.Edit; - const userInfo = useResource( - UserFormInfoCredentials, - UsersResource, - { key: tabState.initialState.userId, includes: ['includeMetaParameters'] }, - { active: tabSelected && editing }, - ); + const userInfo = useResource(UserFormInfoCredentials, UsersResource, tabState.initialState.userId, { active: tabSelected && editing }); const authProvidersResource = useResource(UserFormInfoCredentials, AuthProvidersResource, null); const passwordValidationRef = usePasswordValidation(); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoPart.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoPart.ts index e4bcf5ba5f..f571968b46 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoPart.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoPart.ts @@ -7,11 +7,10 @@ */ import { observable, toJS } from 'mobx'; -import type { AdminUser, AuthRolesResource, UserResourceIncludes, UsersResource } from '@cloudbeaver/core-authentication'; +import type { AdminUser, AuthRolesResource, UserMetaParameter, UsersMetaParametersResource, UsersResource } from '@cloudbeaver/core-authentication'; import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; -import { CachedResourceIncludeArgs, getCachedDataResourceLoaderState } from '@cloudbeaver/core-resource'; +import { getCachedDataResourceLoaderState } from '@cloudbeaver/core-resource'; import type { ServerConfigResource } from '@cloudbeaver/core-root'; -import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; import { FormMode, FormPart, formValidationContext, IFormState } from '@cloudbeaver/core-ui'; import { isArraysEqual, isDefined, isObjectsEqual, isValuesEqual } from '@cloudbeaver/core-utils'; import { DATA_CONTEXT_LOADABLE_STATE } from '@cloudbeaver/core-view'; @@ -22,12 +21,12 @@ import type { IUserFormInfoState } from './IUserFormInfoState'; const DEFAULT_ENABLED = true; export class UserFormInfoPart extends FormPart { - private baseIncludes: CachedResourceIncludeArgs; constructor( private readonly authRolesResource: AuthRolesResource, private readonly serverConfigResource: ServerConfigResource, formState: IFormState, private readonly usersResource: UsersResource, + private readonly usersMetaParametersResource: UsersMetaParametersResource, ) { super(formState, { userId: formState.state.userId || '', @@ -37,7 +36,6 @@ export class UserFormInfoPart extends FormPart, contexts: IExecutionContextProvider>): void | Promise { @@ -59,7 +57,7 @@ export class UserFormInfoPart extends FormPart): User const usersResource = di.getService(UsersResource); const serverConfigResource = di.getService(ServerConfigResource); const authRolesResource = di.getService(AuthRolesResource); + const usersMetaParametersResource = di.getService(UsersMetaParametersResource); - return new UserFormInfoPart(authRolesResource, serverConfigResource, formState, usersResource); + return new UserFormInfoPart(authRolesResource, serverConfigResource, formState, usersResource, usersMetaParametersResource); }); } diff --git a/webapp/packages/plugin-user-profile/src/UserProfileForm/UserAuthenticationPart/UserProfileFormAuthenticationPart.ts b/webapp/packages/plugin-user-profile/src/UserProfileForm/UserAuthenticationPart/UserProfileFormAuthenticationPart.ts index 243bc0244f..fe6058cdbe 100644 --- a/webapp/packages/plugin-user-profile/src/UserProfileForm/UserAuthenticationPart/UserProfileFormAuthenticationPart.ts +++ b/webapp/packages/plugin-user-profile/src/UserProfileForm/UserAuthenticationPart/UserProfileFormAuthenticationPart.ts @@ -5,10 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import type { PasswordPolicyService, UserInfoResource, UserResourceIncludes } from '@cloudbeaver/core-authentication'; +import type { PasswordPolicyService, UserInfoMetaParametersResource, UserInfoResource, UserResourceIncludes } from '@cloudbeaver/core-authentication'; import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; -import type { CachedResourceIncludeArgs } from '@cloudbeaver/core-resource'; -import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; import { FormPart, formValidationContext, IFormState } from '@cloudbeaver/core-ui'; import { isValuesEqual, schemaValidationError } from '@cloudbeaver/core-utils'; @@ -16,18 +14,17 @@ import type { IUserProfileFormState } from '../UserProfileFormService'; import { type IUserProfileFormAuthenticationState, USER_PROFILE_FORM_AUTHENTICATION_PART_STATE_SCHEMA } from './IUserProfileFormAuthenticationState'; export class UserProfileFormAuthenticationPart extends FormPart { - private baseIncludes: CachedResourceIncludeArgs; constructor( formState: IFormState, private readonly userInfoResource: UserInfoResource, private readonly passwordPolicyService: PasswordPolicyService, + private readonly userInfoMetaParametersResource: UserInfoMetaParametersResource, ) { super(formState, { oldPassword: '', password: '', repeatedPassword: '', }); - this.baseIncludes = ['includeMetaParameters']; } protected format(data: IFormState, contexts: IExecutionContextProvider>): void { @@ -37,11 +34,11 @@ export class UserProfileFormAuthenticationPart extends FormPart { - private baseIncludes: CachedResourceIncludeArgs; constructor( formState: IFormState, private readonly userInfoResource: UserInfoResource, + private readonly userInfoMetaParametersResource: UserInfoMetaParametersResource, ) { super(formState, { userId: userInfoResource.data?.userId || '', displayName: userInfoResource.data?.displayName || '', authRole: userInfoResource.data?.authRole || '', - metaParameters: toJS(userInfoResource.data?.metaParameters || {}), + metaParameters: toJS(userInfoMetaParametersResource.data || {}), }); - this.baseIncludes = ['includeMetaParameters']; } protected format(data: IFormState, contexts: IExecutionContextProvider>): void { @@ -37,11 +34,11 @@ export class UserProfileFormInfoPart extends FormPart { const di = context.get(DATA_CONTEXT_DI_PROVIDER)!; const userInfoResource = di.getService(UserInfoResource); + const userInfoMetaParametersResource = di.getService(UserInfoMetaParametersResource); - return new UserProfileFormInfoPart(formState, userInfoResource); + return new UserProfileFormInfoPart(formState, userInfoResource, userInfoMetaParametersResource); }); } From e20583b7ad1863054cb2a93ecb933c6e512cd2fd Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Fri, 13 Sep 2024 12:17:13 +0200 Subject: [PATCH 03/20] CB-4461 removes includeOriginDetails for users --- .../src/UserInfoResource.ts | 5 +- .../src/UsersOriginDetailsResource.ts | 105 ++++++++++++++++++ .../core-authentication/src/UsersResource.ts | 9 -- .../packages/core-authentication/src/index.ts | 1 + .../core-authentication/src/manifest.ts | 1 + .../src/queries/authentication/authLogin.gql | 9 +- .../queries/authentication/getActiveUser.gql | 2 +- .../queries/authentication/getAuthStatus.gql | 23 ++-- .../authentication/updateUserPreferences.gql | 2 +- .../authentication/users/createUser.gql | 2 +- .../users/getAdminUserOriginDetails.gql | 5 + .../authentication/users/getUserById.gql | 2 +- .../authentication/users/getUsersList.gql | 2 +- .../users/getUsersOriginDetailsList.gql | 6 + .../queries/fragments/AdminOriginDetails.gql | 5 + .../queries/fragments/ObjectOriginInfo.gql | 17 +-- .../src/queries/fragments/OriginDetails.gql | 16 +++ .../Origin/UserFormOriginInfoPanel.tsx | 19 ++-- 18 files changed, 164 insertions(+), 67 deletions(-) create mode 100644 webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts create mode 100644 webapp/packages/core-sdk/src/queries/authentication/users/getAdminUserOriginDetails.gql create mode 100644 webapp/packages/core-sdk/src/queries/authentication/users/getUsersOriginDetailsList.gql create mode 100644 webapp/packages/core-sdk/src/queries/fragments/AdminOriginDetails.gql create mode 100644 webapp/packages/core-sdk/src/queries/fragments/OriginDetails.gql diff --git a/webapp/packages/core-authentication/src/UserInfoResource.ts b/webapp/packages/core-authentication/src/UserInfoResource.ts index b0af056c03..fc82e5a8e9 100644 --- a/webapp/packages/core-authentication/src/UserInfoResource.ts +++ b/webapp/packages/core-authentication/src/UserInfoResource.ts @@ -53,7 +53,7 @@ export class UserInfoResource extends CachedDataResource null, undefined, ['customIncludeOriginDetails', 'includeConfigurationParameters']); + super(() => null, undefined, ['includeConfigurationParameters']); this.onUserChange = new SyncExecutor(); this.onException = new SyncExecutor(); @@ -103,7 +103,6 @@ export class UserInfoResource extends CachedDataResource { + constructor( + private readonly graphQLService: GraphQLService, + private readonly usersResource: UsersResource, + ) { + super(); + + this.sync(this.usersResource); + } + + protected async loader(originalKey: ResourceKey): Promise> { + const all = this.aliases.isAlias(originalKey, CachedMapAllKey); + const keys: string[] = []; + + if (all) { + throw new Error('Loading all users is prohibited'); + } + + const userMetaParametersList: AdminOriginDetailsFragment[] = []; + + await ResourceKeyUtils.forEachAsync(originalKey, async key => { + let userId: string | undefined; + + if (!isResourceAlias(key)) { + userId = key; + } + + if (userId !== undefined) { + const { user } = await this.graphQLService.sdk.getAdminUserOriginDetails({ + userId, + }); + + keys.push(userId); + userMetaParametersList.push(user); + } else { + const pageKey = + this.aliases.isAlias(originalKey, CachedResourceOffsetPageKey) || this.aliases.isAlias(originalKey, CachedResourceOffsetPageListKey); + const filterKey = this.aliases.isAlias(originalKey, UsersResourceFilterKey); + let offset = CACHED_RESOURCE_DEFAULT_PAGE_OFFSET; + let limit = CACHED_RESOURCE_DEFAULT_PAGE_LIMIT; + let userIdMask: string | undefined; + let enabledState: boolean | undefined; + + if (pageKey) { + offset = pageKey.options.offset; + limit = pageKey.options.limit; + } + + if (filterKey) { + userIdMask = filterKey.options.userId; + enabledState = filterKey.options.enabledState; + } + + const { users } = await this.graphQLService.sdk.getUsersOriginDetailsList({ + page: { + offset, + limit, + }, + filter: { + userIdMask, + enabledState, + }, + }); + + userMetaParametersList.push(...users); + keys.push(...users.map(user => user.userId)); + + this.offsetPagination.setPageEnd(CachedResourceOffsetPageListKey(offset, users.length).setTarget(filterKey), users.length === limit); + } + }); + + this.set(resourceKeyList(keys), userMetaParametersList); + + return this.data; + } + + protected validateKey(key: string): boolean { + return typeof key === 'string'; + } +} diff --git a/webapp/packages/core-authentication/src/UsersResource.ts b/webapp/packages/core-authentication/src/UsersResource.ts index eb09e4a13e..cb3347f8d1 100644 --- a/webapp/packages/core-authentication/src/UsersResource.ts +++ b/webapp/packages/core-authentication/src/UsersResource.ts @@ -135,7 +135,6 @@ export class UsersResource extends CachedMapResource import('./UserMetaParametersResource').then(m => m.UserMetaParametersResource), () => import('./UserInfoMetaParametersResource').then(m => m.UserInfoMetaParametersResource), () => import('./UsersMetaDataResource').then(m => m.UsersMetaParametersResource), + () => import('./UsersOriginDetailsResource').then(m => m.UsersOriginDetailsResource), () => import('./UsersResource').then(m => m.UsersResource), ], }; diff --git a/webapp/packages/core-sdk/src/queries/authentication/authLogin.gql b/webapp/packages/core-sdk/src/queries/authentication/authLogin.gql index cbb0ea8b7f..60678fe692 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/authLogin.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/authLogin.gql @@ -1,11 +1,4 @@ -query authLogin( - $provider: ID! - $configuration: ID - $credentials: Object - $linkUser: Boolean - $customIncludeOriginDetails: Boolean! - $forceSessionsLogout: Boolean -) { +query authLogin($provider: ID!, $configuration: ID, $credentials: Object, $linkUser: Boolean, $forceSessionsLogout: Boolean) { authInfo: authLogin( provider: $provider configuration: $configuration diff --git a/webapp/packages/core-sdk/src/queries/authentication/getActiveUser.gql b/webapp/packages/core-sdk/src/queries/authentication/getActiveUser.gql index a0d4c9ac9e..1419b31c6c 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/getActiveUser.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/getActiveUser.gql @@ -1,4 +1,4 @@ -query getActiveUser($includeConfigurationParameters: Boolean!, $customIncludeOriginDetails: Boolean!) { +query getActiveUser($includeConfigurationParameters: Boolean!) { user: activeUser { userId displayName diff --git a/webapp/packages/core-sdk/src/queries/authentication/getAuthStatus.gql b/webapp/packages/core-sdk/src/queries/authentication/getAuthStatus.gql index 57f3446b30..add143143d 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/getAuthStatus.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/getAuthStatus.gql @@ -1,17 +1,10 @@ -query getAuthStatus( - $authId: ID! - $linkUser: Boolean - $customIncludeOriginDetails: Boolean! -) { - authInfo: authUpdateStatus( - authId: $authId, - linkUser: $linkUser - ) { - redirectLink - authId - authStatus - userTokens { - ...AuthToken - } +query getAuthStatus($authId: ID!, $linkUser: Boolean) { + authInfo: authUpdateStatus(authId: $authId, linkUser: $linkUser) { + redirectLink + authId + authStatus + userTokens { + ...AuthToken } + } } diff --git a/webapp/packages/core-sdk/src/queries/authentication/updateUserPreferences.gql b/webapp/packages/core-sdk/src/queries/authentication/updateUserPreferences.gql index acfe93a0d9..2a13182cb3 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/updateUserPreferences.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/updateUserPreferences.gql @@ -1,4 +1,4 @@ -mutation updateUserPreferences($preferences: Object!, $includeConfigurationParameters: Boolean!, $customIncludeOriginDetails: Boolean!) { +mutation updateUserPreferences($preferences: Object!, $includeConfigurationParameters: Boolean!) { user: setUserPreferences(preferences: $preferences) { userId displayName diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/createUser.gql b/webapp/packages/core-sdk/src/queries/authentication/users/createUser.gql index 8165ba7e46..649a332167 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/users/createUser.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/users/createUser.gql @@ -1,4 +1,4 @@ -query createUser($userId: ID!, $enabled: Boolean!, $authRole: String, $customIncludeOriginDetails: Boolean!) { +query createUser($userId: ID!, $enabled: Boolean!, $authRole: String) { user: createUser(userId: $userId, enabled: $enabled, authRole: $authRole) { ...AdminUserInfo } diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/getAdminUserOriginDetails.gql b/webapp/packages/core-sdk/src/queries/authentication/users/getAdminUserOriginDetails.gql new file mode 100644 index 0000000000..749ddb6308 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/users/getAdminUserOriginDetails.gql @@ -0,0 +1,5 @@ +query getAdminUserOriginDetails($userId: ID!) { + user: adminUserInfo(userId: $userId) { + ...AdminOriginDetails + } +} diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/getUserById.gql b/webapp/packages/core-sdk/src/queries/authentication/users/getUserById.gql index 1f009a27c4..24cf53dec3 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/users/getUserById.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/users/getUserById.gql @@ -1,4 +1,4 @@ -query getAdminUserInfo($userId: ID!, $customIncludeOriginDetails: Boolean!) { +query getAdminUserInfo($userId: ID!) { user: adminUserInfo(userId: $userId) { ...AdminUserInfo } diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/getUsersList.gql b/webapp/packages/core-sdk/src/queries/authentication/users/getUsersList.gql index fa4772904a..9f7377b8c3 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/users/getUsersList.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/users/getUsersList.gql @@ -1,4 +1,4 @@ -query getUsersList($page: PageInput!, $filter: AdminUserFilterInput!, $customIncludeOriginDetails: Boolean!) { +query getUsersList($page: PageInput!, $filter: AdminUserFilterInput!) { users: listUsers(page: $page, filter: $filter) { ...AdminUserInfo } diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/getUsersOriginDetailsList.gql b/webapp/packages/core-sdk/src/queries/authentication/users/getUsersOriginDetailsList.gql new file mode 100644 index 0000000000..0eae403825 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/users/getUsersOriginDetailsList.gql @@ -0,0 +1,6 @@ +query getUsersOriginDetailsList($page: PageInput!, $filter: AdminUserFilterInput!) { + users: listUsers(page: $page, filter: $filter) { + userId + ...AdminOriginDetails + } +} diff --git a/webapp/packages/core-sdk/src/queries/fragments/AdminOriginDetails.gql b/webapp/packages/core-sdk/src/queries/fragments/AdminOriginDetails.gql new file mode 100644 index 0000000000..5a87159728 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/fragments/AdminOriginDetails.gql @@ -0,0 +1,5 @@ +fragment AdminOriginDetails on AdminUserInfo { + origins { + ...OriginDetails + } +} diff --git a/webapp/packages/core-sdk/src/queries/fragments/ObjectOriginInfo.gql b/webapp/packages/core-sdk/src/queries/fragments/ObjectOriginInfo.gql index f610576645..f42be2b125 100644 --- a/webapp/packages/core-sdk/src/queries/fragments/ObjectOriginInfo.gql +++ b/webapp/packages/core-sdk/src/queries/fragments/ObjectOriginInfo.gql @@ -3,19 +3,4 @@ fragment ObjectOriginInfo on ObjectOrigin { subType displayName icon - - details @include(if: $customIncludeOriginDetails) { - id - required - displayName - description - category - dataType - defaultValue - validValues - value - length - features - order - } -} \ No newline at end of file +} diff --git a/webapp/packages/core-sdk/src/queries/fragments/OriginDetails.gql b/webapp/packages/core-sdk/src/queries/fragments/OriginDetails.gql new file mode 100644 index 0000000000..bea3482c93 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/fragments/OriginDetails.gql @@ -0,0 +1,16 @@ +fragment OriginDetails on ObjectOrigin { + details { + id + required + displayName + description + category + dataType + defaultValue + validValues + value + length + features + order + } +} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Origin/UserFormOriginInfoPanel.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Origin/UserFormOriginInfoPanel.tsx index 67c344ecd5..f3f7ee5870 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Origin/UserFormOriginInfoPanel.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Origin/UserFormOriginInfoPanel.tsx @@ -8,7 +8,7 @@ import { observer } from 'mobx-react-lite'; import { Fragment } from 'react'; -import { AdminUserOrigin, UsersResource } from '@cloudbeaver/core-authentication'; +import { AdminUserOrigin, UsersOriginDetailsResource, UsersResource } from '@cloudbeaver/core-authentication'; import { Button, Combobox, @@ -42,18 +42,17 @@ export const UserFormOriginInfoPanel: TabContainerPanelComponent const localState = useTabState(() => ({ selectedOrigin: '0', })); - const userInfoLoader = useResource( - UserFormOriginInfoPanel, - UsersResource, - { key: state.userId, includes: ['customIncludeOriginDetails'] }, - { - active: editing, - }, - ); + const userInfoLoader = useResource(UserFormOriginInfoPanel, UsersResource, state.userId, { + active: editing, + }); const commonDialogService = useService(CommonDialogService); const notificationService = useService(NotificationService); const origins = userInfoLoader.data?.origins ?? []; const origin: AdminUserOrigin | undefined = origins[localState.selectedOrigin as any]; + const usersOriginDetailsResource = useResource(UserFormOriginInfoPanel, UsersOriginDetailsResource, state.userId, { + active: editing, + }); + const originDetails = usersOriginDetailsResource.data?.origins?.[localState.selectedOrigin as any]?.details ?? []; const { selected } = useTab(tabId); @@ -105,7 +104,7 @@ export const UserFormOriginInfoPanel: TabContainerPanelComponent Date: Fri, 13 Sep 2024 12:22:10 +0200 Subject: [PATCH 04/20] CB-44661 renames to UsersMetaParametersResource --- ...{UsersMetaDataResource.ts => UsersMetaParametersResource.ts} | 0 webapp/packages/core-authentication/src/index.ts | 2 +- webapp/packages/core-authentication/src/manifest.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename webapp/packages/core-authentication/src/{UsersMetaDataResource.ts => UsersMetaParametersResource.ts} (100%) diff --git a/webapp/packages/core-authentication/src/UsersMetaDataResource.ts b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts similarity index 100% rename from webapp/packages/core-authentication/src/UsersMetaDataResource.ts rename to webapp/packages/core-authentication/src/UsersMetaParametersResource.ts diff --git a/webapp/packages/core-authentication/src/index.ts b/webapp/packages/core-authentication/src/index.ts index dbdcee9cc8..bc16b205d3 100644 --- a/webapp/packages/core-authentication/src/index.ts +++ b/webapp/packages/core-authentication/src/index.ts @@ -25,7 +25,7 @@ export * from './UserInfoResource'; export * from './UserMetaParametersResource'; export * from './UserInfoMetaParametersResource'; export * from './UsersOriginDetailsResource'; -export * from './UsersMetaDataResource'; +export * from './UsersMetaParametersResource'; export * from './UsersResource'; export * from './TeamMetaParametersResource'; export * from './TeamInfoMetaParametersResource'; diff --git a/webapp/packages/core-authentication/src/manifest.ts b/webapp/packages/core-authentication/src/manifest.ts index 8963f71ba1..9f2d914c6f 100644 --- a/webapp/packages/core-authentication/src/manifest.ts +++ b/webapp/packages/core-authentication/src/manifest.ts @@ -33,7 +33,7 @@ export const coreAuthenticationManifest: PluginManifest = { () => import('./UserInfoResource').then(m => m.UserInfoResource), () => import('./UserMetaParametersResource').then(m => m.UserMetaParametersResource), () => import('./UserInfoMetaParametersResource').then(m => m.UserInfoMetaParametersResource), - () => import('./UsersMetaDataResource').then(m => m.UsersMetaParametersResource), + () => import('./UsersMetaParametersResource').then(m => m.UsersMetaParametersResource), () => import('./UsersOriginDetailsResource').then(m => m.UsersOriginDetailsResource), () => import('./UsersResource').then(m => m.UsersResource), ], From e9ff24c9e520f19afefff0e8335e2c10b5e7ce10 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Fri, 13 Sep 2024 16:25:41 +0200 Subject: [PATCH 05/20] CB-4461 removes includeOrigin and customIncludeOriginDetails includes from connections feature --- .../ConnectionInfoOriginDetailsResource.ts | 107 +++++++++++++++++ .../src/ConnectionInfoOriginResource.ts | 113 ++++++++++++++++++ .../src/ConnectionInfoResource.ts | 4 - .../src/DatabaseConnection.ts | 15 +-- webapp/packages/core-connections/src/index.ts | 2 + .../packages/core-connections/src/manifest.ts | 2 + .../queries/connections/closeConnection.gql | 2 - .../queries/connections/createConnection.gql | 2 - .../connections/createConnectionFromNode.gql | 2 - .../createConnectionFromTemplate.gql | 2 - .../connections/getTemplateConnections.gql | 2 - .../connections/getUserConnections.gql | 2 - .../connections/getUserConnectionsOrigin.gql | 5 + .../getUserConnectionsOriginDetails.gql | 5 + .../queries/connections/initConnection.gql | 2 - .../setConnectionNavigatorSettings.gql | 2 - .../queries/connections/updateConnection.gql | 2 - .../queries/fragments/DatabaseConnection.gql | 4 - .../fragments/DatabaseConnectionOrigin.gql | 8 ++ .../DatabaseConnectionOriginDetails.gql | 8 ++ .../GrantedConnections/ConnectionList.tsx | 6 +- .../GrantedConnections/GrantedConnections.tsx | 16 ++- .../GrantedConnectionsList.tsx | 12 +- .../getFilteredConnections.ts | 18 ++- .../UserFormConnectionAccess.tsx | 16 +-- .../src/Search/ConnectionSearchService.ts | 9 +- .../src/TemplateConnectionsResource.ts | 2 - .../Connections/ConnectionsAdministration.tsx | 9 +- .../ConnectionsAdministrationController.ts | 13 +- .../ConnectionsAdministrationService.ts | 2 + .../ConnectionsTable/Connection.tsx | 10 +- .../ConnectionDetailsInfo/Origin.tsx | 10 +- .../ConnectionsTable/ConnectionEdit.tsx | 5 +- .../ConnectionsTable/ConnectionsTable.tsx | 18 ++- .../Connections/CreateConnectionService.ts | 11 +- .../ConnectionAccess/ConnectionAccess.tsx | 2 +- .../src/ConnectionForm/ConnectionFormState.ts | 18 ++- .../ConnectionForm/IConnectionFormProps.ts | 3 +- .../Options/ConnectionOptionsTabService.ts | 2 +- .../src/ConnectionForm/Options/Options.tsx | 4 +- .../ConnectionOriginInfoTabService.ts | 10 +- .../ConnectionForm/OriginInfo/OriginInfo.tsx | 53 ++++---- .../OriginInfo/OriginInfoTab.tsx | 4 +- .../ConnectionForm/useConnectionFormState.ts | 10 +- .../PublicConnectionFormService.ts | 10 +- 45 files changed, 448 insertions(+), 116 deletions(-) create mode 100644 webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts create mode 100644 webapp/packages/core-connections/src/ConnectionInfoOriginResource.ts create mode 100644 webapp/packages/core-sdk/src/queries/connections/getUserConnectionsOrigin.gql create mode 100644 webapp/packages/core-sdk/src/queries/connections/getUserConnectionsOriginDetails.gql create mode 100644 webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOrigin.gql create mode 100644 webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOriginDetails.gql diff --git a/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts b/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts new file mode 100644 index 0000000000..17effdd809 --- /dev/null +++ b/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts @@ -0,0 +1,107 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { runInAction, toJS } from 'mobx'; + +import { injectable } from '@cloudbeaver/core-di'; +import { ProjectsService } from '@cloudbeaver/core-projects'; +import { CachedMapResource, isResourceAlias, ResourceKey, resourceKeyList, ResourceKeyUtils } from '@cloudbeaver/core-resource'; +import { DatabaseConnectionOriginDetailsFragment, GraphQLService } from '@cloudbeaver/core-sdk'; +import { schemaValidationError } from '@cloudbeaver/core-utils'; + +import { CONNECTION_INFO_PARAM_SCHEMA, IConnectionInfoParams } from './CONNECTION_INFO_PARAM_SCHEMA'; +import { + ConnectionInfoActiveProjectKey, + ConnectionInfoProjectKey, + ConnectionInfoResource, + createConnectionParam, + isConnectionInfoParamEqual, +} from './ConnectionInfoResource'; + +@injectable() +export class ConnectionInfoOriginDetailsResource extends CachedMapResource { + constructor( + private readonly projectsService: ProjectsService, + private readonly graphQLService: GraphQLService, + private readonly connectionInfoResource: ConnectionInfoResource, + ) { + super(); + + this.sync(this.connectionInfoResource); + } + + protected async loader( + originalKey: ResourceKey, + _: any, + refresh?: boolean, + ): Promise> { + const connectionsList: DatabaseConnectionOriginDetailsFragment[] = []; + const projectKey = this.aliases.isAlias(originalKey, ConnectionInfoProjectKey); + let removedConnections: IConnectionInfoParams[] = []; + let projectId: string | undefined; + let projectIds: string[] | undefined; + + if (projectKey) { + projectIds = projectKey.options.projectIds; + } + + if (this.aliases.isAlias(originalKey, ConnectionInfoActiveProjectKey)) { + projectIds = this.projectsService.activeProjects.map(project => project.id); + } + + if (isResourceAlias(originalKey)) { + const key = this.aliases.transformToKey(originalKey); + const outdated = ResourceKeyUtils.filter(key, key => this.isOutdated(key)); + + if (!refresh && outdated.length === 1) { + originalKey = outdated[0]; // load only single connection + } + } + + await ResourceKeyUtils.forEachAsync(originalKey, async key => { + let connectionId: string | undefined; + if (!isResourceAlias(key)) { + projectId = key.projectId; + connectionId = key.connectionId; + } + + const { connections } = await this.graphQLService.sdk.getUserConnectionsOriginDetails({ + projectId, + connectionId, + projectIds, + }); + + if (connectionId && !connections.some(connection => connection.id === connectionId)) { + throw new Error(`Connection is not found (${connectionId})`); + } + + connectionsList.push(...connections); + }); + + runInAction(() => { + if (isResourceAlias(originalKey)) { + removedConnections = ResourceKeyUtils.toList(this.aliases.transformToKey(originalKey)).filter( + key => !connectionsList.some(connection => isConnectionInfoParamEqual(key, createConnectionParam(connection))), + ); + } + + this.delete(resourceKeyList(removedConnections)); + const key = resourceKeyList(connectionsList.map(createConnectionParam)); + this.set(key, connectionsList); + }); + + return this.data; + } + + protected validateKey(key: IConnectionInfoParams): boolean { + const parse = CONNECTION_INFO_PARAM_SCHEMA.safeParse(toJS(key)); + if (!parse.success) { + this.logger.warn(`Invalid resource key ${(schemaValidationError(parse.error).toString(), { prefix: null })}`); + } + return parse.success; + } +} diff --git a/webapp/packages/core-connections/src/ConnectionInfoOriginResource.ts b/webapp/packages/core-connections/src/ConnectionInfoOriginResource.ts new file mode 100644 index 0000000000..0765246ffd --- /dev/null +++ b/webapp/packages/core-connections/src/ConnectionInfoOriginResource.ts @@ -0,0 +1,113 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { runInAction, toJS } from 'mobx'; + +import { injectable } from '@cloudbeaver/core-di'; +import { ProjectsService } from '@cloudbeaver/core-projects'; +import { CachedMapResource, isResourceAlias, ResourceKey, resourceKeyList, ResourceKeyUtils } from '@cloudbeaver/core-resource'; +import { DatabaseConnectionOriginFragment, GraphQLService } from '@cloudbeaver/core-sdk'; +import { schemaValidationError } from '@cloudbeaver/core-utils'; + +import { CONNECTION_INFO_PARAM_SCHEMA, IConnectionInfoParams } from './CONNECTION_INFO_PARAM_SCHEMA'; +import { + ConnectionInfoActiveProjectKey, + ConnectionInfoProjectKey, + ConnectionInfoResource, + createConnectionParam, + isConnectionInfoParamEqual, +} from './ConnectionInfoResource'; + +@injectable() +export class ConnectionInfoOriginResource extends CachedMapResource { + constructor( + private readonly projectsService: ProjectsService, + private readonly graphQLService: GraphQLService, + private readonly connectionInfoResource: ConnectionInfoResource, + ) { + super(); + + this.aliases.add(ConnectionInfoProjectKey, param => resourceKeyList(this.keys.filter(key => param.options.projectIds.includes(key.projectId)))); + + this.aliases.add(ConnectionInfoActiveProjectKey, () => + resourceKeyList(this.keys.filter(key => projectsService.activeProjects.some(({ id }) => id === key.projectId))), + ); + + this.sync(this.connectionInfoResource); + } + + protected async loader( + originalKey: ResourceKey, + _: any, + refresh?: boolean, + ): Promise> { + const connectionsList: DatabaseConnectionOriginFragment[] = []; + const projectKey = this.aliases.isAlias(originalKey, ConnectionInfoProjectKey); + let removedConnections: IConnectionInfoParams[] = []; + let projectId: string | undefined; + let projectIds: string[] | undefined; + + if (projectKey) { + projectIds = projectKey.options.projectIds; + } + + if (this.aliases.isAlias(originalKey, ConnectionInfoActiveProjectKey)) { + projectIds = this.projectsService.activeProjects.map(project => project.id); + } + + if (isResourceAlias(originalKey)) { + const key = this.aliases.transformToKey(originalKey); + const outdated = ResourceKeyUtils.filter(key, key => this.isOutdated(key)); + + if (!refresh && outdated.length === 1) { + originalKey = outdated[0]; // load only single connection + } + } + + await ResourceKeyUtils.forEachAsync(originalKey, async key => { + let connectionId: string | undefined; + if (!isResourceAlias(key)) { + projectId = key.projectId; + connectionId = key.connectionId; + } + + const { connections } = await this.graphQLService.sdk.getUserConnectionsOrigin({ + projectId, + connectionId, + projectIds, + }); + + if (connectionId && !connections.some(connection => connection.id === connectionId)) { + throw new Error(`Connection is not found (${connectionId})`); + } + + connectionsList.push(...connections); + }); + + runInAction(() => { + if (isResourceAlias(originalKey)) { + removedConnections = ResourceKeyUtils.toList(this.aliases.transformToKey(originalKey)).filter( + key => !connectionsList.some(connection => isConnectionInfoParamEqual(key, createConnectionParam(connection))), + ); + } + + this.delete(resourceKeyList(removedConnections)); + const key = resourceKeyList(connectionsList.map(createConnectionParam)); + this.set(key, connectionsList); + }); + + return this.data; + } + + protected validateKey(key: IConnectionInfoParams): boolean { + const parse = CONNECTION_INFO_PARAM_SCHEMA.safeParse(toJS(key)); + if (!parse.success) { + this.logger.warn(`Invalid resource key ${(schemaValidationError(parse.error).toString(), { prefix: null })}`); + } + return parse.success; + } +} diff --git a/webapp/packages/core-connections/src/ConnectionInfoResource.ts b/webapp/packages/core-connections/src/ConnectionInfoResource.ts index ae7a32f3fe..407f31850c 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoResource.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoResource.ts @@ -47,8 +47,6 @@ export type Connection = DatabaseConnection & { }; export type ConnectionInitConfig = Omit< InitConnectionMutationVariables, - | 'includeOrigin' - | 'customIncludeOriginDetails' | 'includeAuthProperties' | 'includeNetworkHandlersConfig' | 'includeAuthNeeded' @@ -587,9 +585,7 @@ export class ConnectionInfoResource extends CachedMapResource import('./ConnectionExecutionContext/ConnectionExecutionContextService').then(m => m.ConnectionExecutionContextService), () => import('./ConnectionsManagerService').then(m => m.ConnectionsManagerService), () => import('./ConnectionInfoResource').then(m => m.ConnectionInfoResource), + () => import('./ConnectionInfoOriginResource').then(m => m.ConnectionInfoOriginResource), + () => import('./ConnectionInfoOriginDetailsResource').then(m => m.ConnectionInfoOriginDetailsResource), () => import('./ConnectionToolsResource').then(m => m.ConnectionToolsResource), () => import('./ContainerResource').then(m => m.ContainerResource), () => import('./ConnectionsLocaleService').then(m => m.ConnectionsLocaleService), diff --git a/webapp/packages/core-sdk/src/queries/connections/closeConnection.gql b/webapp/packages/core-sdk/src/queries/connections/closeConnection.gql index 7aee378640..41d1e5bee5 100644 --- a/webapp/packages/core-sdk/src/queries/connections/closeConnection.gql +++ b/webapp/packages/core-sdk/src/queries/connections/closeConnection.gql @@ -1,8 +1,6 @@ mutation closeConnection( $projectId: ID! $connectionId: ID! - $includeOrigin: Boolean! - $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $includeNetworkHandlersConfig: Boolean! $includeCredentialsSaved: Boolean! diff --git a/webapp/packages/core-sdk/src/queries/connections/createConnection.gql b/webapp/packages/core-sdk/src/queries/connections/createConnection.gql index 9af020fc7a..26b5d67500 100644 --- a/webapp/packages/core-sdk/src/queries/connections/createConnection.gql +++ b/webapp/packages/core-sdk/src/queries/connections/createConnection.gql @@ -1,8 +1,6 @@ mutation createConnection( $projectId: ID! $config: ConnectionConfig! - $includeOrigin: Boolean! - $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $includeNetworkHandlersConfig: Boolean! $includeCredentialsSaved: Boolean! diff --git a/webapp/packages/core-sdk/src/queries/connections/createConnectionFromNode.gql b/webapp/packages/core-sdk/src/queries/connections/createConnectionFromNode.gql index 9115537615..5dd8de0e1d 100644 --- a/webapp/packages/core-sdk/src/queries/connections/createConnectionFromNode.gql +++ b/webapp/packages/core-sdk/src/queries/connections/createConnectionFromNode.gql @@ -2,8 +2,6 @@ mutation createConnectionFromNode( $projectId: ID! $nodePath: String! $config: ConnectionConfig - $includeOrigin: Boolean! - $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $includeNetworkHandlersConfig: Boolean! $includeCredentialsSaved: Boolean! diff --git a/webapp/packages/core-sdk/src/queries/connections/createConnectionFromTemplate.gql b/webapp/packages/core-sdk/src/queries/connections/createConnectionFromTemplate.gql index 54dda8b0fa..93a68a8b9c 100644 --- a/webapp/packages/core-sdk/src/queries/connections/createConnectionFromTemplate.gql +++ b/webapp/packages/core-sdk/src/queries/connections/createConnectionFromTemplate.gql @@ -2,8 +2,6 @@ mutation createConnectionFromTemplate( $projectId: ID! $templateId: ID! $connectionName: String! - $includeOrigin: Boolean! - $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $includeNetworkHandlersConfig: Boolean! $includeCredentialsSaved: Boolean! diff --git a/webapp/packages/core-sdk/src/queries/connections/getTemplateConnections.gql b/webapp/packages/core-sdk/src/queries/connections/getTemplateConnections.gql index 7d28702d00..f25c011c8c 100644 --- a/webapp/packages/core-sdk/src/queries/connections/getTemplateConnections.gql +++ b/webapp/packages/core-sdk/src/queries/connections/getTemplateConnections.gql @@ -1,7 +1,5 @@ query getTemplateConnections( $projectId: ID - $includeOrigin: Boolean! - $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $includeNetworkHandlersConfig: Boolean! $includeCredentialsSaved: Boolean! diff --git a/webapp/packages/core-sdk/src/queries/connections/getUserConnections.gql b/webapp/packages/core-sdk/src/queries/connections/getUserConnections.gql index a147612f7c..0e13f665dd 100644 --- a/webapp/packages/core-sdk/src/queries/connections/getUserConnections.gql +++ b/webapp/packages/core-sdk/src/queries/connections/getUserConnections.gql @@ -2,8 +2,6 @@ query getUserConnections( $projectId: ID $connectionId: ID $projectIds: [ID!] - $includeOrigin: Boolean! - $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $includeNetworkHandlersConfig: Boolean! $includeCredentialsSaved: Boolean! diff --git a/webapp/packages/core-sdk/src/queries/connections/getUserConnectionsOrigin.gql b/webapp/packages/core-sdk/src/queries/connections/getUserConnectionsOrigin.gql new file mode 100644 index 0000000000..907b0a95bf --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/connections/getUserConnectionsOrigin.gql @@ -0,0 +1,5 @@ +query getUserConnectionsOrigin($projectId: ID, $connectionId: ID, $projectIds: [ID!]) { + connections: userConnections(projectId: $projectId, id: $connectionId, projectIds: $projectIds) { + ...DatabaseConnectionOrigin + } +} diff --git a/webapp/packages/core-sdk/src/queries/connections/getUserConnectionsOriginDetails.gql b/webapp/packages/core-sdk/src/queries/connections/getUserConnectionsOriginDetails.gql new file mode 100644 index 0000000000..f419e38f02 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/connections/getUserConnectionsOriginDetails.gql @@ -0,0 +1,5 @@ +query getUserConnectionsOriginDetails($projectId: ID, $connectionId: ID, $projectIds: [ID!]) { + connections: userConnections(projectId: $projectId, id: $connectionId, projectIds: $projectIds) { + ...DatabaseConnectionOriginDetails + } +} diff --git a/webapp/packages/core-sdk/src/queries/connections/initConnection.gql b/webapp/packages/core-sdk/src/queries/connections/initConnection.gql index 98522e47a1..98d1a9e247 100644 --- a/webapp/packages/core-sdk/src/queries/connections/initConnection.gql +++ b/webapp/packages/core-sdk/src/queries/connections/initConnection.gql @@ -6,8 +6,6 @@ mutation initConnection( $saveCredentials: Boolean $sharedCredentials: Boolean $selectedSecretId: String - $includeOrigin: Boolean! - $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $includeNetworkHandlersConfig: Boolean! $includeCredentialsSaved: Boolean! diff --git a/webapp/packages/core-sdk/src/queries/connections/setConnectionNavigatorSettings.gql b/webapp/packages/core-sdk/src/queries/connections/setConnectionNavigatorSettings.gql index c5cf9278ee..6dce7d6da0 100644 --- a/webapp/packages/core-sdk/src/queries/connections/setConnectionNavigatorSettings.gql +++ b/webapp/packages/core-sdk/src/queries/connections/setConnectionNavigatorSettings.gql @@ -2,8 +2,6 @@ mutation setConnectionNavigatorSettings( $projectId: ID! $connectionId: ID! $settings: NavigatorSettingsInput! - $includeOrigin: Boolean! - $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $includeNetworkHandlersConfig: Boolean! $includeCredentialsSaved: Boolean! diff --git a/webapp/packages/core-sdk/src/queries/connections/updateConnection.gql b/webapp/packages/core-sdk/src/queries/connections/updateConnection.gql index ebabddc440..f240f3d980 100644 --- a/webapp/packages/core-sdk/src/queries/connections/updateConnection.gql +++ b/webapp/packages/core-sdk/src/queries/connections/updateConnection.gql @@ -1,8 +1,6 @@ mutation updateConnection( $projectId: ID! $config: ConnectionConfig! - $includeOrigin: Boolean! - $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $includeNetworkHandlersConfig: Boolean! $includeCredentialsSaved: Boolean! diff --git a/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnection.gql b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnection.gql index bd0b84abee..1770c66c6a 100644 --- a/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnection.gql +++ b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnection.gql @@ -36,10 +36,6 @@ fragment DatabaseConnection on ConnectionInfo { features supportedDataFormats - origin @include(if: $includeOrigin) { - ...ObjectOriginInfo - } - authNeeded @include(if: $includeAuthNeeded) authModel diff --git a/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOrigin.gql b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOrigin.gql new file mode 100644 index 0000000000..fd95b3343c --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOrigin.gql @@ -0,0 +1,8 @@ +fragment DatabaseConnectionOrigin on ConnectionInfo { + id + projectId + driverId + origin { + ...ObjectOriginInfo + } +} diff --git a/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOriginDetails.gql b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOriginDetails.gql new file mode 100644 index 0000000000..366f8c3147 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOriginDetails.gql @@ -0,0 +1,8 @@ +fragment DatabaseConnectionOriginDetails on ConnectionInfo { + id + projectId + driverId + origin { + ...OriginDetails + } +} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/ConnectionList.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/ConnectionList.tsx index e19005ab97..b237e6d3a2 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/ConnectionList.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/ConnectionList.tsx @@ -26,6 +26,7 @@ import { } from '@cloudbeaver/core-blocks'; import { Connection, DBDriverResource } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; +import { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import styles from './ConnectionList.module.css'; import { getFilteredConnections } from './getFilteredConnections'; @@ -35,12 +36,13 @@ import { GrantedConnectionsTableItem } from './GrantedConnectionsTableItem'; interface Props { connectionList: Connection[]; + connectionsOrigins: DatabaseConnectionOriginFragment[]; grantedSubjects: string[]; disabled: boolean; onGrant: (subjectIds: string[]) => void; } -export const ConnectionList = observer(function ConnectionList({ connectionList, grantedSubjects, disabled, onGrant }) { +export const ConnectionList = observer(function ConnectionList({ connectionList, connectionsOrigins, grantedSubjects, disabled, onGrant }) { const props = useObjectRef({ onGrant }); const style = useS(styles); const translate = useTranslate(); @@ -57,7 +59,7 @@ export const ConnectionList = observer(function ConnectionList({ connecti selectedSubjects.clear(); }, []); - const connections = getFilteredConnections(connectionList, filterState.filterValue); + const connections = getFilteredConnections(connectionList, connectionsOrigins, filterState.filterValue); const keys = connections.map(connection => connection.id); return ( diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnections.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnections.tsx index ec94d32f1f..7e5a0e90ab 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnections.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnections.tsx @@ -20,10 +20,18 @@ import { useS, useTranslate, } from '@cloudbeaver/core-blocks'; -import { Connection, ConnectionInfoProjectKey, ConnectionInfoResource, DBDriverResource, isCloudConnection } from '@cloudbeaver/core-connections'; +import { + Connection, + ConnectionInfoOriginResource, + ConnectionInfoProjectKey, + ConnectionInfoResource, + DBDriverResource, + isCloudConnection, +} from '@cloudbeaver/core-connections'; import type { TLocalizationToken } from '@cloudbeaver/core-localization'; import { isGlobalProject, ProjectInfo, ProjectInfoResource } from '@cloudbeaver/core-projects'; import { CachedMapAllKey } from '@cloudbeaver/core-resource'; +import { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import { TabContainerPanelComponent, useTab } from '@cloudbeaver/core-ui'; import type { ITeamFormProps } from '../ITeamFormProps'; @@ -49,10 +57,12 @@ export const GrantedConnections: TabContainerPanelComponent = ob useResource(GrantedConnections, DBDriverResource, CachedMapAllKey, { active: selected }); const connectionsLoader = useResource(GrantedConnections, ConnectionInfoResource, globalConnectionsKey, { active: selected }); + const connectionsOriginLoader = useResource(GrantedConnections, ConnectionInfoOriginResource, globalConnectionsKey, { active: selected }); const connections = connectionsLoader.data as Connection[]; const grantedConnections = getComputed(() => connections.filter(connection => state.state.grantedSubjects.includes(connection.id))); + const connectionsOrigins = (connectionsOriginLoader.data ?? []) as DatabaseConnectionOriginFragment[]; useAutoLoad(GrantedConnections, state, selected && !loaded); @@ -62,7 +72,7 @@ export const GrantedConnections: TabContainerPanelComponent = ob let info: TLocalizationToken | null = null; - const cloudExists = connections.some(isCloudConnection); + const cloudExists = connectionsOrigins.some(isCloudConnection); if (cloudExists) { info = 'cloud_connections_access_placeholder'; @@ -86,6 +96,7 @@ export const GrantedConnections: TabContainerPanelComponent = ob = ob {state.state.editing && ( void; onEdit: () => void; } -export const GrantedConnectionList = observer(function GrantedConnectionList({ grantedConnections, disabled, onRevoke, onEdit }) { +export const GrantedConnectionList = observer(function GrantedConnectionList({ + connectionsOrigins, + grantedConnections, + disabled, + onRevoke, + onEdit, +}) { const props = useObjectRef({ onRevoke, onEdit }); const styles = useS(style); const translate = useTranslate(); @@ -51,7 +59,7 @@ export const GrantedConnectionList = observer(function GrantedConnectionL const [selectedSubjects] = useState>(() => observable(new Map())); const [filterState] = useState(() => observable({ filterValue: '' })); - const connections = getFilteredConnections(grantedConnections, filterState.filterValue); + const connections = getFilteredConnections(grantedConnections, connectionsOrigins, filterState.filterValue); const keys = connections.map(connection => connection.id); const selected = getComputed(() => Array.from(selectedSubjects.values()).some(v => v)); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/getFilteredConnections.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/getFilteredConnections.ts index 41afb3cdcb..a965344d08 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/getFilteredConnections.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/getFilteredConnections.ts @@ -6,14 +6,26 @@ * you may not use this file except in compliance with the License. */ import { isCloudConnection } from '@cloudbeaver/core-connections'; -import type { DatabaseConnectionFragment } from '@cloudbeaver/core-sdk'; +import type { DatabaseConnectionFragment, DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; /** * @param {DatabaseConnectionFragment[]} connections * @param {string} filter */ -export function getFilteredConnections(connections: DatabaseConnectionFragment[], filter: string): DatabaseConnectionFragment[] { +export function getFilteredConnections( + connections: DatabaseConnectionFragment[], + connectionsOrigin: DatabaseConnectionOriginFragment[], + filter: string, +): DatabaseConnectionFragment[] { + const connectionsOriginsMap = new Map(); + + for (const connectionOrigin of connectionsOrigin) { + connectionsOriginsMap.set(connectionOrigin.id, connectionOrigin); + } + return connections - .filter(connection => connection.name.toLowerCase().includes(filter.toLowerCase()) && !isCloudConnection(connection)) + .filter( + connection => connection.name.toLowerCase().includes(filter.toLowerCase()) && !isCloudConnection(connectionsOriginsMap.get(connection.id)), + ) .sort((a, b) => a.name.localeCompare(b.name)); } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/UserFormConnectionAccess.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/UserFormConnectionAccess.tsx index cb5846299e..a8c08d7032 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/UserFormConnectionAccess.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/UserFormConnectionAccess.tsx @@ -23,6 +23,7 @@ import { } from '@cloudbeaver/core-blocks'; import { compareConnectionsInfo, + ConnectionInfoOriginResource, ConnectionInfoProjectKey, ConnectionInfoResource, DBDriverResource, @@ -44,16 +45,15 @@ export const UserFormConnectionAccess: TabContainerPanelComponent const driversResource = useService(DBDriverResource); const tabState = useTabState(); const projectLoader = useResource(UserFormConnectionAccess, ProjectInfoResource, CachedMapAllKey, { active: tab.selected }); - const connectionsLoader = useResource( - UserFormConnectionAccess, - ConnectionInfoResource, - ConnectionInfoProjectKey(...projectLoader.data.filter(isGlobalProject).map(project => project.id)), - { active: tab.selected }, - ); + const key = ConnectionInfoProjectKey(...projectLoader.data.filter(isGlobalProject).map(project => project.id)); + const connectionsLoader = useResource(UserFormConnectionAccess, ConnectionInfoResource, key, { active: tab.selected }); + const connectionsOriginsLoader = useResource(UserFormConnectionAccess, ConnectionInfoOriginResource, key, { active: tab.selected }); const connections = connectionsLoader.data.filter(isDefined).sort(compareConnectionsInfo); - const cloudExists = connections.some(isCloudConnection); - const localConnections = connections.filter(connection => !isCloudConnection(connection)); + const connectionsOrigins = connectionsOriginsLoader.data.filter(isDefined); + const cloudExists = connectionsOrigins.some(isCloudConnection); + const localConnectionsIds = new Set(connectionsOrigins.filter(connection => !isCloudConnection(connection)).map(connection => connection.id)); + const localConnections = connections.filter(connection => localConnectionsIds.has(connection.id)); useResource( UserFormConnectionAccess, diff --git a/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts b/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts index 4a37d88ebf..f7f1cb252b 100644 --- a/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts +++ b/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts @@ -8,7 +8,12 @@ import { makeObservable, observable } from 'mobx'; import { ConfirmationDialog } from '@cloudbeaver/core-blocks'; -import { ConnectionInfoResource, ConnectionsManagerService, createConnectionParam } from '@cloudbeaver/core-connections'; +import { + ConnectionInfoOriginResource, + ConnectionInfoResource, + ConnectionsManagerService, + createConnectionParam, +} from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { CommonDialogService, DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; @@ -40,6 +45,7 @@ export class ConnectionSearchService { private readonly projectsService: ProjectsService, private readonly projectInfoResource: ProjectInfoResource, private readonly connectionsManagerService: ConnectionsManagerService, + private readonly connectionInfoOriginResource: ConnectionInfoOriginResource, ) { this.optionsPanelService.closeTask.addHandler(this.closeHandler); @@ -156,6 +162,7 @@ export class ConnectionSearchService { this.projectInfoResource, this.connectionFormService, this.connectionInfoResource, + this.connectionInfoOriginResource, ); this.formState.closeTask.addHandler(this.goBack.bind(this)); diff --git a/webapp/packages/plugin-connection-template/src/TemplateConnectionsResource.ts b/webapp/packages/plugin-connection-template/src/TemplateConnectionsResource.ts index d82f877b7d..a8f791a285 100644 --- a/webapp/packages/plugin-connection-template/src/TemplateConnectionsResource.ts +++ b/webapp/packages/plugin-connection-template/src/TemplateConnectionsResource.ts @@ -61,9 +61,7 @@ export class TemplateConnectionsResource extends CachedDataResource { const { connections } = await this.graphQLService.sdk.getTemplateConnections({ includeNetworkHandlersConfig: true, - customIncludeOriginDetails: false, includeAuthProperties: true, - includeOrigin: false, includeAuthNeeded: true, includeCredentialsSaved: false, includeProperties: false, diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministration.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministration.tsx index 2abc992790..f33a0fb6a2 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministration.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministration.tsx @@ -26,7 +26,12 @@ import { useS, useTranslate, } from '@cloudbeaver/core-blocks'; -import { ConnectionInfoActiveProjectKey, ConnectionInfoResource, DBDriverResource } from '@cloudbeaver/core-connections'; +import { + ConnectionInfoActiveProjectKey, + ConnectionInfoOriginResource, + ConnectionInfoResource, + DBDriverResource, +} from '@cloudbeaver/core-connections'; import { useController, useService } from '@cloudbeaver/core-di'; import { CachedMapAllKey } from '@cloudbeaver/core-resource'; @@ -60,6 +65,7 @@ export const ConnectionsAdministration = observer diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationController.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationController.ts index dfc032294d..eb6ad31003 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationController.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationController.ts @@ -13,6 +13,7 @@ import { compareNewConnectionsInfo, Connection, ConnectionInfoActiveProjectKey, + ConnectionInfoOriginResource, ConnectionInfoResource, createConnectionParam, DatabaseConnection, @@ -24,6 +25,7 @@ import { NotificationService } from '@cloudbeaver/core-events'; import { LocalizationService } from '@cloudbeaver/core-localization'; import { isGlobalProject, isSharedProject, ProjectInfoResource, projectInfoSortByName } from '@cloudbeaver/core-projects'; import { resourceKeyList } from '@cloudbeaver/core-resource'; +import { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import { isArraysEqual, isDefined, isObjectsEqual } from '@cloudbeaver/core-utils'; @injectable() @@ -66,6 +68,10 @@ export class ConnectionsAdministrationController { }); } + get connectionsOrigins(): DatabaseConnectionOriginFragment[] { + return this.connectionInfoOriginResource.get(ConnectionInfoActiveProjectKey).filter(isDefined) ?? []; + } + get itemsSelected(): boolean { return Array.from(this.selectedItems.values()).some(v => v); } @@ -76,10 +82,12 @@ export class ConnectionsAdministrationController { private readonly commonDialogService: CommonDialogService, private readonly localizationService: LocalizationService, private readonly projectInfoResource: ProjectInfoResource, + private readonly connectionInfoOriginResource: ConnectionInfoOriginResource, ) { makeObservable(this, { isProcessing: observable, connections: computed({ equals: (a, b) => isArraysEqual(a, b) }), + connectionsOrigins: computed({ equals: (a, b) => isArraysEqual(a, b) }), keys: computed({ equals: (a, b) => isArraysEqual(a, b, isObjectsEqual) }), itemsSelected: computed, }); @@ -91,7 +99,10 @@ export class ConnectionsAdministrationController { } this.isProcessing = true; try { - await this.connectionInfoResource.refresh(ConnectionInfoActiveProjectKey); + await Promise.all([ + this.connectionInfoResource.refresh(ConnectionInfoActiveProjectKey), + this.connectionInfoOriginResource.refresh(ConnectionInfoActiveProjectKey), + ]); this.connectionInfoResource.cleanNewFlags(); this.notificationService.logSuccess({ title: 'connections_administration_tools_refresh_success' }); } catch (exception: any) { diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts index c52a5301f5..b54287d20f 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts @@ -15,11 +15,13 @@ import { CommonDialogService, DialogueStateResult } from '@cloudbeaver/core-dial import { NotificationService } from '@cloudbeaver/core-events'; import { CachedMapAllKey } from '@cloudbeaver/core-resource'; import { ServerConfigResource } from '@cloudbeaver/core-root'; +import { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import { CreateConnectionService } from './CreateConnectionService'; export interface IConnectionDetailsPlaceholderProps { connection: DatabaseConnection; + connectionOrigin: DatabaseConnectionOriginFragment; } const ConnectionsAdministration = React.lazy(async () => { diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/Connection.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/Connection.tsx index bd5da4b40b..363bc55e8a 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/Connection.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/Connection.tsx @@ -10,6 +10,7 @@ import { observer } from 'mobx-react-lite'; import { Loader, Placeholder, s, StaticImage, TableColumnValue, TableItem, TableItemExpand, TableItemSelect, useS } from '@cloudbeaver/core-blocks'; import { DatabaseConnection, DBDriverResource, IConnectionInfoParams } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; +import { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import { ConnectionsAdministrationService } from '../ConnectionsAdministrationService'; import styles from './Connection.module.css'; @@ -18,10 +19,11 @@ import { ConnectionEdit } from './ConnectionEdit'; interface Props { connectionKey: IConnectionInfoParams; connection: DatabaseConnection; + connectionOrigin: DatabaseConnectionOriginFragment; projectName?: string | null; } -export const Connection = observer(function Connection({ connectionKey, connection, projectName }) { +export const Connection = observer(function Connection({ connectionKey, connection, projectName, connectionOrigin }) { const driversResource = useService(DBDriverResource); const connectionsAdministrationService = useService(ConnectionsAdministrationService); const icon = driversResource.get(connection.driverId)?.icon; @@ -52,7 +54,11 @@ export const Connection = observer(function Connection({ connectionKey, c )} - + diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/Origin.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/Origin.tsx index b576322589..6a1b677d77 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/Origin.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/Origin.tsx @@ -13,16 +13,16 @@ import { PlaceholderComponent, s, StaticImage, useS } from '@cloudbeaver/core-bl import type { IConnectionDetailsPlaceholderProps } from '../../ConnectionsAdministrationService'; import ConnectionDetailsStyles from './ConnectionDetailsStyles.module.css'; -export const Origin: PlaceholderComponent = observer(function Origin({ connection }) { - const isLocal = connection.origin?.type === AUTH_PROVIDER_LOCAL_ID; +export const Origin: PlaceholderComponent = observer(function Origin({ connectionOrigin }) { + const isLocal = connectionOrigin?.origin?.type === AUTH_PROVIDER_LOCAL_ID; const style = useS(ConnectionDetailsStyles); - if (!connection.origin || isLocal) { + if (!connectionOrigin?.origin || isLocal) { return null; } - const icon = connection.origin.icon; - const title = connection.origin.displayName; + const icon = connectionOrigin.origin.icon; + const title = connectionOrigin.origin.displayName; return ; }); diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionEdit.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionEdit.tsx index d2c1c750ae..4fbba5ae87 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionEdit.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionEdit.tsx @@ -9,7 +9,7 @@ import { observer } from 'mobx-react-lite'; import { useMemo } from 'react'; import { Loader, s, useS } from '@cloudbeaver/core-blocks'; -import { ConnectionInfoResource, IConnectionInfoParams } from '@cloudbeaver/core-connections'; +import { ConnectionInfoOriginResource, ConnectionInfoResource, IConnectionInfoParams } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { ConnectionFormLoader, useConnectionFormState } from '@cloudbeaver/plugin-connections'; @@ -21,10 +21,11 @@ interface Props { export const ConnectionEdit = observer(function ConnectionEditNew({ item }) { const connectionInfoResource = useService(ConnectionInfoResource); + const connectionInfoOriginResource = useService(ConnectionInfoOriginResource); // const tableContext = useContext(TableContext); // const collapse = useCallback(() => tableContext?.setItemExpand(item, false), [tableContext, item]); - const data = useConnectionFormState(connectionInfoResource, state => state.setOptions('edit', 'admin')); + const data = useConnectionFormState(connectionInfoResource, connectionInfoOriginResource, state => state.setOptions('edit', 'admin')); const style = useS(styles); const projectId = item.projectId; diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx index 3f6fbd6bd8..749c6e85fd 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx @@ -6,32 +6,45 @@ * you may not use this file except in compliance with the License. */ import { observer } from 'mobx-react-lite'; +import { useMemo } from 'react'; import { getComputed, Table, TableBody, TableColumnHeader, TableHeader, TableSelect, useResource, useTranslate } from '@cloudbeaver/core-blocks'; import { DatabaseConnection, IConnectionInfoParams, serializeConnectionParam } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { isGlobalProject, isSharedProject, ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects'; import { CachedMapAllKey } from '@cloudbeaver/core-resource'; +import { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import { Connection } from './Connection'; interface Props { keys: IConnectionInfoParams[]; connections: DatabaseConnection[]; + connectionsOrigins: DatabaseConnectionOriginFragment[]; selectedItems: Map; expandedItems: Map; } -export const ConnectionsTable = observer(function ConnectionsTable({ keys, connections, selectedItems, expandedItems }) { +export const ConnectionsTable = observer(function ConnectionsTable({ keys, connectionsOrigins, connections, selectedItems, expandedItems }) { const translate = useTranslate(); const projectService = useService(ProjectsService); const projectsLoader = useResource(ConnectionsTable, ProjectInfoResource, CachedMapAllKey); const displayProjects = getComputed( () => projectService.activeProjects.filter(project => isGlobalProject(project) || isSharedProject(project)).length > 1, ); + const connectionsOriginMap = useMemo( + () => + getComputed(() => + connectionsOrigins.reduce((map, origin) => { + map.set(origin.id, origin); + return map; + }, new Map()), + ), + [connectionsOrigins], + ); function getProjectName(projectId: string) { - return displayProjects ? projectsLoader.resource.get(projectId)?.name ?? null : undefined; + return displayProjects ? (projectsLoader.resource.get(projectId)?.name ?? null) : undefined; } return ( @@ -53,6 +66,7 @@ export const ConnectionsTable = observer(function ConnectionsTable({ keys key={serializeConnectionParam(keys[i])} connectionKey={keys[i]} connection={connection} + connectionOrigin={connectionsOriginMap.get(connection.id)} projectName={getProjectName(connection.projectId)} /> ))} diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts index fc1051c911..c0c00c507d 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts @@ -8,7 +8,7 @@ import { action, makeObservable, observable } from 'mobx'; import { AdministrationScreenService } from '@cloudbeaver/core-administration'; -import { ConnectionInfoResource } from '@cloudbeaver/core-connections'; +import { ConnectionInfoOriginResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; @@ -38,6 +38,7 @@ export class CreateConnectionService { private readonly connectionInfoResource: ConnectionInfoResource, private readonly projectsService: ProjectsService, private readonly projectInfoResource: ProjectInfoResource, + private readonly connectionInfoOriginResource: ConnectionInfoOriginResource, ) { this.data = null; this.tabsContainer = new TabsContainer('Connection Creation mode'); @@ -109,7 +110,13 @@ export class CreateConnectionService { } setConnectionTemplate(projectId: string, config: ConnectionConfig, availableDrivers: string[]): void { - this.data = new ConnectionFormState(this.projectsService, this.projectInfoResource, this.connectionFormService, this.connectionInfoResource); + this.data = new ConnectionFormState( + this.projectsService, + this.projectInfoResource, + this.connectionFormService, + this.connectionInfoResource, + this.connectionInfoOriginResource, + ); this.data.closeTask.addHandler(this.cancelCreate.bind(this)); diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx index cafa9f0eb0..a1bea5c618 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx @@ -63,7 +63,7 @@ export const ConnectionAccess: TabContainerPanelComponent } const loading = users.isLoading() || teams.isLoading() || state.state.loading; - const cloud = formState.info ? isCloudConnection(formState.info) : false; + const cloud = formState.info ? isCloudConnection(formState.originInfo) : false; const disabled = loading || !state.state.loaded || formState.disabled || cloud; let info: TLocalizationToken | null = null; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts index 8a846d4338..1873386ec5 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts @@ -7,7 +7,13 @@ */ import { action, computed, makeObservable, observable } from 'mobx'; -import { ConnectionInfoResource, createConnectionParam, DatabaseConnection, IConnectionInfoParams } from '@cloudbeaver/core-connections'; +import { + ConnectionInfoOriginResource, + ConnectionInfoResource, + createConnectionParam, + DatabaseConnection, + IConnectionInfoParams, +} from '@cloudbeaver/core-connections'; import { Executor, IExecutionContextProvider, IExecutor } from '@cloudbeaver/core-executor'; import type { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects'; import type { ResourceKeySimple } from '@cloudbeaver/core-resource'; @@ -56,6 +62,14 @@ export class ConnectionFormState implements IConnectionFormState { return this.resource.get(createConnectionParam(this.projectId, this.config.connectionId)); } + get originInfo() { + if (!this.config.connectionId || this.projectId === null) { + return undefined; + } + + return this.originResource.get(createConnectionParam(this.projectId, this.config.connectionId)); + } + get readonly(): boolean { if (this.stateInfo?.readonly) { return true; @@ -96,6 +110,7 @@ export class ConnectionFormState implements IConnectionFormState { private readonly projectInfoResource: ProjectInfoResource, service: ConnectionFormService, resource: ConnectionInfoResource, + private readonly originResource: ConnectionInfoOriginResource, ) { this._id = uuid(); this.initError = null; @@ -165,6 +180,7 @@ export class ConnectionFormState implements IConnectionFormState { availableDrivers: computed, _availableDrivers: observable, info: computed, + originInfo: computed, statusMessage: observable, configured: observable, readonly: computed, diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts index cb500aee50..1c4104a99b 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts @@ -5,7 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import type { ConnectionInfoResource, DatabaseConnection } from '@cloudbeaver/core-connections'; +import type { ConnectionInfoResource, DatabaseConnection, DatabaseConnectionOrigin } from '@cloudbeaver/core-connections'; import type { IExecutor, IExecutorHandlersCollection } from '@cloudbeaver/core-executor'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; import type { IFormStateInfo } from '@cloudbeaver/core-ui'; @@ -33,6 +33,7 @@ export interface IConnectionFormState { readonly availableDrivers: string[]; readonly resource: ConnectionInfoResource; readonly info: DatabaseConnection | undefined; + readonly originInfo: DatabaseConnectionOrigin | undefined; readonly readonly: boolean; readonly submittingTask: IExecutorHandlersCollection; readonly closeTask: IExecutor; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts index 74506198f6..214825c664 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts @@ -244,7 +244,7 @@ export class ConnectionOptionsTabService extends Bootstrap { private configure(data: IConnectionFormState, contexts: IExecutionContextProvider) { const configuration = contexts.getContext(connectionFormConfigureContext); - configuration.include('includeOrigin', 'includeAuthProperties', 'includeCredentialsSaved', 'customIncludeOptions'); + configuration.include('includeAuthProperties', 'includeCredentialsSaved', 'customIncludeOptions'); } private async prepareConfig({ state }: IConnectionFormSubmitData, contexts: IExecutionContextProvider) { diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx index 39ada137a4..7b1b189a25 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx @@ -81,7 +81,7 @@ export const Options: TabContainerPanelComponent = observe const service = useService(ConnectionFormService); const formRef = useRef(null); const translate = useTranslate(); - const { info, config, availableDrivers, submittingTask: submittingHandlers, disabled } = state; + const { info, originInfo, config, availableDrivers, submittingTask: submittingHandlers, disabled } = state; const style = useS(styles); const tabsState = useContext(TabsContext); const isSharedProject = projectInfoResource.isProjectShared(state.projectId); @@ -149,7 +149,7 @@ export const Options: TabContainerPanelComponent = observe }); const edit = state.mode === 'edit'; - const originLocal = !info || isLocalConnection(info); + const originLocal = !info || (originInfo && isLocalConnection(originInfo)); const drivers = driverMap.resource.enabledDrivers.filter(({ id }) => availableDrivers.includes(id)); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionOriginInfoTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionOriginInfoTabService.ts index 183d2a0661..89055b06f1 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionOriginInfoTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionOriginInfoTabService.ts @@ -41,19 +41,11 @@ export class ConnectionOriginInfoTabService extends Bootstrap { tab: () => OriginInfoTab, panel: () => OriginInfo, stateGetter: () => () => ({}), - isHidden: (tabId, props) => (props?.state.info ? isLocalConnection(props.state.info) : true), + isHidden: (tabId, props) => (props?.state.originInfo ? isLocalConnection(props.state.originInfo) : true), }); - this.connectionFormService.configureTask.addHandler(this.configure.bind(this)); - this.connectionFormService.actionsContainer.add(ConnectionFormAuthenticationAction, 0); } load(): void {} - - private configure(data: IConnectionFormState, contexts: IExecutionContextProvider) { - const configuration = contexts.getContext(connectionFormConfigureContext); - - configuration.include('includeOrigin'); - } } diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx index 36fb966197..1f959ed580 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx @@ -21,7 +21,12 @@ import { useS, useTranslate, } from '@cloudbeaver/core-blocks'; -import { createConnectionParam, DatabaseAuthModelsResource, DBDriverResource } from '@cloudbeaver/core-connections'; +import { + ConnectionInfoOriginDetailsResource, + createConnectionParam, + DatabaseAuthModelsResource, + DBDriverResource, +} from '@cloudbeaver/core-connections'; import { TabContainerPanelComponent, useTab, useTabState } from '@cloudbeaver/core-ui'; import type { IConnectionFormProps } from '../IConnectionFormProps'; @@ -46,34 +51,28 @@ export const OriginInfo: TabContainerPanelComponent = obse const providerId = authModeLoader.data?.requiredAuth ?? info?.requiredAuth ?? AUTH_PROVIDER_LOCAL_ID; const isAuthenticated = userInfoLoader.resource.hasToken(providerId); const providerLoader = useResource(OriginInfo, AuthProvidersResource, providerId); + const connectionId = tab.selected && info ? createConnectionParam(info.projectId, info.id) : null; - const connection = useResource( - OriginInfo, - resource, - { - key: tab.selected && info ? createConnectionParam(info.projectId, info.id) : null, - includes: ['includeOrigin', 'customIncludeOriginDetails'] as const, - }, - { - active: isAuthenticated, - onData: connection => { - runInAction(() => { - if (!connection.origin.details) { - return; - } + const connectionOriginDetailsResource = useResource(OriginInfo, ConnectionInfoOriginDetailsResource, connectionId); + const connection = useResource(OriginInfo, resource, connectionId, { + active: isAuthenticated, + onData: connection => { + runInAction(() => { + if (!connectionOriginDetailsResource.data?.origin.details) { + return; + } - for (const property of Object.keys(state)) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete state[property]; - } + for (const property of Object.keys(state)) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete state[property]; + } - for (const property of connection.origin.details) { - state[property.id!] = property.value; - } - }); - }, + for (const property of connectionOriginDetailsResource.data.origin.details) { + state[property.id!] = property.value; + } + }); }, - ); + }); if (connection.isLoading()) { return ( @@ -103,7 +102,7 @@ export const OriginInfo: TabContainerPanelComponent = obse ); } - if (!connection.data?.origin.details || connection.data.origin.details.length === 0) { + if (!connectionOriginDetailsResource.data?.origin.details || connectionOriginDetailsResource.data?.origin.details.length === 0) { return ( {translate('connections_administration_connection_no_information')} @@ -114,7 +113,7 @@ export const OriginInfo: TabContainerPanelComponent = obse return ( - + diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfoTab.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfoTab.tsx index 8f918f04eb..3de7f26933 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfoTab.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfoTab.tsx @@ -12,11 +12,11 @@ import { Tab, TabContainerTabComponent, TabTitle } from '@cloudbeaver/core-ui'; import type { IConnectionFormProps } from '../IConnectionFormProps'; -export const OriginInfoTab: TabContainerTabComponent = observer(function OriginInfoTab({ state: { info }, ...rest }) { +export const OriginInfoTab: TabContainerTabComponent = observer(function OriginInfoTab({ state: { originInfo }, ...rest }) { return ( - + ); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts b/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts index 993c5c13e7..7d241a001e 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts @@ -7,7 +7,7 @@ */ import { useEffect, useState } from 'react'; -import type { ConnectionInfoResource } from '@cloudbeaver/core-connections'; +import type { ConnectionInfoOriginResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects'; @@ -15,13 +15,17 @@ import { ConnectionFormService } from './ConnectionFormService'; import { ConnectionFormState } from './ConnectionFormState'; import type { IConnectionFormState } from './IConnectionFormProps'; -export function useConnectionFormState(resource: ConnectionInfoResource, configure?: (state: IConnectionFormState) => any): IConnectionFormState { +export function useConnectionFormState( + resource: ConnectionInfoResource, + originResource: ConnectionInfoOriginResource, + configure?: (state: IConnectionFormState) => any, +): IConnectionFormState { const projectsService = useService(ProjectsService); const projectInfoResource = useService(ProjectInfoResource); const service = useService(ConnectionFormService); const [state] = useState(() => { - const state = new ConnectionFormState(projectsService, projectInfoResource, service, resource); + const state = new ConnectionFormState(projectsService, projectInfoResource, service, resource, originResource); configure?.(state); state.load(); diff --git a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts index 272bf0747f..cb2773eefd 100644 --- a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts +++ b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts @@ -9,7 +9,13 @@ import { action, makeObservable, observable } from 'mobx'; import { UserInfoResource } from '@cloudbeaver/core-authentication'; import { ConfirmationDialog, importLazyComponent } from '@cloudbeaver/core-blocks'; -import { ConnectionInfoResource, ConnectionsManagerService, createConnectionParam, IConnectionInfoParams } from '@cloudbeaver/core-connections'; +import { + ConnectionInfoOriginResource, + ConnectionInfoResource, + ConnectionsManagerService, + createConnectionParam, + IConnectionInfoParams, +} from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { CommonDialogService, DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; @@ -43,6 +49,7 @@ export class PublicConnectionFormService { private readonly authenticationService: AuthenticationService, private readonly projectsService: ProjectsService, private readonly projectInfoResource: ProjectInfoResource, + private readonly connectionInfoOriginResource: ConnectionInfoOriginResource, ) { this.formState = null; this.optionsPanelService.closeTask.addHandler(this.closeHandler); @@ -82,6 +89,7 @@ export class PublicConnectionFormService { this.projectInfoResource, this.connectionFormService, this.connectionInfoResource, + this.connectionInfoOriginResource, ); this.formState.closeTask.addHandler(this.close.bind(this, true)); From 1ff7028c218ffaa5193749e992fb0249dd8af749 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Fri, 13 Sep 2024 16:42:59 +0200 Subject: [PATCH 06/20] CB-4461 removes the comment --- .../src/UserProfileForm/UserInfoPart/UserProfileFormInfoPart.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/webapp/packages/plugin-user-profile/src/UserProfileForm/UserInfoPart/UserProfileFormInfoPart.ts b/webapp/packages/plugin-user-profile/src/UserProfileForm/UserInfoPart/UserProfileFormInfoPart.ts index da7d0c659a..2e44b35320 100644 --- a/webapp/packages/plugin-user-profile/src/UserProfileForm/UserInfoPart/UserProfileFormInfoPart.ts +++ b/webapp/packages/plugin-user-profile/src/UserProfileForm/UserInfoPart/UserProfileFormInfoPart.ts @@ -65,7 +65,6 @@ export class UserProfileFormInfoPart extends FormPart Date: Mon, 16 Sep 2024 16:40:51 +0200 Subject: [PATCH 07/20] CB-4461 cleanup --- .../src/TeamInfoMetaParametersResource.ts | 6 +++++- .../core-authentication/src/TeamsResource.ts | 18 +++--------------- .../src/UserInfoMetaParametersResource.ts | 2 +- .../src/UsersMetaParametersResource.ts | 3 +-- .../Users/Teams/Contexts/teamContext.ts | 2 +- .../Teams/Options/TeamOptionsTabService.ts | 14 +++++++++++--- .../Users/Teams/TeamFormState.ts | 3 +-- .../Users/UserForm/Info/UserFormInfoPart.ts | 3 +-- .../ConnectionsAdministrationController.ts | 2 +- .../ConnectionsAdministrationService.ts | 2 +- .../UserProfileFormAuthenticationPart.ts | 2 +- 11 files changed, 27 insertions(+), 30 deletions(-) diff --git a/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts b/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts index 21987208d3..53859c6079 100644 --- a/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts @@ -9,7 +9,7 @@ import { injectable } from '@cloudbeaver/core-di'; import { CachedMapAllKey, CachedMapResource, isResourceAlias, ResourceKey, resourceKeyList, ResourceKeyUtils } from '@cloudbeaver/core-resource'; import { GraphQLService } from '@cloudbeaver/core-sdk'; -import { TeamMetaParameter } from './TeamMetaParametersResource'; +import type { TeamMetaParameter } from './TeamMetaParametersResource'; import { TeamsResource } from './TeamsResource'; @injectable() @@ -56,6 +56,10 @@ export class TeamInfoMetaParametersResource extends CachedMapResource): Promise { + await this.graphQLService.sdk.saveTeamMetaParameters({ teamId, parameters }); + } + protected validateKey(key: string): boolean { return typeof key === 'string'; } diff --git a/webapp/packages/core-authentication/src/TeamsResource.ts b/webapp/packages/core-authentication/src/TeamsResource.ts index 23dbdd4fc3..f65b7edaa8 100644 --- a/webapp/packages/core-authentication/src/TeamsResource.ts +++ b/webapp/packages/core-authentication/src/TeamsResource.ts @@ -24,7 +24,7 @@ import { } from '@cloudbeaver/core-sdk'; import { isArraysEqual, UndefinedToNull } from '@cloudbeaver/core-utils'; -import { TeamMetaParameter } from './TeamMetaParametersResource'; +import type { TeamMetaParameter } from './TeamMetaParametersResource'; const NEW_TEAM_SYMBOL = Symbol('new-team'); @@ -40,10 +40,7 @@ export class TeamsResource extends CachedMapResource, - ): Promise { + async createTeam({ teamId, teamPermissions, teamName, description }: TeamInfo): Promise { const response = await this.graphQLService.sdk.createTeam({ teamId, teamName, @@ -59,16 +56,12 @@ export class TeamsResource extends CachedMapResource, - ): Promise { + async updateTeam({ teamId, teamPermissions, teamName, description }: TeamInfo): Promise { const { team } = await this.graphQLService.sdk.updateTeam({ teamId, teamName, @@ -78,7 +71,6 @@ export class TeamsResource extends CachedMapResource): Promise { - await this.graphQLService.sdk.saveTeamMetaParameters({ teamId, parameters }); - } - protected async loader(originalKey: ResourceKey, includes?: string[]): Promise> { const all = this.aliases.isAlias(originalKey, CachedMapAllKey); const teamsList: TeamInfo[] = []; diff --git a/webapp/packages/core-authentication/src/UserInfoMetaParametersResource.ts b/webapp/packages/core-authentication/src/UserInfoMetaParametersResource.ts index 38cc888f18..976bb380bd 100644 --- a/webapp/packages/core-authentication/src/UserInfoMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/UserInfoMetaParametersResource.ts @@ -10,7 +10,7 @@ import { CachedDataResource, ResourceKey } from '@cloudbeaver/core-resource'; import { GraphQLService } from '@cloudbeaver/core-sdk'; import { UserInfoResource } from './UserInfoResource'; -import { UserMetaParameter } from './UserMetaParametersResource'; +import type { UserMetaParameter } from './UserMetaParametersResource'; @injectable() export class UserInfoMetaParametersResource extends CachedDataResource { diff --git a/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts index 454f043138..d9bbda478e 100644 --- a/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts @@ -20,7 +20,7 @@ import { } from '@cloudbeaver/core-resource'; import { GraphQLService } from '@cloudbeaver/core-sdk'; -import { UserMetaParameter } from './UserMetaParametersResource'; +import type { UserMetaParameter } from './UserMetaParametersResource'; import { UsersResource, UsersResourceFilterKey } from './UsersResource'; @injectable() @@ -39,7 +39,6 @@ export class UsersMetaParametersResource extends CachedMapResource): Promise> { const all = this.aliases.isAlias(originalKey, CachedMapAllKey); const keys: string[] = []; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts index 846e214eab..a0d0674660 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts @@ -5,7 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import { TeamInfoConfig } from '../ITeamFormProps'; +import type { TeamInfoConfig } from '../ITeamFormProps'; export function teamContext(): TeamInfoConfig { return { diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts index ff02edc114..d9fcbca3d1 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts @@ -7,7 +7,7 @@ */ import React from 'react'; -import { TeamsResource } from '@cloudbeaver/core-authentication'; +import { TeamInfoMetaParametersResource, TeamsResource } from '@cloudbeaver/core-authentication'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -27,6 +27,7 @@ export class TeamOptionsTabService extends Bootstrap { constructor( private readonly teamFormService: TeamFormService, private readonly teamResource: TeamsResource, + private readonly teamsMetaParametersResource: TeamInfoMetaParametersResource, private readonly localizationService: LocalizationService, ) { super(); @@ -108,11 +109,18 @@ export class TeamOptionsTabService extends Bootstrap { try { if (create) { - const team = await this.teamResource.createTeam(config, metaParameters); + const [team] = await Promise.all([ + this.teamResource.createTeam(config), + this.teamsMetaParametersResource.setMetaParameters(config.teamId, metaParameters), + ]); + status.info('administration_teams_team_info_created'); status.info(team.teamId); } else { - const team = await this.teamResource.updateTeam(config, metaParameters); + const [team] = await Promise.all([ + this.teamResource.updateTeam(config), + this.teamsMetaParametersResource.setMetaParameters(config.teamId, metaParameters), + ]); status.info('administration_teams_team_info_updated'); status.info(team.teamId); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts index fdf936bdd7..60c6789b96 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts @@ -150,7 +150,6 @@ export class TeamFormState implements ITeamFormState { return; } - await this.resource.load(data.config.teamId); - await this.teamInfoMetaParametersResource.load(data.config.teamId); + await Promise.all([this.resource.load(data.config.teamId), this.teamInfoMetaParametersResource.load(data.config.teamId)]); } } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoPart.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoPart.ts index f571968b46..3236b7566c 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoPart.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoPart.ts @@ -207,10 +207,9 @@ export class UserFormInfoPart extends FormPart Date: Mon, 16 Sep 2024 16:56:46 +0200 Subject: [PATCH 08/20] CB-4461 fixes pagination for new resources --- .../src/UsersMetaParametersResource.ts | 18 ++++++++++++++++-- .../src/UsersOriginDetailsResource.ts | 18 ++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts index d9bbda478e..14b6df8ba1 100644 --- a/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts @@ -5,6 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ +import { runInAction } from 'mobx'; + import { injectable } from '@cloudbeaver/core-di'; import { CACHED_RESOURCE_DEFAULT_PAGE_LIMIT, @@ -42,6 +44,7 @@ export class UsersMetaParametersResource extends CachedMapResource): Promise> { const all = this.aliases.isAlias(originalKey, CachedMapAllKey); const keys: string[] = []; + const pages: Parameters[] = []; if (all) { throw new Error('Loading all users is prohibited'); @@ -96,11 +99,22 @@ export class UsersMetaParametersResource extends CachedMapResource user.metaParameters)); keys.push(...users.map(user => user.userId)); - this.offsetPagination.setPageEnd(CachedResourceOffsetPageListKey(offset, users.length).setTarget(filterKey), users.length === limit); + pages.push([ + CachedResourceOffsetPageListKey(offset, users.length).setParent(filterKey!), + users.map(user => user.userId), + users.length === limit, + ]); } }); - this.set(resourceKeyList(keys), userMetaParametersList); + const key = resourceKeyList(keys); + + runInAction(() => { + this.set(key, userMetaParametersList); + for (const pageArgs of pages) { + this.offsetPagination.setPage(...pageArgs); + } + }); return this.data; } diff --git a/webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts b/webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts index 101d6cd558..2e635bb46b 100644 --- a/webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts +++ b/webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts @@ -5,6 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ +import { runInAction } from 'mobx'; + import { injectable } from '@cloudbeaver/core-di'; import { CACHED_RESOURCE_DEFAULT_PAGE_LIMIT, @@ -36,6 +38,7 @@ export class UsersOriginDetailsResource extends CachedMapResource): Promise> { const all = this.aliases.isAlias(originalKey, CachedMapAllKey); const keys: string[] = []; + const pages: Parameters[] = []; if (all) { throw new Error('Loading all users is prohibited'); @@ -90,11 +93,22 @@ export class UsersOriginDetailsResource extends CachedMapResource user.userId)); - this.offsetPagination.setPageEnd(CachedResourceOffsetPageListKey(offset, users.length).setTarget(filterKey), users.length === limit); + pages.push([ + CachedResourceOffsetPageListKey(offset, users.length).setParent(filterKey!), + users.map(user => user.userId), + users.length === limit, + ]); } }); - this.set(resourceKeyList(keys), userMetaParametersList); + const key = resourceKeyList(keys); + + runInAction(() => { + this.set(key, userMetaParametersList); + for (const pageArgs of pages) { + this.offsetPagination.setPage(...pageArgs); + } + }); return this.data; } From 865903df25e447003289d83f9ec8bafb7a2baaa7 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Mon, 16 Sep 2024 18:10:15 +0200 Subject: [PATCH 09/20] CB-4661 pr fixes --- .../src/TeamInfoMetaParametersResource.ts | 5 +- .../src/UserInfoMetaParametersResource.ts | 14 ++--- .../src/UsersMetaParametersResource.ts | 54 ++----------------- .../src/UsersOriginDetailsResource.ts | 54 ++----------------- .../ConnectionInfoOriginDetailsResource.ts | 1 + .../src/ConnectionInfoOriginResource.ts | 1 + 6 files changed, 17 insertions(+), 112 deletions(-) diff --git a/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts b/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts index 53859c6079..6526f793b9 100644 --- a/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts @@ -21,6 +21,7 @@ export class TeamInfoMetaParametersResource extends CachedMapResource): Promise> { @@ -57,7 +58,9 @@ export class TeamInfoMetaParametersResource extends CachedMapResource): Promise { - await this.graphQLService.sdk.saveTeamMetaParameters({ teamId, parameters }); + await this.performUpdate(teamId, [], async () => { + await this.graphQLService.sdk.saveTeamMetaParameters({ teamId, parameters }); + }); } protected validateKey(key: string): boolean { diff --git a/webapp/packages/core-authentication/src/UserInfoMetaParametersResource.ts b/webapp/packages/core-authentication/src/UserInfoMetaParametersResource.ts index 976bb380bd..172d89db37 100644 --- a/webapp/packages/core-authentication/src/UserInfoMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/UserInfoMetaParametersResource.ts @@ -13,23 +13,19 @@ import { UserInfoResource } from './UserInfoResource'; import type { UserMetaParameter } from './UserMetaParametersResource'; @injectable() -export class UserInfoMetaParametersResource extends CachedDataResource { +export class UserInfoMetaParametersResource extends CachedDataResource { constructor( private readonly graphQLService: GraphQLService, private readonly userInfoResource: UserInfoResource, ) { - super(() => null, undefined); + super(() => undefined, undefined); this.sync(this.userInfoResource); } - protected async loader(param: ResourceKey): Promise { - try { - const { user } = await this.graphQLService.sdk.getActiveUserMetaParameters(); + protected async loader(param: ResourceKey): Promise { + const { user } = await this.graphQLService.sdk.getActiveUserMetaParameters(); - return user?.metaParameters; - } catch (exception: any) { - return null; - } + return user?.metaParameters; } } diff --git a/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts index 14b6df8ba1..1ccb3c1a5a 100644 --- a/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts @@ -8,22 +8,11 @@ import { runInAction } from 'mobx'; import { injectable } from '@cloudbeaver/core-di'; -import { - CACHED_RESOURCE_DEFAULT_PAGE_LIMIT, - CACHED_RESOURCE_DEFAULT_PAGE_OFFSET, - CachedMapAllKey, - CachedMapResource, - CachedResourceOffsetPageKey, - CachedResourceOffsetPageListKey, - isResourceAlias, - ResourceKey, - resourceKeyList, - ResourceKeyUtils, -} from '@cloudbeaver/core-resource'; +import { CachedMapAllKey, CachedMapResource, isResourceAlias, ResourceKey, resourceKeyList, ResourceKeyUtils } from '@cloudbeaver/core-resource'; import { GraphQLService } from '@cloudbeaver/core-sdk'; import type { UserMetaParameter } from './UserMetaParametersResource'; -import { UsersResource, UsersResourceFilterKey } from './UsersResource'; +import { UsersResource } from './UsersResource'; @injectable() export class UsersMetaParametersResource extends CachedMapResource { @@ -34,6 +23,7 @@ export class UsersMetaParametersResource extends CachedMapResource): Promise { @@ -66,44 +56,6 @@ export class UsersMetaParametersResource extends CachedMapResource user.metaParameters)); - keys.push(...users.map(user => user.userId)); - - pages.push([ - CachedResourceOffsetPageListKey(offset, users.length).setParent(filterKey!), - users.map(user => user.userId), - users.length === limit, - ]); } }); diff --git a/webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts b/webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts index 2e635bb46b..972e48314d 100644 --- a/webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts +++ b/webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts @@ -8,21 +8,10 @@ import { runInAction } from 'mobx'; import { injectable } from '@cloudbeaver/core-di'; -import { - CACHED_RESOURCE_DEFAULT_PAGE_LIMIT, - CACHED_RESOURCE_DEFAULT_PAGE_OFFSET, - CachedMapAllKey, - CachedMapResource, - CachedResourceOffsetPageKey, - CachedResourceOffsetPageListKey, - isResourceAlias, - ResourceKey, - resourceKeyList, - ResourceKeyUtils, -} from '@cloudbeaver/core-resource'; +import { CachedMapAllKey, CachedMapResource, isResourceAlias, ResourceKey, resourceKeyList, ResourceKeyUtils } from '@cloudbeaver/core-resource'; import { AdminOriginDetailsFragment, GraphQLService } from '@cloudbeaver/core-sdk'; -import { UsersResource, UsersResourceFilterKey } from './UsersResource'; +import { UsersResource } from './UsersResource'; @injectable() export class UsersOriginDetailsResource extends CachedMapResource { @@ -33,6 +22,7 @@ export class UsersOriginDetailsResource extends CachedMapResource): Promise> { @@ -60,44 +50,6 @@ export class UsersOriginDetailsResource extends CachedMapResource user.userId)); - - pages.push([ - CachedResourceOffsetPageListKey(offset, users.length).setParent(filterKey!), - users.map(user => user.userId), - users.length === limit, - ]); } }); diff --git a/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts b/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts index 17effdd809..b3ae7859ad 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts @@ -32,6 +32,7 @@ export class ConnectionInfoOriginDetailsResource extends CachedMapResource Date: Mon, 16 Sep 2024 18:24:49 +0200 Subject: [PATCH 10/20] CB-4661 pr fixes 2 --- webapp/packages/core-authentication/src/TeamsResource.ts | 2 -- .../core-authentication/src/UsersMetaParametersResource.ts | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/webapp/packages/core-authentication/src/TeamsResource.ts b/webapp/packages/core-authentication/src/TeamsResource.ts index f65b7edaa8..fc50cf6313 100644 --- a/webapp/packages/core-authentication/src/TeamsResource.ts +++ b/webapp/packages/core-authentication/src/TeamsResource.ts @@ -24,8 +24,6 @@ import { } from '@cloudbeaver/core-sdk'; import { isArraysEqual, UndefinedToNull } from '@cloudbeaver/core-utils'; -import type { TeamMetaParameter } from './TeamMetaParametersResource'; - const NEW_TEAM_SYMBOL = Symbol('new-team'); export type TeamInfo = AdminTeamInfoFragment; diff --git a/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts index 1ccb3c1a5a..7c77a55178 100644 --- a/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts @@ -27,8 +27,9 @@ export class UsersMetaParametersResource extends CachedMapResource): Promise { - await this.graphQLService.sdk.saveUserMetaParameters({ userId, parameters }); - this.markOutdated(userId); + await this.performUpdate(userId, undefined, async () => { + await this.graphQLService.sdk.saveUserMetaParameters({ userId, parameters }); + }); } protected async loader(originalKey: ResourceKey): Promise> { From 438ce9f0bc031d05137525884afc1a138524fd55 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Tue, 17 Sep 2024 13:22:07 +0200 Subject: [PATCH 11/20] CB-4661 fixes origin info for connection templates table --- .../Connections/ConnectionsAdministrationService.ts | 2 +- .../Connections/ConnectionsTable/Connection.tsx | 4 +++- .../ConnectionsTable/ConnectionsTable.tsx | 12 ++++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts index cf17c0cf39..1620540af9 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts @@ -19,7 +19,7 @@ import { CreateConnectionService } from './CreateConnectionService'; export interface IConnectionDetailsPlaceholderProps { connection: DatabaseConnection; - connectionOrigin: DatabaseConnectionOriginFragment; + connectionOrigin?: DatabaseConnectionOriginFragment; } const ConnectionsAdministration = React.lazy(async () => { diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/Connection.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/Connection.tsx index e68320fd00..48a22df07f 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/Connection.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/Connection.tsx @@ -22,6 +22,7 @@ import { import { DatabaseConnection, IConnectionInfoParams } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { ProjectInfoResource } from '@cloudbeaver/core-projects'; +import { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import { ConnectionsAdministrationService } from '../ConnectionsAdministrationService'; import styles from './Connection.module.css'; @@ -31,10 +32,11 @@ interface Props { connectionKey: IConnectionInfoParams; connection: DatabaseConnection; shouldDisplayProject: boolean; + connectionOrigin?: DatabaseConnectionOriginFragment; icon?: string; } -export const Connection = observer(function Connection({ connectionKey, connection, shouldDisplayProject, icon }) { +export const Connection = observer(function Connection({ connectionKey, connectionOrigin, connection, shouldDisplayProject, icon }) { const style = useS(styles); const connectionsAdministrationService = useService(ConnectionsAdministrationService); const projectInfoResource = useResource(Connection, ProjectInfoResource, connectionKey.projectId, { active: shouldDisplayProject }); diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx index aa909a60c2..cc6d9fe3a0 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx @@ -6,10 +6,9 @@ * you may not use this file except in compliance with the License. */ import { observer } from 'mobx-react-lite'; -import { useMemo } from 'react'; import { Table, TableBody, TableColumnHeader, TableHeader, TableSelect, useResource, useTranslate } from '@cloudbeaver/core-blocks'; -import { DBDriverResource, serializeConnectionParam } from '@cloudbeaver/core-connections'; +import { ConnectionInfoOriginResource, DBDriverResource, serializeConnectionParam } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { isGlobalProject, isSharedProject, ProjectsService } from '@cloudbeaver/core-projects'; import { CachedMapAllKey } from '@cloudbeaver/core-resource'; @@ -27,6 +26,14 @@ export const ConnectionsTable = observer(function ConnectionsTable({ stat const projectService = useService(ProjectsService); const dbDriverResource = useResource(ConnectionsTable, DBDriverResource, CachedMapAllKey); const shouldDisplayProjects = projectService.activeProjects.filter(project => isGlobalProject(project) || isSharedProject(project)).length > 1; + const connectionOriginResource = useResource(ConnectionsTable, ConnectionInfoOriginResource, CachedMapAllKey); + const connectionOriginsMap: Map = connectionOriginResource.data.reduce((acc, origin) => { + if (origin?.id) { + acc.set(origin.id, origin); + } + + return acc; + }, new Map()); return ( @@ -47,6 +54,7 @@ export const ConnectionsTable = observer(function ConnectionsTable({ stat key={serializeConnectionParam(state.keys[i])} connectionKey={state.keys[i]} connection={connection} + connectionOrigin={connectionOriginsMap.get(connection.id)} shouldDisplayProject={shouldDisplayProjects} icon={dbDriverResource.resource.get(connection.driverId)?.icon} /> From ad22f292cd8f9fd88c1d870c9c45b6e183204c0d Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Tue, 17 Sep 2024 13:57:50 +0200 Subject: [PATCH 12/20] CB-4661 fix pr --- .../core-authentication/src/TeamInfoMetaParametersResource.ts | 4 ++++ .../core-authentication/src/UsersMetaParametersResource.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts b/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts index 6526f793b9..032f3889d6 100644 --- a/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts @@ -60,6 +60,10 @@ export class TeamInfoMetaParametersResource extends CachedMapResource): Promise { await this.performUpdate(teamId, [], async () => { await this.graphQLService.sdk.saveTeamMetaParameters({ teamId, parameters }); + + if (this.data) { + this.data.set(teamId, parameters as TeamMetaParameter); + } }); } diff --git a/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts index 7c77a55178..65844f651f 100644 --- a/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts @@ -29,6 +29,10 @@ export class UsersMetaParametersResource extends CachedMapResource): Promise { await this.performUpdate(userId, undefined, async () => { await this.graphQLService.sdk.saveUserMetaParameters({ userId, parameters }); + + if (this.data) { + this.data.set(userId, parameters as UserMetaParameter); + } }); } From 3f071f84aae422d7b1b82e5004293d00642b4c13 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Tue, 17 Sep 2024 14:13:20 +0200 Subject: [PATCH 13/20] CB-4661 cleanup --- .../src/UsersMetaParametersResource.ts | 11 +---------- .../src/UsersOriginDetailsResource.ts | 11 +---------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts index 65844f651f..b611529562 100644 --- a/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/UsersMetaParametersResource.ts @@ -5,8 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import { runInAction } from 'mobx'; - import { injectable } from '@cloudbeaver/core-di'; import { CachedMapAllKey, CachedMapResource, isResourceAlias, ResourceKey, resourceKeyList, ResourceKeyUtils } from '@cloudbeaver/core-resource'; import { GraphQLService } from '@cloudbeaver/core-sdk'; @@ -39,7 +37,6 @@ export class UsersMetaParametersResource extends CachedMapResource): Promise> { const all = this.aliases.isAlias(originalKey, CachedMapAllKey); const keys: string[] = []; - const pages: Parameters[] = []; if (all) { throw new Error('Loading all users is prohibited'); @@ -65,13 +62,7 @@ export class UsersMetaParametersResource extends CachedMapResource { - this.set(key, userMetaParametersList); - for (const pageArgs of pages) { - this.offsetPagination.setPage(...pageArgs); - } - }); + this.set(key, userMetaParametersList); return this.data; } diff --git a/webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts b/webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts index 972e48314d..ae5a988a61 100644 --- a/webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts +++ b/webapp/packages/core-authentication/src/UsersOriginDetailsResource.ts @@ -5,8 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import { runInAction } from 'mobx'; - import { injectable } from '@cloudbeaver/core-di'; import { CachedMapAllKey, CachedMapResource, isResourceAlias, ResourceKey, resourceKeyList, ResourceKeyUtils } from '@cloudbeaver/core-resource'; import { AdminOriginDetailsFragment, GraphQLService } from '@cloudbeaver/core-sdk'; @@ -28,7 +26,6 @@ export class UsersOriginDetailsResource extends CachedMapResource): Promise> { const all = this.aliases.isAlias(originalKey, CachedMapAllKey); const keys: string[] = []; - const pages: Parameters[] = []; if (all) { throw new Error('Loading all users is prohibited'); @@ -54,13 +51,7 @@ export class UsersOriginDetailsResource extends CachedMapResource { - this.set(key, userMetaParametersList); - for (const pageArgs of pages) { - this.offsetPagination.setPage(...pageArgs); - } - }); + this.set(key, userMetaParametersList); return this.data; } From 84240cdbf4d285534a2ab112bf9184feb7d69066 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Wed, 18 Sep 2024 14:46:11 +0200 Subject: [PATCH 14/20] CB-4461 pr fixes --- .../src/TeamInfoMetaParametersResource.ts | 5 ++ .../src/UsersMetaParametersResource.ts | 5 +- .../src/UsersOriginDetailsResource.ts | 5 +- .../ConnectionInfoOriginDetailsResource.ts | 63 ++++++++----------- .../src/ConnectionInfoOriginResource.ts | 55 +++++++--------- .../src/ConnectionInfoResource.ts | 48 ++++++-------- .../src/DatabaseConnection.ts | 17 ++--- .../src/parseConnectionKey.ts | 45 +++++++++++++ webapp/packages/core-resource/src/index.ts | 1 + .../fragments/DatabaseConnectionOrigin.gql | 1 - .../DatabaseConnectionOriginDetails.gql | 1 - .../GrantedConnections/ConnectionList.tsx | 5 +- .../GrantedConnections/GrantedConnections.tsx | 6 +- .../GrantedConnectionsList.tsx | 5 +- .../getFilteredConnections.ts | 19 +++--- .../UserFormConnectionAccess.tsx | 6 +- .../ConnectionsAdministrationService.ts | 5 +- .../ConnectionsTable/Connection.tsx | 5 +- .../ConnectionsTable/ConnectionsTable.tsx | 5 +- .../ConnectionAccess/ConnectionAccess.tsx | 2 +- .../ConnectionForm/IConnectionFormProps.ts | 4 +- .../src/ConnectionForm/Options/Options.tsx | 2 +- .../ConnectionOriginInfoTabService.ts | 5 +- 23 files changed, 159 insertions(+), 156 deletions(-) create mode 100644 webapp/packages/core-connections/src/parseConnectionKey.ts diff --git a/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts b/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts index 032f3889d6..489ddfc725 100644 --- a/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/TeamInfoMetaParametersResource.ts @@ -38,6 +38,11 @@ export class TeamInfoMetaParametersResource extends CachedMapResource): Promise> { const all = this.aliases.isAlias(originalKey, CachedMapAllKey); - const keys: string[] = []; + const keys = resourceKeyList([]); if (all) { throw new Error('Loading all users is prohibited'); @@ -61,8 +61,7 @@ export class UsersMetaParametersResource extends CachedMapResource): Promise> { const all = this.aliases.isAlias(originalKey, CachedMapAllKey); - const keys: string[] = []; + const keys = resourceKeyList([]); if (all) { throw new Error('Loading all users is prohibited'); @@ -50,8 +50,7 @@ export class UsersOriginDetailsResource extends CachedMapResource { +export class ConnectionInfoOriginDetailsResource extends CachedMapResource { constructor( private readonly projectsService: ProjectsService, private readonly graphQLService: GraphQLService, @@ -39,35 +36,25 @@ export class ConnectionInfoOriginDetailsResource extends CachedMapResource, _: any, refresh?: boolean, - ): Promise> { - const connectionsList: DatabaseConnectionOriginDetailsFragment[] = []; - const projectKey = this.aliases.isAlias(originalKey, ConnectionInfoProjectKey); + ): Promise> { + const connectionsList: ConnectionInfoOriginDetails[] = []; let removedConnections: IConnectionInfoParams[] = []; - let projectId: string | undefined; - let projectIds: string[] | undefined; - - if (projectKey) { - projectIds = projectKey.options.projectIds; - } - - if (this.aliases.isAlias(originalKey, ConnectionInfoActiveProjectKey)) { - projectIds = this.projectsService.activeProjects.map(project => project.id); - } - - if (isResourceAlias(originalKey)) { - const key = this.aliases.transformToKey(originalKey); - const outdated = ResourceKeyUtils.filter(key, key => this.isOutdated(key)); + const parsed = parseConnectionKey({ + originalKey, + aliases: this.aliases, + isOutdated: this.isOutdated.bind(this), + activeProjects: this.projectsService.activeProjects, + refresh, + }); - if (!refresh && outdated.length === 1) { - originalKey = outdated[0]; // load only single connection - } - } + let { projectId } = parsed; + const { projectIds, key } = parsed; - await ResourceKeyUtils.forEachAsync(originalKey, async key => { + await ResourceKeyUtils.forEachAsync(key, async connectionKey => { let connectionId: string | undefined; - if (!isResourceAlias(key)) { - projectId = key.projectId; - connectionId = key.connectionId; + if (!isResourceAlias(connectionKey)) { + projectId = connectionKey.projectId; + connectionId = connectionKey.connectionId; } const { connections } = await this.graphQLService.sdk.getUserConnectionsOriginDetails({ @@ -84,15 +71,15 @@ export class ConnectionInfoOriginDetailsResource extends CachedMapResource { - if (isResourceAlias(originalKey)) { - removedConnections = ResourceKeyUtils.toList(this.aliases.transformToKey(originalKey)).filter( - key => !connectionsList.some(connection => isConnectionInfoParamEqual(key, createConnectionParam(connection))), + if (isResourceAlias(key)) { + removedConnections = ResourceKeyUtils.toList(this.aliases.transformToKey(key)).filter( + filterKey => !connectionsList.some(connection => isConnectionInfoParamEqual(filterKey, createConnectionParam(connection))), ); } this.delete(resourceKeyList(removedConnections)); - const key = resourceKeyList(connectionsList.map(createConnectionParam)); - this.set(key, connectionsList); + const keys = resourceKeyList(connectionsList.map(createConnectionParam)); + this.set(keys, connectionsList); }); return this.data; diff --git a/webapp/packages/core-connections/src/ConnectionInfoOriginResource.ts b/webapp/packages/core-connections/src/ConnectionInfoOriginResource.ts index 00db00cd06..e712715adf 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoOriginResource.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoOriginResource.ts @@ -21,9 +21,12 @@ import { createConnectionParam, isConnectionInfoParamEqual, } from './ConnectionInfoResource'; +import { parseConnectionKey } from './parseConnectionKey'; + +export type ConnectionInfoOrigin = DatabaseConnectionOriginFragment; @injectable() -export class ConnectionInfoOriginResource extends CachedMapResource { +export class ConnectionInfoOriginResource extends CachedMapResource { constructor( private readonly projectsService: ProjectsService, private readonly graphQLService: GraphQLService, @@ -45,35 +48,25 @@ export class ConnectionInfoOriginResource extends CachedMapResource, _: any, refresh?: boolean, - ): Promise> { - const connectionsList: DatabaseConnectionOriginFragment[] = []; - const projectKey = this.aliases.isAlias(originalKey, ConnectionInfoProjectKey); + ): Promise> { + const connectionsList: ConnectionInfoOrigin[] = []; let removedConnections: IConnectionInfoParams[] = []; - let projectId: string | undefined; - let projectIds: string[] | undefined; - - if (projectKey) { - projectIds = projectKey.options.projectIds; - } - - if (this.aliases.isAlias(originalKey, ConnectionInfoActiveProjectKey)) { - projectIds = this.projectsService.activeProjects.map(project => project.id); - } - - if (isResourceAlias(originalKey)) { - const key = this.aliases.transformToKey(originalKey); - const outdated = ResourceKeyUtils.filter(key, key => this.isOutdated(key)); + const parsed = parseConnectionKey({ + originalKey, + aliases: this.aliases, + isOutdated: this.isOutdated.bind(this), + activeProjects: this.projectsService.activeProjects, + refresh, + }); - if (!refresh && outdated.length === 1) { - originalKey = outdated[0]; // load only single connection - } - } + let { projectId } = parsed; + const { projectIds, key } = parsed; - await ResourceKeyUtils.forEachAsync(originalKey, async key => { + await ResourceKeyUtils.forEachAsync(key, async connectionKey => { let connectionId: string | undefined; - if (!isResourceAlias(key)) { - projectId = key.projectId; - connectionId = key.connectionId; + if (!isResourceAlias(connectionKey)) { + projectId = connectionKey.projectId; + connectionId = connectionKey.connectionId; } const { connections } = await this.graphQLService.sdk.getUserConnectionsOrigin({ @@ -90,15 +83,15 @@ export class ConnectionInfoOriginResource extends CachedMapResource { - if (isResourceAlias(originalKey)) { - removedConnections = ResourceKeyUtils.toList(this.aliases.transformToKey(originalKey)).filter( - key => !connectionsList.some(connection => isConnectionInfoParamEqual(key, createConnectionParam(connection))), + if (isResourceAlias(key)) { + removedConnections = ResourceKeyUtils.toList(this.aliases.transformToKey(key)).filter( + filterKey => !connectionsList.some(connection => isConnectionInfoParamEqual(filterKey, createConnectionParam(connection))), ); } this.delete(resourceKeyList(removedConnections)); - const key = resourceKeyList(connectionsList.map(createConnectionParam)); - this.set(key, connectionsList); + const keys = resourceKeyList(connectionsList.map(createConnectionParam)); + this.set(keys, connectionsList); }); return this.data; diff --git a/webapp/packages/core-connections/src/ConnectionInfoResource.ts b/webapp/packages/core-connections/src/ConnectionInfoResource.ts index 407f31850c..5dd3a57341 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoResource.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoResource.ts @@ -41,6 +41,7 @@ import { CONNECTION_INFO_PARAM_SCHEMA, type IConnectionInfoParams } from './CONN import { ConnectionInfoEventHandler, IConnectionInfoEvent } from './ConnectionInfoEventHandler'; import type { DatabaseConnection } from './DatabaseConnection'; import { DBDriverResource } from './DBDriverResource'; +import { parseConnectionKey } from './parseConnectionKey'; export type Connection = DatabaseConnection & { authProperties?: UserConnectionAuthPropertiesFragment[]; @@ -490,33 +491,24 @@ export class ConnectionInfoResource extends CachedMapResource> { const connectionsList: Connection[] = []; - const projectKey = this.aliases.isAlias(originalKey, ConnectionInfoProjectKey); let removedConnections: IConnectionInfoParams[] = []; - let projectId: string | undefined; - let projectIds: string[] | undefined; - if (projectKey) { - projectIds = projectKey.options.projectIds; - } - - if (this.aliases.isAlias(originalKey, ConnectionInfoActiveProjectKey)) { - projectIds = this.projectsService.activeProjects.map(project => project.id); - } - - if (isResourceAlias(originalKey)) { - const key = this.aliases.transformToKey(originalKey); - const outdated = ResourceKeyUtils.filter(key, key => this.isOutdated(key, includes)); + const parsed = parseConnectionKey({ + originalKey, + aliases: this.aliases, + isOutdated: this.isOutdated.bind(this), + activeProjects: this.projectsService.activeProjects, + refresh, + }); - if (!refresh && outdated.length === 1) { - originalKey = outdated[0]; // load only single connection - } - } + let { projectId } = parsed; + const { projectIds, key } = parsed; - await ResourceKeyUtils.forEachAsync(originalKey, async key => { + await ResourceKeyUtils.forEachAsync(key, async connectionKey => { let connectionId: string | undefined; - if (!isResourceAlias(key)) { - projectId = key.projectId; - connectionId = key.connectionId; + if (!isResourceAlias(connectionKey)) { + projectId = connectionKey.projectId; + connectionId = connectionKey.connectionId; } const { connections } = await this.graphQLService.sdk.getUserConnections({ @@ -524,7 +516,7 @@ export class ConnectionInfoResource extends CachedMapResource connection.id === connectionId)) { @@ -535,15 +527,15 @@ export class ConnectionInfoResource extends CachedMapResource { - if (isResourceAlias(originalKey)) { - removedConnections = ResourceKeyUtils.toList(this.aliases.transformToKey(originalKey)).filter( - key => !connectionsList.some(connection => isConnectionInfoParamEqual(key, createConnectionParam(connection))), + if (isResourceAlias(key)) { + removedConnections = ResourceKeyUtils.toList(this.aliases.transformToKey(key)).filter( + filterKey => !connectionsList.some(connection => isConnectionInfoParamEqual(filterKey, createConnectionParam(connection))), ); } this.delete(resourceKeyList(removedConnections)); - const key = resourceKeyList(connectionsList.map(createConnectionParam)); - this.set(key, connectionsList); + const keys = resourceKeyList(connectionsList.map(createConnectionParam)); + this.set(keys, connectionsList); }); this.sessionUpdate = false; diff --git a/webapp/packages/core-connections/src/DatabaseConnection.ts b/webapp/packages/core-connections/src/DatabaseConnection.ts index 97acd8962c..c8cb8c9988 100644 --- a/webapp/packages/core-connections/src/DatabaseConnection.ts +++ b/webapp/packages/core-connections/src/DatabaseConnection.ts @@ -6,21 +6,14 @@ * you may not use this file except in compliance with the License. */ import { AUTH_PROVIDER_LOCAL_ID } from '@cloudbeaver/core-authentication'; -import type { DatabaseConnectionFragment, DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; +import type { DatabaseConnectionFragment, ObjectOriginInfoFragment } from '@cloudbeaver/core-sdk'; export type DatabaseConnection = DatabaseConnectionFragment; -export type DatabaseConnectionOrigin = DatabaseConnectionOriginFragment; -export function isLocalConnection(connectionOrigin: DatabaseConnectionOrigin | DatabaseConnection): boolean { - if (!('origin' in connectionOrigin) || !connectionOrigin.origin) { - return true; - } - return connectionOrigin.origin.type === AUTH_PROVIDER_LOCAL_ID; +export function isLocalConnection(origin: ObjectOriginInfoFragment): boolean { + return origin.type === AUTH_PROVIDER_LOCAL_ID; } -export function isCloudConnection(connectionOrigin?: DatabaseConnectionOrigin): boolean { - if (!connectionOrigin?.origin) { - return false; - } - return connectionOrigin.origin.type === 'cloud'; +export function isCloudConnection(origin: ObjectOriginInfoFragment): boolean { + return origin.type === 'cloud'; } diff --git a/webapp/packages/core-connections/src/parseConnectionKey.ts b/webapp/packages/core-connections/src/parseConnectionKey.ts new file mode 100644 index 0000000000..ac6a1b795e --- /dev/null +++ b/webapp/packages/core-connections/src/parseConnectionKey.ts @@ -0,0 +1,45 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { isResourceAlias, ResourceAliases, ResourceKey, ResourceKeyUtils } from '@cloudbeaver/core-resource'; +import { ProjectInfo } from '@cloudbeaver/core-sdk'; + +import { IConnectionInfoParams } from './CONNECTION_INFO_PARAM_SCHEMA'; +import { ConnectionInfoActiveProjectKey, ConnectionInfoProjectKey } from './ConnectionInfoResource'; + +type Args = { + originalKey: ResourceKey; + aliases: ResourceAliases; + isOutdated: (key: ResourceKey) => boolean; + activeProjects: ProjectInfo[]; + refresh?: boolean; +}; + +export function parseConnectionKey({ originalKey, aliases, isOutdated, activeProjects, refresh }: Args) { + const projectKey = aliases.isAlias(originalKey, ConnectionInfoProjectKey); + let projectId: string | undefined; + let projectIds: string[] | undefined; + + if (projectKey) { + projectIds = projectKey.options.projectIds; + } + + if (aliases.isAlias(originalKey, ConnectionInfoActiveProjectKey)) { + projectIds = activeProjects.map(project => project.id); + } + + if (isResourceAlias(originalKey)) { + const key = aliases.transformToKey(originalKey); + const outdated = ResourceKeyUtils.filter(key, key => isOutdated(key)); + + if (!refresh && outdated.length === 1) { + originalKey = outdated[0]; // load only single connection + } + } + + return { projectId, projectIds, key: originalKey }; +} diff --git a/webapp/packages/core-resource/src/index.ts b/webapp/packages/core-resource/src/index.ts index 6ff9ce3edd..e9c643252d 100644 --- a/webapp/packages/core-resource/src/index.ts +++ b/webapp/packages/core-resource/src/index.ts @@ -24,6 +24,7 @@ export * from './Resource/ICachedResourceMetadata'; export * from './Resource/IResource'; export * from './Resource/Resource'; export * from './Resource/ResourceAlias'; +export * from './Resource/ResourceAliases'; export * from './Resource/ResourceError'; export * from './Resource/ResourceKey'; export * from './Resource/ResourceKeyAlias'; diff --git a/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOrigin.gql b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOrigin.gql index fd95b3343c..be6631cd89 100644 --- a/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOrigin.gql +++ b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOrigin.gql @@ -1,7 +1,6 @@ fragment DatabaseConnectionOrigin on ConnectionInfo { id projectId - driverId origin { ...ObjectOriginInfo } diff --git a/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOriginDetails.gql b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOriginDetails.gql index 366f8c3147..4d2de9a430 100644 --- a/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOriginDetails.gql +++ b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionOriginDetails.gql @@ -1,7 +1,6 @@ fragment DatabaseConnectionOriginDetails on ConnectionInfo { id projectId - driverId origin { ...OriginDetails } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/ConnectionList.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/ConnectionList.tsx index b237e6d3a2..2d9dd9a9f2 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/ConnectionList.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/ConnectionList.tsx @@ -24,9 +24,8 @@ import { useS, useTranslate, } from '@cloudbeaver/core-blocks'; -import { Connection, DBDriverResource } from '@cloudbeaver/core-connections'; +import { Connection, ConnectionInfoOrigin, DBDriverResource } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; -import { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import styles from './ConnectionList.module.css'; import { getFilteredConnections } from './getFilteredConnections'; @@ -36,7 +35,7 @@ import { GrantedConnectionsTableItem } from './GrantedConnectionsTableItem'; interface Props { connectionList: Connection[]; - connectionsOrigins: DatabaseConnectionOriginFragment[]; + connectionsOrigins: ConnectionInfoOrigin[]; grantedSubjects: string[]; disabled: boolean; onGrant: (subjectIds: string[]) => void; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnections.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnections.tsx index 7e5a0e90ab..edba9f0fb7 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnections.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnections.tsx @@ -22,6 +22,7 @@ import { } from '@cloudbeaver/core-blocks'; import { Connection, + ConnectionInfoOrigin, ConnectionInfoOriginResource, ConnectionInfoProjectKey, ConnectionInfoResource, @@ -31,7 +32,6 @@ import { import type { TLocalizationToken } from '@cloudbeaver/core-localization'; import { isGlobalProject, ProjectInfo, ProjectInfoResource } from '@cloudbeaver/core-projects'; import { CachedMapAllKey } from '@cloudbeaver/core-resource'; -import { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import { TabContainerPanelComponent, useTab } from '@cloudbeaver/core-ui'; import type { ITeamFormProps } from '../ITeamFormProps'; @@ -62,7 +62,7 @@ export const GrantedConnections: TabContainerPanelComponent = ob const connections = connectionsLoader.data as Connection[]; const grantedConnections = getComputed(() => connections.filter(connection => state.state.grantedSubjects.includes(connection.id))); - const connectionsOrigins = (connectionsOriginLoader.data ?? []) as DatabaseConnectionOriginFragment[]; + const connectionsOrigins = (connectionsOriginLoader.data ?? []) as ConnectionInfoOrigin[]; useAutoLoad(GrantedConnections, state, selected && !loaded); @@ -72,7 +72,7 @@ export const GrantedConnections: TabContainerPanelComponent = ob let info: TLocalizationToken | null = null; - const cloudExists = connectionsOrigins.some(isCloudConnection); + const cloudExists = connectionsOrigins.some(connectionOrigin => isCloudConnection(connectionOrigin.origin)); if (cloudExists) { info = 'cloud_connections_access_placeholder'; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsList.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsList.tsx index 85d2bd5620..e96b988961 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsList.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsList.tsx @@ -24,10 +24,9 @@ import { useS, useTranslate, } from '@cloudbeaver/core-blocks'; -import { Connection, DBDriverResource } from '@cloudbeaver/core-connections'; +import { Connection, ConnectionInfoOrigin, DBDriverResource } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import type { TLocalizationToken } from '@cloudbeaver/core-localization'; -import { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import { getFilteredConnections } from './getFilteredConnections'; import style from './GrantedConnectionsList.module.css'; @@ -37,7 +36,7 @@ import { GrantedConnectionsTableItem } from './GrantedConnectionsTableItem'; interface Props { grantedConnections: Connection[]; - connectionsOrigins: DatabaseConnectionOriginFragment[]; + connectionsOrigins: ConnectionInfoOrigin[]; disabled: boolean; onRevoke: (subjectIds: string[]) => void; onEdit: () => void; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/getFilteredConnections.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/getFilteredConnections.ts index a965344d08..7d5020bb06 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/getFilteredConnections.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/getFilteredConnections.ts @@ -5,27 +5,24 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import { isCloudConnection } from '@cloudbeaver/core-connections'; -import type { DatabaseConnectionFragment, DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; +import { Connection, ConnectionInfoOrigin, isCloudConnection } from '@cloudbeaver/core-connections'; /** * @param {DatabaseConnectionFragment[]} connections * @param {string} filter */ -export function getFilteredConnections( - connections: DatabaseConnectionFragment[], - connectionsOrigin: DatabaseConnectionOriginFragment[], - filter: string, -): DatabaseConnectionFragment[] { - const connectionsOriginsMap = new Map(); +export function getFilteredConnections(connections: Connection[], connectionsOrigin: ConnectionInfoOrigin[], filter: string): Connection[] { + const connectionsOriginsMap = new Map(); for (const connectionOrigin of connectionsOrigin) { connectionsOriginsMap.set(connectionOrigin.id, connectionOrigin); } return connections - .filter( - connection => connection.name.toLowerCase().includes(filter.toLowerCase()) && !isCloudConnection(connectionsOriginsMap.get(connection.id)), - ) + .filter(connection => { + const originDetails = connectionsOriginsMap.get(connection.id); + + return connection.name.toLowerCase().includes(filter.toLowerCase()) && originDetails && !isCloudConnection(originDetails.origin); + }) .sort((a, b) => a.name.localeCompare(b.name)); } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/UserFormConnectionAccess.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/UserFormConnectionAccess.tsx index a8c08d7032..df7a64e1d9 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/UserFormConnectionAccess.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/UserFormConnectionAccess.tsx @@ -51,8 +51,10 @@ export const UserFormConnectionAccess: TabContainerPanelComponent const connections = connectionsLoader.data.filter(isDefined).sort(compareConnectionsInfo); const connectionsOrigins = connectionsOriginsLoader.data.filter(isDefined); - const cloudExists = connectionsOrigins.some(isCloudConnection); - const localConnectionsIds = new Set(connectionsOrigins.filter(connection => !isCloudConnection(connection)).map(connection => connection.id)); + const cloudExists = connectionsOrigins.some(connectionOrigin => isCloudConnection(connectionOrigin.origin)); + const localConnectionsIds = new Set( + connectionsOrigins.filter(connection => !isCloudConnection(connection.origin)).map(connection => connection.id), + ); const localConnections = connections.filter(connection => localConnectionsIds.has(connection.id)); useResource( diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts index 1620540af9..64401a1733 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts @@ -9,17 +9,16 @@ import React from 'react'; import { AdministrationItemService, AdministrationItemType } from '@cloudbeaver/core-administration'; import { ConfirmationDialog, PlaceholderContainer } from '@cloudbeaver/core-blocks'; -import { ConnectionInfoResource, DatabaseConnection } from '@cloudbeaver/core-connections'; +import { ConnectionInfoOrigin, ConnectionInfoResource, DatabaseConnection } from '@cloudbeaver/core-connections'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService, DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { ServerConfigResource } from '@cloudbeaver/core-root'; -import type { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import { CreateConnectionService } from './CreateConnectionService'; export interface IConnectionDetailsPlaceholderProps { connection: DatabaseConnection; - connectionOrigin?: DatabaseConnectionOriginFragment; + connectionOrigin?: ConnectionInfoOrigin; } const ConnectionsAdministration = React.lazy(async () => { diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/Connection.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/Connection.tsx index 48a22df07f..7181b9729f 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/Connection.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/Connection.tsx @@ -19,10 +19,9 @@ import { useResource, useS, } from '@cloudbeaver/core-blocks'; -import { DatabaseConnection, IConnectionInfoParams } from '@cloudbeaver/core-connections'; +import { ConnectionInfoOrigin, DatabaseConnection, IConnectionInfoParams } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { ProjectInfoResource } from '@cloudbeaver/core-projects'; -import { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import { ConnectionsAdministrationService } from '../ConnectionsAdministrationService'; import styles from './Connection.module.css'; @@ -32,7 +31,7 @@ interface Props { connectionKey: IConnectionInfoParams; connection: DatabaseConnection; shouldDisplayProject: boolean; - connectionOrigin?: DatabaseConnectionOriginFragment; + connectionOrigin?: ConnectionInfoOrigin; icon?: string; } diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx index cc6d9fe3a0..a80c762246 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx @@ -8,11 +8,10 @@ import { observer } from 'mobx-react-lite'; import { Table, TableBody, TableColumnHeader, TableHeader, TableSelect, useResource, useTranslate } from '@cloudbeaver/core-blocks'; -import { ConnectionInfoOriginResource, DBDriverResource, serializeConnectionParam } from '@cloudbeaver/core-connections'; +import { ConnectionInfoOrigin, ConnectionInfoOriginResource, DBDriverResource, serializeConnectionParam } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { isGlobalProject, isSharedProject, ProjectsService } from '@cloudbeaver/core-projects'; import { CachedMapAllKey } from '@cloudbeaver/core-resource'; -import { DatabaseConnectionOriginFragment } from '@cloudbeaver/core-sdk'; import { Connection } from './Connection'; import { IConnectionsTableState } from './useConnectionsTable'; @@ -27,7 +26,7 @@ export const ConnectionsTable = observer(function ConnectionsTable({ stat const dbDriverResource = useResource(ConnectionsTable, DBDriverResource, CachedMapAllKey); const shouldDisplayProjects = projectService.activeProjects.filter(project => isGlobalProject(project) || isSharedProject(project)).length > 1; const connectionOriginResource = useResource(ConnectionsTable, ConnectionInfoOriginResource, CachedMapAllKey); - const connectionOriginsMap: Map = connectionOriginResource.data.reduce((acc, origin) => { + const connectionOriginsMap: Map = connectionOriginResource.data.reduce((acc, origin) => { if (origin?.id) { acc.set(origin.id, origin); } diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx index d5a6dfc5c8..7c9bcb564b 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx @@ -63,7 +63,7 @@ export const ConnectionAccess: TabContainerPanelComponent } const loading = users.isLoading() || teams.isLoading() || state.state.loading; - const cloud = formState.info ? isCloudConnection(formState.originInfo) : false; + const cloud = formState.info && formState.originInfo?.origin ? isCloudConnection(formState.originInfo.origin) : false; const disabled = loading || !state.state.loaded || formState.disabled || cloud; let info: TLocalizationToken | null = null; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts index 1c4104a99b..cb02bcc932 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts @@ -5,7 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import type { ConnectionInfoResource, DatabaseConnection, DatabaseConnectionOrigin } from '@cloudbeaver/core-connections'; +import type { ConnectionInfoOrigin, ConnectionInfoResource, DatabaseConnection } from '@cloudbeaver/core-connections'; import type { IExecutor, IExecutorHandlersCollection } from '@cloudbeaver/core-executor'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; import type { IFormStateInfo } from '@cloudbeaver/core-ui'; @@ -33,7 +33,7 @@ export interface IConnectionFormState { readonly availableDrivers: string[]; readonly resource: ConnectionInfoResource; readonly info: DatabaseConnection | undefined; - readonly originInfo: DatabaseConnectionOrigin | undefined; + readonly originInfo: ConnectionInfoOrigin | undefined; readonly readonly: boolean; readonly submittingTask: IExecutorHandlersCollection; readonly closeTask: IExecutor; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx index 7b1b189a25..cd3c2a2347 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx @@ -149,7 +149,7 @@ export const Options: TabContainerPanelComponent = observe }); const edit = state.mode === 'edit'; - const originLocal = !info || (originInfo && isLocalConnection(originInfo)); + const originLocal = !info || (originInfo?.origin && isLocalConnection(originInfo.origin)); const drivers = driverMap.resource.enabledDrivers.filter(({ id }) => availableDrivers.includes(id)); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionOriginInfoTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionOriginInfoTabService.ts index 89055b06f1..433d2f34e9 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionOriginInfoTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionOriginInfoTabService.ts @@ -9,11 +9,8 @@ import React from 'react'; import { isLocalConnection } from '@cloudbeaver/core-connections'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; -import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; -import { connectionFormConfigureContext } from '../connectionFormConfigureContext'; import { ConnectionFormService } from '../ConnectionFormService'; -import type { IConnectionFormState } from '../IConnectionFormProps'; export const ConnectionFormAuthenticationAction = React.lazy(async () => { const { ConnectionFormAuthenticationAction } = await import('./ConnectionFormAuthenticationAction'); @@ -41,7 +38,7 @@ export class ConnectionOriginInfoTabService extends Bootstrap { tab: () => OriginInfoTab, panel: () => OriginInfo, stateGetter: () => () => ({}), - isHidden: (tabId, props) => (props?.state.originInfo ? isLocalConnection(props.state.originInfo) : true), + isHidden: (tabId, props) => (props?.state.originInfo ? isLocalConnection(props.state.originInfo.origin) : true), }); this.connectionFormService.actionsContainer.add(ConnectionFormAuthenticationAction, 0); From f0771609319daab0991459b3b10726c5384c86b3 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Wed, 18 Sep 2024 16:07:10 +0200 Subject: [PATCH 15/20] CB-4661 cleanup --- .../ConnectionsTable/ConnectionsTable.tsx | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx index a80c762246..9fee661b70 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx @@ -12,6 +12,7 @@ import { ConnectionInfoOrigin, ConnectionInfoOriginResource, DBDriverResource, s import { useService } from '@cloudbeaver/core-di'; import { isGlobalProject, isSharedProject, ProjectsService } from '@cloudbeaver/core-projects'; import { CachedMapAllKey } from '@cloudbeaver/core-resource'; +import { isNotNullDefined } from '@cloudbeaver/core-utils'; import { Connection } from './Connection'; import { IConnectionsTableState } from './useConnectionsTable'; @@ -20,19 +21,27 @@ interface Props { state: IConnectionsTableState; } +function getOriginsMap(origins: (ConnectionInfoOrigin | undefined)[]) { + const map = new Map(); + + for (const origin of origins) { + if (!isNotNullDefined(origin)) { + continue; + } + + map.set(origin.id, origin); + } + + return map; +} + export const ConnectionsTable = observer(function ConnectionsTable({ state }) { const translate = useTranslate(); const projectService = useService(ProjectsService); const dbDriverResource = useResource(ConnectionsTable, DBDriverResource, CachedMapAllKey); const shouldDisplayProjects = projectService.activeProjects.filter(project => isGlobalProject(project) || isSharedProject(project)).length > 1; const connectionOriginResource = useResource(ConnectionsTable, ConnectionInfoOriginResource, CachedMapAllKey); - const connectionOriginsMap: Map = connectionOriginResource.data.reduce((acc, origin) => { - if (origin?.id) { - acc.set(origin.id, origin); - } - - return acc; - }, new Map()); + const connectionOriginsMap = getOriginsMap(connectionOriginResource.data); return (
From 4493dc6f99577ea6c302c5a92994f0336c7a4cfb Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Wed, 18 Sep 2024 16:18:48 +0200 Subject: [PATCH 16/20] CB-4661 fix parallel loading of request for teams --- .../Users/Teams/Options/TeamOptionsTabService.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts index d9fcbca3d1..18d1d2fa56 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts @@ -109,18 +109,14 @@ export class TeamOptionsTabService extends Bootstrap { try { if (create) { - const [team] = await Promise.all([ - this.teamResource.createTeam(config), - this.teamsMetaParametersResource.setMetaParameters(config.teamId, metaParameters), - ]); + const team = await this.teamResource.createTeam(config); + await this.teamsMetaParametersResource.setMetaParameters(config.teamId, metaParameters); status.info('administration_teams_team_info_created'); status.info(team.teamId); } else { - const [team] = await Promise.all([ - this.teamResource.updateTeam(config), - this.teamsMetaParametersResource.setMetaParameters(config.teamId, metaParameters), - ]); + const team = await this.teamResource.updateTeam(config); + await this.teamsMetaParametersResource.setMetaParameters(config.teamId, metaParameters); status.info('administration_teams_team_info_updated'); status.info(team.teamId); From 9c850ca58b83da5fac33b8a468ca53b48925bbf4 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Wed, 18 Sep 2024 16:24:25 +0200 Subject: [PATCH 17/20] CB-4661 cleanup --- .../ConnectionsTable/ConnectionsTable.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx index 9fee661b70..19a3942550 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionsTable.tsx @@ -22,17 +22,7 @@ interface Props { } function getOriginsMap(origins: (ConnectionInfoOrigin | undefined)[]) { - const map = new Map(); - - for (const origin of origins) { - if (!isNotNullDefined(origin)) { - continue; - } - - map.set(origin.id, origin); - } - - return map; + return new Map(origins.filter(isNotNullDefined).map(origin => [origin.id, origin])); } export const ConnectionsTable = observer(function ConnectionsTable({ state }) { From 4e57ce5f443e54dfdf66fcc72c8e9bd1176cf494 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Fri, 20 Sep 2024 13:25:42 +0200 Subject: [PATCH 18/20] CB-4661 fixes aws/azure/gcp and other tabs in edit cloud connection --- .../ConnectionInfoOriginDetailsResource.ts | 4 +++ .../src/ConnectionInfoOriginResource.ts | 4 +++ .../src/Search/ConnectionSearchService.ts | 3 +++ .../ConnectionsTable/ConnectionEdit.tsx | 12 +++++++-- .../Connections/CreateConnectionService.ts | 4 ++- .../src/ConnectionForm/ConnectionFormState.ts | 13 +++++++++- .../ConnectionForm/IConnectionFormProps.ts | 3 ++- .../ConnectionForm/OriginInfo/OriginInfo.tsx | 26 +++++++++---------- .../ConnectionForm/useConnectionFormState.ts | 5 ++-- .../PublicConnectionFormService.ts | 3 +++ 10 files changed, 57 insertions(+), 20 deletions(-) diff --git a/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts b/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts index 8ee84d6892..b0cb244ca0 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts @@ -85,6 +85,10 @@ export class ConnectionInfoOriginDetailsResource extends CachedMapResource(function ConnectionEditNew({ item }) { const connectionInfoResource = useService(ConnectionInfoResource); const connectionInfoOriginResource = useService(ConnectionInfoOriginResource); + const connectionInfoOriginDetailsResource = useService(ConnectionInfoOriginDetailsResource); // const tableContext = useContext(TableContext); // const collapse = useCallback(() => tableContext?.setItemExpand(item, false), [tableContext, item]); - const data = useConnectionFormState(connectionInfoResource, connectionInfoOriginResource, state => state.setOptions('edit', 'admin')); + const data = useConnectionFormState(connectionInfoResource, connectionInfoOriginResource, connectionInfoOriginDetailsResource, state => + state.setOptions('edit', 'admin'), + ); const style = useS(styles); const projectId = item.projectId; diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts index c0c00c507d..1296496b14 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts @@ -8,7 +8,7 @@ import { action, makeObservable, observable } from 'mobx'; import { AdministrationScreenService } from '@cloudbeaver/core-administration'; -import { ConnectionInfoOriginResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; +import { ConnectionInfoOriginDetailsResource, ConnectionInfoOriginResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; @@ -39,6 +39,7 @@ export class CreateConnectionService { private readonly projectsService: ProjectsService, private readonly projectInfoResource: ProjectInfoResource, private readonly connectionInfoOriginResource: ConnectionInfoOriginResource, + private readonly connectionInfoOriginDetailsResource: ConnectionInfoOriginDetailsResource, ) { this.data = null; this.tabsContainer = new TabsContainer('Connection Creation mode'); @@ -116,6 +117,7 @@ export class CreateConnectionService { this.connectionFormService, this.connectionInfoResource, this.connectionInfoOriginResource, + this.connectionInfoOriginDetailsResource, ); this.data.closeTask.addHandler(this.cancelCreate.bind(this)); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts index 1873386ec5..17db5001f9 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts @@ -8,6 +8,7 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { + ConnectionInfoOriginDetailsResource, ConnectionInfoOriginResource, ConnectionInfoResource, createConnectionParam, @@ -62,6 +63,14 @@ export class ConnectionFormState implements IConnectionFormState { return this.resource.get(createConnectionParam(this.projectId, this.config.connectionId)); } + get originDetails() { + if (!this.config.connectionId || this.projectId === null) { + return undefined; + } + + this.originDetailsResource.get(createConnectionParam(this.projectId, this.config.connectionId)); + } + get originInfo() { if (!this.config.connectionId || this.projectId === null) { return undefined; @@ -111,6 +120,7 @@ export class ConnectionFormState implements IConnectionFormState { service: ConnectionFormService, resource: ConnectionInfoResource, private readonly originResource: ConnectionInfoOriginResource, + private readonly originDetailsResource: ConnectionInfoOriginDetailsResource, ) { this._id = uuid(); this.initError = null; @@ -181,6 +191,7 @@ export class ConnectionFormState implements IConnectionFormState { _availableDrivers: observable, info: computed, originInfo: computed, + originDetails: computed, statusMessage: observable, configured: observable, readonly: computed, @@ -334,6 +345,6 @@ export class ConnectionFormState implements IConnectionFormState { return; } - await data.resource.load(key, configuration.connectionIncludes); + Promise.all([data.resource.load(key, configuration.connectionIncludes), this.originResource.load(key), this.originDetailsResource.load(key)]); } } diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts index cb02bcc932..28af3f13c6 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts @@ -5,7 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import type { ConnectionInfoOrigin, ConnectionInfoResource, DatabaseConnection } from '@cloudbeaver/core-connections'; +import type { ConnectionInfoOrigin, ConnectionInfoOriginDetails, ConnectionInfoResource, DatabaseConnection } from '@cloudbeaver/core-connections'; import type { IExecutor, IExecutorHandlersCollection } from '@cloudbeaver/core-executor'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; import type { IFormStateInfo } from '@cloudbeaver/core-ui'; @@ -34,6 +34,7 @@ export interface IConnectionFormState { readonly resource: ConnectionInfoResource; readonly info: DatabaseConnection | undefined; readonly originInfo: ConnectionInfoOrigin | undefined; + readonly originDetails: ConnectionInfoOriginDetails | undefined; readonly readonly: boolean; readonly submittingTask: IExecutorHandlersCollection; readonly closeTask: IExecutor; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx index 1f959ed580..91e9f8460b 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx @@ -21,12 +21,7 @@ import { useS, useTranslate, } from '@cloudbeaver/core-blocks'; -import { - ConnectionInfoOriginDetailsResource, - createConnectionParam, - DatabaseAuthModelsResource, - DBDriverResource, -} from '@cloudbeaver/core-connections'; +import { createConnectionParam, DatabaseAuthModelsResource, DBDriverResource } from '@cloudbeaver/core-connections'; import { TabContainerPanelComponent, useTab, useTabState } from '@cloudbeaver/core-ui'; import type { IConnectionFormProps } from '../IConnectionFormProps'; @@ -34,7 +29,7 @@ import styles from './OriginInfo.module.css'; export const OriginInfo: TabContainerPanelComponent = observer(function OriginInfo({ tabId, - state: { info, resource, config }, + state: { info, resource, config, originDetails }, }) { const tab = useTab(tabId); const translate = useTranslate(); @@ -51,14 +46,19 @@ export const OriginInfo: TabContainerPanelComponent = obse const providerId = authModeLoader.data?.requiredAuth ?? info?.requiredAuth ?? AUTH_PROVIDER_LOCAL_ID; const isAuthenticated = userInfoLoader.resource.hasToken(providerId); const providerLoader = useResource(OriginInfo, AuthProvidersResource, providerId); - const connectionId = tab.selected && info ? createConnectionParam(info.projectId, info.id) : null; + const connectionId = + tab.selected && info + ? createConnectionParam({ + id: info.id, + projectId: info.projectId, + }) + : null; - const connectionOriginDetailsResource = useResource(OriginInfo, ConnectionInfoOriginDetailsResource, connectionId); const connection = useResource(OriginInfo, resource, connectionId, { active: isAuthenticated, onData: connection => { runInAction(() => { - if (!connectionOriginDetailsResource.data?.origin.details) { + if (!originDetails?.origin.details) { return; } @@ -67,7 +67,7 @@ export const OriginInfo: TabContainerPanelComponent = obse delete state[property]; } - for (const property of connectionOriginDetailsResource.data.origin.details) { + for (const property of originDetails.origin.details) { state[property.id!] = property.value; } }); @@ -102,7 +102,7 @@ export const OriginInfo: TabContainerPanelComponent = obse ); } - if (!connectionOriginDetailsResource.data?.origin.details || connectionOriginDetailsResource.data?.origin.details.length === 0) { + if (!originDetails?.origin.details || originDetails?.origin.details.length === 0) { return ( {translate('connections_administration_connection_no_information')} @@ -113,7 +113,7 @@ export const OriginInfo: TabContainerPanelComponent = obse return ( - + diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts b/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts index 7d241a001e..ad2bc7ca74 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts @@ -7,7 +7,7 @@ */ import { useEffect, useState } from 'react'; -import type { ConnectionInfoOriginResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; +import type { ConnectionInfoOriginDetailsResource, ConnectionInfoOriginResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects'; @@ -18,6 +18,7 @@ import type { IConnectionFormState } from './IConnectionFormProps'; export function useConnectionFormState( resource: ConnectionInfoResource, originResource: ConnectionInfoOriginResource, + originDetailsResource: ConnectionInfoOriginDetailsResource, configure?: (state: IConnectionFormState) => any, ): IConnectionFormState { const projectsService = useService(ProjectsService); @@ -25,7 +26,7 @@ export function useConnectionFormState( const service = useService(ConnectionFormService); const [state] = useState(() => { - const state = new ConnectionFormState(projectsService, projectInfoResource, service, resource, originResource); + const state = new ConnectionFormState(projectsService, projectInfoResource, service, resource, originResource, originDetailsResource); configure?.(state); state.load(); diff --git a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts index cb2773eefd..60f33410e5 100644 --- a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts +++ b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts @@ -10,6 +10,7 @@ import { action, makeObservable, observable } from 'mobx'; import { UserInfoResource } from '@cloudbeaver/core-authentication'; import { ConfirmationDialog, importLazyComponent } from '@cloudbeaver/core-blocks'; import { + ConnectionInfoOriginDetailsResource, ConnectionInfoOriginResource, ConnectionInfoResource, ConnectionsManagerService, @@ -50,6 +51,7 @@ export class PublicConnectionFormService { private readonly projectsService: ProjectsService, private readonly projectInfoResource: ProjectInfoResource, private readonly connectionInfoOriginResource: ConnectionInfoOriginResource, + private readonly connectionInfoOriginDetailsResource: ConnectionInfoOriginDetailsResource, ) { this.formState = null; this.optionsPanelService.closeTask.addHandler(this.closeHandler); @@ -90,6 +92,7 @@ export class PublicConnectionFormService { this.connectionFormService, this.connectionInfoResource, this.connectionInfoOriginResource, + this.connectionInfoOriginDetailsResource, ); this.formState.closeTask.addHandler(this.close.bind(this, true)); From 5f06d8e4898e2f4abc7a83c0003169b8f67bdbcb Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Mon, 23 Sep 2024 10:36:29 +0200 Subject: [PATCH 19/20] Revert "CB-4661 fixes aws/azure/gcp and other tabs in edit cloud connection" This reverts commit 4e57ce5f443e54dfdf66fcc72c8e9bd1176cf494. --- .../ConnectionInfoOriginDetailsResource.ts | 4 --- .../src/ConnectionInfoOriginResource.ts | 4 --- .../src/Search/ConnectionSearchService.ts | 3 --- .../ConnectionsTable/ConnectionEdit.tsx | 12 ++------- .../Connections/CreateConnectionService.ts | 4 +-- .../src/ConnectionForm/ConnectionFormState.ts | 13 +--------- .../ConnectionForm/IConnectionFormProps.ts | 3 +-- .../ConnectionForm/OriginInfo/OriginInfo.tsx | 26 +++++++++---------- .../ConnectionForm/useConnectionFormState.ts | 5 ++-- .../PublicConnectionFormService.ts | 3 --- 10 files changed, 20 insertions(+), 57 deletions(-) diff --git a/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts b/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts index b0cb244ca0..8ee84d6892 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts @@ -85,10 +85,6 @@ export class ConnectionInfoOriginDetailsResource extends CachedMapResource(function ConnectionEditNew({ item }) { const connectionInfoResource = useService(ConnectionInfoResource); const connectionInfoOriginResource = useService(ConnectionInfoOriginResource); - const connectionInfoOriginDetailsResource = useService(ConnectionInfoOriginDetailsResource); // const tableContext = useContext(TableContext); // const collapse = useCallback(() => tableContext?.setItemExpand(item, false), [tableContext, item]); - const data = useConnectionFormState(connectionInfoResource, connectionInfoOriginResource, connectionInfoOriginDetailsResource, state => - state.setOptions('edit', 'admin'), - ); + const data = useConnectionFormState(connectionInfoResource, connectionInfoOriginResource, state => state.setOptions('edit', 'admin')); const style = useS(styles); const projectId = item.projectId; diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts index 1296496b14..c0c00c507d 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts @@ -8,7 +8,7 @@ import { action, makeObservable, observable } from 'mobx'; import { AdministrationScreenService } from '@cloudbeaver/core-administration'; -import { ConnectionInfoOriginDetailsResource, ConnectionInfoOriginResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; +import { ConnectionInfoOriginResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; @@ -39,7 +39,6 @@ export class CreateConnectionService { private readonly projectsService: ProjectsService, private readonly projectInfoResource: ProjectInfoResource, private readonly connectionInfoOriginResource: ConnectionInfoOriginResource, - private readonly connectionInfoOriginDetailsResource: ConnectionInfoOriginDetailsResource, ) { this.data = null; this.tabsContainer = new TabsContainer('Connection Creation mode'); @@ -117,7 +116,6 @@ export class CreateConnectionService { this.connectionFormService, this.connectionInfoResource, this.connectionInfoOriginResource, - this.connectionInfoOriginDetailsResource, ); this.data.closeTask.addHandler(this.cancelCreate.bind(this)); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts index 17db5001f9..1873386ec5 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts @@ -8,7 +8,6 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { - ConnectionInfoOriginDetailsResource, ConnectionInfoOriginResource, ConnectionInfoResource, createConnectionParam, @@ -63,14 +62,6 @@ export class ConnectionFormState implements IConnectionFormState { return this.resource.get(createConnectionParam(this.projectId, this.config.connectionId)); } - get originDetails() { - if (!this.config.connectionId || this.projectId === null) { - return undefined; - } - - this.originDetailsResource.get(createConnectionParam(this.projectId, this.config.connectionId)); - } - get originInfo() { if (!this.config.connectionId || this.projectId === null) { return undefined; @@ -120,7 +111,6 @@ export class ConnectionFormState implements IConnectionFormState { service: ConnectionFormService, resource: ConnectionInfoResource, private readonly originResource: ConnectionInfoOriginResource, - private readonly originDetailsResource: ConnectionInfoOriginDetailsResource, ) { this._id = uuid(); this.initError = null; @@ -191,7 +181,6 @@ export class ConnectionFormState implements IConnectionFormState { _availableDrivers: observable, info: computed, originInfo: computed, - originDetails: computed, statusMessage: observable, configured: observable, readonly: computed, @@ -345,6 +334,6 @@ export class ConnectionFormState implements IConnectionFormState { return; } - Promise.all([data.resource.load(key, configuration.connectionIncludes), this.originResource.load(key), this.originDetailsResource.load(key)]); + await data.resource.load(key, configuration.connectionIncludes); } } diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts index 28af3f13c6..cb02bcc932 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts @@ -5,7 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import type { ConnectionInfoOrigin, ConnectionInfoOriginDetails, ConnectionInfoResource, DatabaseConnection } from '@cloudbeaver/core-connections'; +import type { ConnectionInfoOrigin, ConnectionInfoResource, DatabaseConnection } from '@cloudbeaver/core-connections'; import type { IExecutor, IExecutorHandlersCollection } from '@cloudbeaver/core-executor'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; import type { IFormStateInfo } from '@cloudbeaver/core-ui'; @@ -34,7 +34,6 @@ export interface IConnectionFormState { readonly resource: ConnectionInfoResource; readonly info: DatabaseConnection | undefined; readonly originInfo: ConnectionInfoOrigin | undefined; - readonly originDetails: ConnectionInfoOriginDetails | undefined; readonly readonly: boolean; readonly submittingTask: IExecutorHandlersCollection; readonly closeTask: IExecutor; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx index 91e9f8460b..1f959ed580 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx @@ -21,7 +21,12 @@ import { useS, useTranslate, } from '@cloudbeaver/core-blocks'; -import { createConnectionParam, DatabaseAuthModelsResource, DBDriverResource } from '@cloudbeaver/core-connections'; +import { + ConnectionInfoOriginDetailsResource, + createConnectionParam, + DatabaseAuthModelsResource, + DBDriverResource, +} from '@cloudbeaver/core-connections'; import { TabContainerPanelComponent, useTab, useTabState } from '@cloudbeaver/core-ui'; import type { IConnectionFormProps } from '../IConnectionFormProps'; @@ -29,7 +34,7 @@ import styles from './OriginInfo.module.css'; export const OriginInfo: TabContainerPanelComponent = observer(function OriginInfo({ tabId, - state: { info, resource, config, originDetails }, + state: { info, resource, config }, }) { const tab = useTab(tabId); const translate = useTranslate(); @@ -46,19 +51,14 @@ export const OriginInfo: TabContainerPanelComponent = obse const providerId = authModeLoader.data?.requiredAuth ?? info?.requiredAuth ?? AUTH_PROVIDER_LOCAL_ID; const isAuthenticated = userInfoLoader.resource.hasToken(providerId); const providerLoader = useResource(OriginInfo, AuthProvidersResource, providerId); - const connectionId = - tab.selected && info - ? createConnectionParam({ - id: info.id, - projectId: info.projectId, - }) - : null; + const connectionId = tab.selected && info ? createConnectionParam(info.projectId, info.id) : null; + const connectionOriginDetailsResource = useResource(OriginInfo, ConnectionInfoOriginDetailsResource, connectionId); const connection = useResource(OriginInfo, resource, connectionId, { active: isAuthenticated, onData: connection => { runInAction(() => { - if (!originDetails?.origin.details) { + if (!connectionOriginDetailsResource.data?.origin.details) { return; } @@ -67,7 +67,7 @@ export const OriginInfo: TabContainerPanelComponent = obse delete state[property]; } - for (const property of originDetails.origin.details) { + for (const property of connectionOriginDetailsResource.data.origin.details) { state[property.id!] = property.value; } }); @@ -102,7 +102,7 @@ export const OriginInfo: TabContainerPanelComponent = obse ); } - if (!originDetails?.origin.details || originDetails?.origin.details.length === 0) { + if (!connectionOriginDetailsResource.data?.origin.details || connectionOriginDetailsResource.data?.origin.details.length === 0) { return ( {translate('connections_administration_connection_no_information')} @@ -113,7 +113,7 @@ export const OriginInfo: TabContainerPanelComponent = obse return ( - + diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts b/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts index ad2bc7ca74..7d241a001e 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts @@ -7,7 +7,7 @@ */ import { useEffect, useState } from 'react'; -import type { ConnectionInfoOriginDetailsResource, ConnectionInfoOriginResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; +import type { ConnectionInfoOriginResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects'; @@ -18,7 +18,6 @@ import type { IConnectionFormState } from './IConnectionFormProps'; export function useConnectionFormState( resource: ConnectionInfoResource, originResource: ConnectionInfoOriginResource, - originDetailsResource: ConnectionInfoOriginDetailsResource, configure?: (state: IConnectionFormState) => any, ): IConnectionFormState { const projectsService = useService(ProjectsService); @@ -26,7 +25,7 @@ export function useConnectionFormState( const service = useService(ConnectionFormService); const [state] = useState(() => { - const state = new ConnectionFormState(projectsService, projectInfoResource, service, resource, originResource, originDetailsResource); + const state = new ConnectionFormState(projectsService, projectInfoResource, service, resource, originResource); configure?.(state); state.load(); diff --git a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts index 60f33410e5..cb2773eefd 100644 --- a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts +++ b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts @@ -10,7 +10,6 @@ import { action, makeObservable, observable } from 'mobx'; import { UserInfoResource } from '@cloudbeaver/core-authentication'; import { ConfirmationDialog, importLazyComponent } from '@cloudbeaver/core-blocks'; import { - ConnectionInfoOriginDetailsResource, ConnectionInfoOriginResource, ConnectionInfoResource, ConnectionsManagerService, @@ -51,7 +50,6 @@ export class PublicConnectionFormService { private readonly projectsService: ProjectsService, private readonly projectInfoResource: ProjectInfoResource, private readonly connectionInfoOriginResource: ConnectionInfoOriginResource, - private readonly connectionInfoOriginDetailsResource: ConnectionInfoOriginDetailsResource, ) { this.formState = null; this.optionsPanelService.closeTask.addHandler(this.closeHandler); @@ -92,7 +90,6 @@ export class PublicConnectionFormService { this.connectionFormService, this.connectionInfoResource, this.connectionInfoOriginResource, - this.connectionInfoOriginDetailsResource, ); this.formState.closeTask.addHandler(this.close.bind(this, true)); From c3d52e427d3f035faaf7046410afacf5422eecf8 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Mon, 23 Sep 2024 11:14:40 +0200 Subject: [PATCH 20/20] CB-4661 adds correct fix for origin tab --- .../src/ConnectionInfoOriginDetailsResource.ts | 4 ++++ .../core-connections/src/ConnectionInfoOriginResource.ts | 4 ++++ .../src/ConnectionForm/ConnectionFormState.ts | 5 ++++- .../src/ConnectionForm/IConnectionFormProps.ts | 3 ++- .../src/ConnectionForm/OriginInfo/OriginInfo.tsx | 4 +++- .../src/ConnectionForm/useConnectionFormState.ts | 2 +- 6 files changed, 18 insertions(+), 4 deletions(-) diff --git a/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts b/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts index 8ee84d6892..b0cb244ca0 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoOriginDetailsResource.ts @@ -85,6 +85,10 @@ export class ConnectionInfoOriginDetailsResource extends CachedMapResource; readonly closeTask: IExecutor; @@ -110,12 +111,13 @@ export class ConnectionFormState implements IConnectionFormState { private readonly projectInfoResource: ProjectInfoResource, service: ConnectionFormService, resource: ConnectionInfoResource, - private readonly originResource: ConnectionInfoOriginResource, + originResource: ConnectionInfoOriginResource, ) { this._id = uuid(); this.initError = null; this.resource = resource; + this.originResource = originResource; this.projectId = null; this.config = {}; this._availableDrivers = []; @@ -335,5 +337,6 @@ export class ConnectionFormState implements IConnectionFormState { } await data.resource.load(key, configuration.connectionIncludes); + await this.originResource.load(key); } } diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts index cb02bcc932..95993cc023 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts @@ -5,7 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import type { ConnectionInfoOrigin, ConnectionInfoResource, DatabaseConnection } from '@cloudbeaver/core-connections'; +import type { ConnectionInfoOrigin, ConnectionInfoOriginResource, ConnectionInfoResource, DatabaseConnection } from '@cloudbeaver/core-connections'; import type { IExecutor, IExecutorHandlersCollection } from '@cloudbeaver/core-executor'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; import type { IFormStateInfo } from '@cloudbeaver/core-ui'; @@ -32,6 +32,7 @@ export interface IConnectionFormState { readonly availableDrivers: string[]; readonly resource: ConnectionInfoResource; + readonly originResource: ConnectionInfoOriginResource; readonly info: DatabaseConnection | undefined; readonly originInfo: ConnectionInfoOrigin | undefined; readonly readonly: boolean; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx index 1f959ed580..ffb906e8db 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx @@ -53,7 +53,9 @@ export const OriginInfo: TabContainerPanelComponent = obse const providerLoader = useResource(OriginInfo, AuthProvidersResource, providerId); const connectionId = tab.selected && info ? createConnectionParam(info.projectId, info.id) : null; - const connectionOriginDetailsResource = useResource(OriginInfo, ConnectionInfoOriginDetailsResource, connectionId); + const connectionOriginDetailsResource = useResource(OriginInfo, ConnectionInfoOriginDetailsResource, connectionId, { + active: isAuthenticated, + }); const connection = useResource(OriginInfo, resource, connectionId, { active: isAuthenticated, onData: connection => { diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts b/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts index 7d241a001e..a8a858f980 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts @@ -7,7 +7,7 @@ */ import { useEffect, useState } from 'react'; -import type { ConnectionInfoOriginResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; +import { ConnectionInfoOriginResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects';