diff --git a/webapp/.eslintrc.cjs b/webapp/.eslintrc.cjs index e328085e23..c22fd15204 100644 --- a/webapp/.eslintrc.cjs +++ b/webapp/.eslintrc.cjs @@ -12,8 +12,6 @@ module.exports = { parserOptions: { ecmaVersion: 2019, sourceType: 'module', - tsconfigRootDir: __dirname, - project: './tsconfig.eslint.json', ecmaFeatures: { jsx: true, }, diff --git a/webapp/package.json b/webapp/package.json index f71e3d6701..82c341a523 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -27,13 +27,15 @@ "mobx-react-lite": "~3.4.2", "msw": "^1.1.0", "path-browserify": "~1.0.1", + "prettier": "^2.8.8", "react": "~18.2.0", "react-dom": "~18.2.0", "reakit": "~1.3.11", "reflect-metadata": "~0.1.13", - "reshadow": "~0.0.1", + "reshadow": "^0.0.1", "rimraf": "~4.3.1", "typescript": "4.9.5" }, - "dependencies": {} + "dependencies": {}, + "prettier": "@cloudbeaver/prettier-config" } diff --git a/webapp/packages/core-administration/src/AdministrationItem/AdministrationItemService.ts b/webapp/packages/core-administration/src/AdministrationItem/AdministrationItemService.ts index 72d7c39d6b..2ceedb9aa3 100644 --- a/webapp/packages/core-administration/src/AdministrationItem/AdministrationItemService.ts +++ b/webapp/packages/core-administration/src/AdministrationItem/AdministrationItemService.ts @@ -5,17 +5,14 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { observable, makeObservable } from 'mobx'; +import { makeObservable, observable } from 'mobx'; import { injectable } from '@cloudbeaver/core-di'; import { Executor, IExecutor, IExecutorHandler } from '@cloudbeaver/core-executor'; import type { RouterState } from '@cloudbeaver/core-routing'; import { filterConfigurationWizard } from './filterConfigurationWizard'; -import { - IAdministrationItem, IAdministrationItemOptions, IAdministrationItemSubItem, AdministrationItemType -} from './IAdministrationItem'; +import { AdministrationItemType, IAdministrationItem, IAdministrationItemOptions, IAdministrationItemSubItem } from './IAdministrationItem'; import type { IAdministrationItemRoute } from './IAdministrationItemRoute'; import { orderAdministrationItems } from './orderAdministrationItems'; @@ -49,20 +46,29 @@ export class AdministrationItemService { this.deActivationTask = new Executor(); this.activationTask - .addHandler(() => { this.itemActivating = true; }) + .addHandler(() => { + this.itemActivating = true; + }) .addHandler(this.activateHandler) - .addPostHandler(() => { this.itemActivating = false; }); + .addPostHandler(() => { + this.itemActivating = false; + }); this.deActivationTask - .addHandler(() => { this.itemDeactivating = true; }) + .addHandler(() => { + this.itemDeactivating = true; + }) .addHandler(this.deActivateHandler) - .addPostHandler(() => { this.itemDeactivating = false; }); + .addPostHandler(() => { + this.itemDeactivating = false; + }); } getUniqueItems(configurationWizard: boolean): IAdministrationItem[] { const items: IAdministrationItem[] = []; - const orderedByPriority = this.items.slice() + const orderedByPriority = this.items + .slice() .sort((a, b) => { if (a.name !== b.name) { return a.name.localeCompare(b.name); @@ -88,10 +94,9 @@ export class AdministrationItemService { } getActiveItems(configurationWizard: boolean): IAdministrationItem[] { - return this.getUniqueItems(configurationWizard).filter(item => - filterHiddenAdministrationItem(configurationWizard)(item) - && filterConfigurationWizard(configurationWizard)(item) - ).sort(orderAdministrationItems(configurationWizard)); + return this.getUniqueItems(configurationWizard) + .filter(item => filterHiddenAdministrationItem(configurationWizard)(item) && filterConfigurationWizard(configurationWizard)(item)) + .sort(orderAdministrationItems(configurationWizard)); } getDefaultItem(configurationWizard: boolean): string | null { @@ -140,11 +145,10 @@ export class AdministrationItemService { create(options: IAdministrationItemOptions): void { const type = options.type ?? AdministrationItemType.Administration; - const existedIndex = this.items.findIndex(item => item.name === options.name && ( - item.type === type - || item.type === AdministrationItemType.Default - || type === AdministrationItemType.Default - )); + const existedIndex = this.items.findIndex( + item => + item.name === options.name && (item.type === type || item.type === AdministrationItemType.Default || type === AdministrationItemType.Default), + ); if (!options.replace && existedIndex !== -1) { throw new Error(`Administration item "${options.name}" already exists in the same visibility scope`); @@ -159,21 +163,11 @@ export class AdministrationItemService { this.items.push(item); } - async activate( - screen: IAdministrationItemRoute, - configurationWizard: boolean, - outside: boolean, - outsideAdminPage: boolean - ): Promise { + async activate(screen: IAdministrationItemRoute, configurationWizard: boolean, outside: boolean, outsideAdminPage: boolean): Promise { await this.activationTask.execute({ screen, configurationWizard, outside, outsideAdminPage }); } - async deActivate( - screen: IAdministrationItemRoute, - configurationWizard: boolean, - outside: boolean, - outsideAdminPage: boolean - ): Promise { + async deActivate(screen: IAdministrationItemRoute, configurationWizard: boolean, outside: boolean, outsideAdminPage: boolean): Promise { await this.deActivationTask.execute({ screen, configurationWizard, outside, outsideAdminPage }); } @@ -181,7 +175,7 @@ export class AdministrationItemService { screen: IAdministrationItemRoute, toScreen: IAdministrationItemRoute | null, configurationWizard: boolean, - outside: boolean + outside: boolean, ): Promise { const item = this.getItem(screen.item, configurationWizard); let nextItem = null; @@ -207,11 +201,7 @@ export class AdministrationItemService { return true; } - async canActivate( - screen: IAdministrationItemRoute, - configurationWizard: boolean, - outside: boolean - ): Promise { + async canActivate(screen: IAdministrationItemRoute, configurationWizard: boolean, outside: boolean): Promise { const item = this.getItem(screen.item, configurationWizard); if (!item) { return false; @@ -231,12 +221,7 @@ export class AdministrationItemService { return true; } - private activateHandler: IExecutorHandler = async ({ - screen, - configurationWizard, - outside, - outsideAdminPage, - }) => { + private activateHandler: IExecutorHandler = async ({ screen, configurationWizard, outside, outsideAdminPage }) => { let lastItem = 0; while (true) { const items = this.getActiveItems(configurationWizard); @@ -271,12 +256,7 @@ export class AdministrationItemService { } }; - private deActivateHandler: IExecutorHandler = async ({ - screen, - configurationWizard, - outside, - outsideAdminPage, - }) => { + private deActivateHandler: IExecutorHandler = async ({ screen, configurationWizard, outside, outsideAdminPage }) => { const item = this.getItem(screen.item, configurationWizard); if (!item) { return; diff --git a/webapp/packages/core-administration/src/AdministrationItem/IAdministrationItem.ts b/webapp/packages/core-administration/src/AdministrationItem/IAdministrationItem.ts index 55a1365e7d..e8a761efc1 100644 --- a/webapp/packages/core-administration/src/AdministrationItem/IAdministrationItem.ts +++ b/webapp/packages/core-administration/src/AdministrationItem/IAdministrationItem.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { ComponentStyle } from '@cloudbeaver/core-theming'; import type { IRouteParams } from './IRouteParams'; @@ -13,7 +12,7 @@ import type { IRouteParams } from './IRouteParams'; export enum AdministrationItemType { Default, Administration, - ConfigurationWizard + ConfigurationWizard, } export interface IAdministrationItemReplaceOptions { @@ -44,29 +43,15 @@ export type AdministrationItemSubContentProps = AdministrationItemContentProps & }; export type AdministrationItemSubContentComponent = React.FunctionComponent; -export type AdministrationItemEvent = ( - configurationWizard: boolean, - outside: boolean, - outsideAdminPage: boolean -) => Promise | void; -export type AdministrationItemCanActivateEvent = ( - configurationWizard: boolean, - administration: boolean, -) => Promise | boolean; +export type AdministrationItemEvent = (configurationWizard: boolean, outside: boolean, outsideAdminPage: boolean) => Promise | void; +export type AdministrationItemCanActivateEvent = (configurationWizard: boolean, administration: boolean) => Promise | boolean; export type AdministrationItemCanDeActivateEvent = ( configurationWizard: boolean, administration: boolean, nextAdministrationItem: IAdministrationItem | null, ) => Promise | boolean; -export type AdministrationItemSubEvent = ( - param: string | null, - configurationWizard: boolean, - outside: boolean -) => Promise | void; -export type AdministrationItemSubCanActivateEvent = ( - param: string | null, - configurationWizard: boolean -) => Promise | boolean; +export type AdministrationItemSubEvent = (param: string | null, configurationWizard: boolean, outside: boolean) => Promise | void; +export type AdministrationItemSubCanActivateEvent = (param: string | null, configurationWizard: boolean) => Promise | boolean; export interface IAdministrationItemSubItem { name: string; diff --git a/webapp/packages/core-administration/src/AdministrationItem/filterConfigurationWizard.ts b/webapp/packages/core-administration/src/AdministrationItem/filterConfigurationWizard.ts index 4ea439b06d..13d5d9de3d 100644 --- a/webapp/packages/core-administration/src/AdministrationItem/filterConfigurationWizard.ts +++ b/webapp/packages/core-administration/src/AdministrationItem/filterConfigurationWizard.ts @@ -5,11 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { AdministrationItemType, IAdministrationItem } from './IAdministrationItem'; export function filterConfigurationWizard(configurationWizard: boolean) { - return (item: IAdministrationItem) => (configurationWizard - ? item.type !== AdministrationItemType.Administration - : item.type !== AdministrationItemType.ConfigurationWizard); + return (item: IAdministrationItem) => + configurationWizard ? item.type !== AdministrationItemType.Administration : item.type !== AdministrationItemType.ConfigurationWizard; } diff --git a/webapp/packages/core-administration/src/AdministrationItem/orderAdministrationItems.ts b/webapp/packages/core-administration/src/AdministrationItem/orderAdministrationItems.ts index bd333a13bb..30f1395fc2 100644 --- a/webapp/packages/core-administration/src/AdministrationItem/orderAdministrationItems.ts +++ b/webapp/packages/core-administration/src/AdministrationItem/orderAdministrationItems.ts @@ -5,17 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IAdministrationItem } from './IAdministrationItem'; export function orderAdministrationItems(configuration: boolean) { return (itemA: IAdministrationItem, itemB: IAdministrationItem): number => { if (configuration) { - return ( - itemA.configurationWizardOptions?.order ?? itemA.order - ) - ( - itemB.configurationWizardOptions?.order ?? itemB.order - ); + return (itemA.configurationWizardOptions?.order ?? itemA.order) - (itemB.configurationWizardOptions?.order ?? itemB.order); } return itemA.order - itemB.order; }; diff --git a/webapp/packages/core-administration/src/AdministrationLocaleService.ts b/webapp/packages/core-administration/src/AdministrationLocaleService.ts index d59fd0e120..eee014dcfb 100644 --- a/webapp/packages/core-administration/src/AdministrationLocaleService.ts +++ b/webapp/packages/core-administration/src/AdministrationLocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class AdministrationLocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenService.ts b/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenService.ts index abb4eb2bfe..ad505c52c6 100644 --- a/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenService.ts +++ b/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenService.ts @@ -5,15 +5,14 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { computed, observable, makeObservable } from 'mobx'; +import { computed, makeObservable, observable } from 'mobx'; import { EAdminPermission } from '@cloudbeaver/core-authentication'; import { injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; -import { IExecutor, Executor } from '@cloudbeaver/core-executor'; -import { SessionPermissionsResource, PermissionsService, ServerConfigResource } from '@cloudbeaver/core-root'; -import { ScreenService, RouterState } from '@cloudbeaver/core-routing'; +import { Executor, IExecutor } from '@cloudbeaver/core-executor'; +import { PermissionsService, ServerConfigResource, SessionPermissionsResource } from '@cloudbeaver/core-root'; +import { RouterState, ScreenService } from '@cloudbeaver/core-routing'; import { LocalStorageSaveService } from '@cloudbeaver/core-settings'; import { GlobalConstants } from '@cloudbeaver/core-utils'; @@ -73,7 +72,7 @@ export class AdministrationScreenService { private readonly administrationItemService: AdministrationItemService, private readonly autoSaveService: LocalStorageSaveService, private readonly serverConfigResource: ServerConfigResource, - private readonly notificationService: NotificationService + private readonly notificationService: NotificationService, ) { this.info = getDefaultAdministrationScreenInfo(); this.itemState = new Map(); @@ -146,27 +145,17 @@ export class AdministrationScreenService { this.getRouteName(itemName, item?.defaultSub, item?.defaultParam), itemName, item?.defaultSub, - item?.defaultParam + item?.defaultParam, ); } navigateToItemSub(item: string, sub: string, param?: string): void { - this.screenService.navigateToScreen( - this.getRouteName(item, sub, param), - item, - sub, - param - ); + this.screenService.navigateToScreen(this.getRouteName(item, sub, param), item, sub, param); } getItemState(name: string): T | undefined; getItemState(name: string, defaultState: () => T, update?: boolean, validate?: (state: T) => boolean): T; - getItemState( - name: string, - defaultState?: () => T, - update?: boolean, - validate?: (state: T) => boolean - ): T | undefined { + getItemState(name: string, defaultState?: () => T, update?: boolean, validate?: (state: T) => boolean): T | undefined { if (!this.serverConfigResource.isLoaded()) { throw new Error('Administration screen getItemState can be used only after server configuration loaded'); } @@ -193,8 +182,8 @@ export class AdministrationScreenService { isAdministrationRouteActive(routeName: string): boolean { return ( - this.screenService.isActive(routeName, AdministrationScreenService.screenName) - || this.screenService.isActive(routeName, AdministrationScreenService.setupName) + this.screenService.isActive(routeName, AdministrationScreenService.screenName) || + this.screenService.isActive(routeName, AdministrationScreenService.setupName) ); } @@ -207,16 +196,10 @@ export class AdministrationScreenService { const screen = this.getScreen(state); if (screen) { - await this.administrationItemService.deActivate( - screen, - this.isConfigurationMode, - screen.item !== toScreen?.item, - toScreen === null - ); + await this.administrationItemService.deActivate(screen, this.isConfigurationMode, screen.item !== toScreen?.item, toScreen === null); } - if (this.isConfigurationMode - && !this.screenService.isActive(nextState.name, AdministrationScreenService.setupName)) { + if (this.isConfigurationMode && !this.screenService.isActive(nextState.name, AdministrationScreenService.setupName)) { this.navigateToRoot(); } } @@ -233,12 +216,7 @@ export class AdministrationScreenService { return true; } - return this.administrationItemService.canDeActivate( - screen, - toScreen, - this.isConfigurationMode, - screen.item !== toScreen?.item - ); + return this.administrationItemService.canDeActivate(screen, toScreen, this.isConfigurationMode, screen.item !== toScreen?.item); } async handleCanActivate(toState: RouterState, fromState: RouterState): Promise { @@ -252,11 +230,7 @@ export class AdministrationScreenService { return false; } - return this.administrationItemService.canActivate( - screen, - this.isConfigurationMode, - screen.item !== fromScreen?.item - ); + return this.administrationItemService.canActivate(screen, this.isConfigurationMode, screen.item !== fromScreen?.item); } async handleActivate(state: RouterState, prevState?: RouterState): Promise { @@ -269,21 +243,16 @@ export class AdministrationScreenService { const screen = this.getScreen(state); const fromScreen = this.getScreen(prevState); if (screen) { - await this.administrationItemService.activate( - screen, - this.isConfigurationMode, - screen.item !== fromScreen?.item, - fromScreen === null - ); + await this.administrationItemService.activate(screen, this.isConfigurationMode, screen.item !== fromScreen?.item, fromScreen === null); } } private validateState() { if ( - this.info.workspaceId !== this.serverConfigResource.workspaceId - || this.info.configurationMode !== this.isConfigurationMode - || this.info.serverVersion !== this.serverConfigResource.serverVersion - || this.info.version !== GlobalConstants.version + this.info.workspaceId !== this.serverConfigResource.workspaceId || + this.info.configurationMode !== this.isConfigurationMode || + this.info.serverVersion !== this.serverConfigResource.serverVersion || + this.info.version !== GlobalConstants.version ) { this.clearItemsState(); this.info.workspaceId = this.serverConfigResource.workspaceId; diff --git a/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/ConfigurationWizardService.ts b/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/ConfigurationWizardService.ts index 35e915f822..a5925c0eb0 100644 --- a/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/ConfigurationWizardService.ts +++ b/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/ConfigurationWizardService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed, makeObservable } from 'mobx'; import { injectable } from '@cloudbeaver/core-di'; @@ -20,11 +19,9 @@ import { AdministrationScreenService } from '../AdministrationScreenService'; @injectable() export class ConfigurationWizardService { get steps(): IAdministrationItem[] { - return this.administrationItemService.getUniqueItems(true) - .filter(item => - filterConfigurationWizard(true)(item) - && filterHiddenAdministrationItem(true)(item) - ) + return this.administrationItemService + .getUniqueItems(true) + .filter(item => filterConfigurationWizard(true)(item) && filterHiddenAdministrationItem(true)(item)) .sort(orderAdministrationItems(true)); } @@ -33,9 +30,7 @@ export class ConfigurationWizardService { } get finishedSteps(): IAdministrationItem[] { - return this.steps.filter(step => ( - step.configurationWizardOptions?.isDone && step.configurationWizardOptions.isDone() - )); + return this.steps.filter(step => step.configurationWizardOptions?.isDone && step.configurationWizardOptions.isDone()); } get currentStepIndex(): number { @@ -48,8 +43,7 @@ export class ConfigurationWizardService { get canFinish(): boolean { return this.steps.every(step => { - if (step.configurationWizardOptions?.isDone - && !step.configurationWizardOptions?.isDone()) { + if (step.configurationWizardOptions?.isDone && !step.configurationWizardOptions?.isDone()) { return false; } @@ -78,7 +72,7 @@ export class ConfigurationWizardService { constructor( private administrationItemService: AdministrationItemService, private administrationScreenService: AdministrationScreenService, - private notificationService: NotificationService + private notificationService: NotificationService, ) { makeObservable(this, { steps: computed, @@ -144,10 +138,7 @@ export class ConfigurationWizardService { if (this.currentStepIndex + 1 < this.steps.length) { if (this.nextStep) { - this.administrationScreenService.navigateTo( - this.nextStep.name, - this.nextStep.configurationWizardOptions?.defaultRoute - ); + this.administrationScreenService.navigateTo(this.nextStep.name, this.nextStep.configurationWizardOptions?.defaultRoute); } } else { await this.finish(); @@ -166,8 +157,7 @@ export class ConfigurationWizardService { } private getStep(name: string) { - return this.administrationItemService.getUniqueItems(true) - .find(step => filterConfigurationWizard(true)(step) && step.name === name); + return this.administrationItemService.getUniqueItems(true).find(step => filterConfigurationWizard(true)(step) && step.name === name); } private async finish() { diff --git a/webapp/packages/core-administration/src/AdministrationSettingsService.test.ts b/webapp/packages/core-administration/src/AdministrationSettingsService.test.ts index 2bd36d74d7..1aab7c0b30 100644 --- a/webapp/packages/core-administration/src/AdministrationSettingsService.test.ts +++ b/webapp/packages/core-administration/src/AdministrationSettingsService.test.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import '@testing-library/jest-dom'; import { mockAuthentication } from '@cloudbeaver/core-authentication/mocks/mockAuthentication'; @@ -21,10 +20,7 @@ import { AdministrationSettings, AdministrationSettingsService } from './Adminis const endpoint = createGQLEndpoint(); const app = createApp(); -const server = mockGraphQL( - ...mockAppInit(endpoint), - ...mockAuthentication(endpoint) -); +const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint)); beforeAll(() => app.init()); @@ -42,11 +38,9 @@ test('Read settings', async () => { const settings = app.injector.getServiceByClass(AdministrationSettingsService); const config = app.injector.getServiceByClass(ServerConfigResource); - server.use( - endpoint.query('serverConfig', mockServerConfig(equalConfig)), - ); + server.use(endpoint.query('serverConfig', mockServerConfig(equalConfig))); await config.refresh(); expect(settings.settings.getValue('baseFeatures')).toEqual(testValue); -}); \ No newline at end of file +}); diff --git a/webapp/packages/core-administration/src/AdministrationSettingsService.ts b/webapp/packages/core-administration/src/AdministrationSettingsService.ts index c1e716dc43..bca4d49c3e 100644 --- a/webapp/packages/core-administration/src/AdministrationSettingsService.ts +++ b/webapp/packages/core-administration/src/AdministrationSettingsService.ts @@ -5,7 +5,6 @@ * 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 { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin'; diff --git a/webapp/packages/core-administration/src/AdministrationToolsPanelStyles.ts b/webapp/packages/core-administration/src/AdministrationToolsPanelStyles.ts index c2e29e4c1b..c5273d2049 100644 --- a/webapp/packages/core-administration/src/AdministrationToolsPanelStyles.ts +++ b/webapp/packages/core-administration/src/AdministrationToolsPanelStyles.ts @@ -1,4 +1,3 @@ - /* * CloudBeaver - Cloud Database Manager * Copyright (C) 2022 DBeaver Corp and others @@ -6,13 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { css } from 'reshadow'; export const ADMINISTRATION_TOOLS_PANEL_STYLES = css` - ToolsPanel { - composes: theme-background-surface theme-text-on-surface theme-border-color-background from global; - border-bottom: solid 1px; - flex: 0 0 auto; - } - `; + ToolsPanel { + composes: theme-background-surface theme-text-on-surface theme-border-color-background from global; + border-bottom: solid 1px; + flex: 0 0 auto; + } +`; diff --git a/webapp/packages/core-administration/src/PermissionsResource.ts b/webapp/packages/core-administration/src/PermissionsResource.ts index 97b9e70e7e..65aff275cc 100644 --- a/webapp/packages/core-administration/src/PermissionsResource.ts +++ b/webapp/packages/core-administration/src/PermissionsResource.ts @@ -5,23 +5,31 @@ * 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 { SessionDataResource } from '@cloudbeaver/core-root'; -import { GraphQLService, CachedMapResource, CachedMapAllKey, AdminPermissionInfoFragment, AdminObjectGrantInfoFragment, ResourceKey, resourceKeyList } from '@cloudbeaver/core-sdk'; +import { + AdminObjectGrantInfoFragment, + AdminPermissionInfoFragment, + CachedMapAllKey, + CachedMapResource, + GraphQLService, + ResourceKey, + resourceKeyList, +} from '@cloudbeaver/core-sdk'; export type PermissionInfo = AdminPermissionInfoFragment; export type AdminObjectGrantInfo = AdminObjectGrantInfoFragment; @injectable() export class PermissionsResource extends CachedMapResource { - constructor( - private readonly graphQLService: GraphQLService, - sessionDataResource: SessionDataResource - ) { + constructor(private readonly graphQLService: GraphQLService, sessionDataResource: SessionDataResource) { super(); - this.sync(sessionDataResource, () => {}, () => CachedMapAllKey); + this.sync( + sessionDataResource, + () => {}, + () => CachedMapAllKey, + ); } protected async loader(): Promise> { diff --git a/webapp/packages/core-administration/src/manifest.ts b/webapp/packages/core-administration/src/manifest.ts index 2a0398ac81..1e1bd39108 100644 --- a/webapp/packages/core-administration/src/manifest.ts +++ b/webapp/packages/core-administration/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { AdministrationItemService } from './AdministrationItem/AdministrationItemService'; @@ -15,7 +14,6 @@ import { ConfigurationWizardService } from './AdministrationScreen/Configuration import { AdministrationSettingsService } from './AdministrationSettingsService'; import { PermissionsResource } from './PermissionsResource'; - export const manifest: PluginManifest = { info: { name: 'Core Administration', diff --git a/webapp/packages/core-app/src/AppLocaleService.ts b/webapp/packages/core-app/src/AppLocaleService.ts index 3a9628a255..068bf68478 100644 --- a/webapp/packages/core-app/src/AppLocaleService.ts +++ b/webapp/packages/core-app/src/AppLocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class AppLocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/core-app/src/AppScreen/AppScreen.tsx b/webapp/packages/core-app/src/AppScreen/AppScreen.tsx index 5f7dff7430..46e6f0713a 100644 --- a/webapp/packages/core-app/src/AppScreen/AppScreen.tsx +++ b/webapp/packages/core-app/src/AppScreen/AppScreen.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { memo } from 'react'; import { Loader, Placeholder } from '@cloudbeaver/core-blocks'; diff --git a/webapp/packages/core-app/src/AppScreen/AppScreenBootstrap.ts b/webapp/packages/core-app/src/AppScreen/AppScreenBootstrap.ts index 31cbc8749d..7bf4123558 100644 --- a/webapp/packages/core-app/src/AppScreen/AppScreenBootstrap.ts +++ b/webapp/packages/core-app/src/AppScreen/AppScreenBootstrap.ts @@ -5,8 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { injectable, Bootstrap } from '@cloudbeaver/core-di'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { Executor, IExecutor } from '@cloudbeaver/core-executor'; import { ScreenService } from '@cloudbeaver/core-routing'; @@ -17,9 +16,7 @@ import { AppScreenService } from './AppScreenService'; export class AppScreenBootstrap extends Bootstrap { readonly activation: IExecutor; - constructor( - private readonly screenService: ScreenService - ) { + constructor(private readonly screenService: ScreenService) { super(); this.activation = new Executor(); } @@ -30,9 +27,11 @@ export class AppScreenBootstrap extends Bootstrap { routes: [{ name: AppScreenService.screenName, path: '/' }], component: AppScreen, root: true, - onActivate: async () => { await this.activation.execute(); }, + onActivate: async () => { + await this.activation.execute(); + }, }); } - load(): void | Promise { } + load(): void | Promise {} } diff --git a/webapp/packages/core-app/src/AppScreen/AppScreenService.ts b/webapp/packages/core-app/src/AppScreen/AppScreenService.ts index 56993eacf0..37991bc238 100644 --- a/webapp/packages/core-app/src/AppScreen/AppScreenService.ts +++ b/webapp/packages/core-app/src/AppScreen/AppScreenService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { PlaceholderContainer } from '@cloudbeaver/core-blocks'; import { injectable } from '@cloudbeaver/core-di'; diff --git a/webapp/packages/core-app/src/AppScreen/Main.tsx b/webapp/packages/core-app/src/AppScreen/Main.tsx index ca42bf4043..5f7f3dff4b 100644 --- a/webapp/packages/core-app/src/AppScreen/Main.tsx +++ b/webapp/packages/core-app/src/AppScreen/Main.tsx @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { splitStyles, Split, ResizerControls, Pane, useSplitUserState, useStyles, Loader, getComputed } from '@cloudbeaver/core-blocks'; +import { getComputed, Loader, Pane, ResizerControls, Split, splitStyles, useSplitUserState, useStyles } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { LeftBarPanelService, SideBarPanel, SideBarPanelService } from '@cloudbeaver/core-ui'; @@ -44,30 +43,20 @@ export const Main = observer(function Main() { return styled(styles)( - - + + - + - + @@ -76,6 +65,6 @@ export const Main = observer(function Main() { - + , ); }); diff --git a/webapp/packages/core-app/src/AppScreen/RightArea.tsx b/webapp/packages/core-app/src/AppScreen/RightArea.tsx index 36e39b1587..6937e68bc6 100644 --- a/webapp/packages/core-app/src/AppScreen/RightArea.tsx +++ b/webapp/packages/core-app/src/AppScreen/RightArea.tsx @@ -5,42 +5,41 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; import { + Loader, Pane, ResizerControls, SlideBox, - SlideElement, slideBoxStyles, + SlideElement, + SlideOverlay, Split, splitHorizontalStyles, splitStyles, - SlideOverlay, - useStyles, useSplitUserState, - Loader + useStyles, } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { OptionsPanelService } from '@cloudbeaver/core-ui'; import { NavigationTabsBar } from '@cloudbeaver/plugin-navigation-tabs'; -import { ToolsPanelService, ToolsPanel } from '@cloudbeaver/plugin-tools-panel'; +import { ToolsPanel, ToolsPanelService } from '@cloudbeaver/plugin-tools-panel'; const styles = css` - Pane { - composes: theme-background-surface theme-text-on-surface from global; - display: flex; - overflow: auto; - } - Loader { - height: 100%; - } - SlideBox { - flex: 1; - } - `; + Pane { + composes: theme-background-surface theme-text-on-surface from global; + display: flex; + overflow: auto; + } + Loader { + height: 100%; + } + SlideBox { + flex: 1; + } +`; interface Props { className?: string; @@ -64,21 +63,14 @@ export const RightArea = observer(function RightArea({ className }) { - + - + @@ -86,6 +78,6 @@ export const RightArea = observer(function RightArea({ className }) { optionsPanelService.close()} /> - + , ); }); diff --git a/webapp/packages/core-app/src/Body.tsx b/webapp/packages/core-app/src/Body.tsx index 19d4c317b4..a4b52dde4d 100644 --- a/webapp/packages/core-app/src/Body.tsx +++ b/webapp/packages/core-app/src/Body.tsx @@ -5,9 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { useRef, useLayoutEffect } from 'react'; +import { useLayoutEffect, useRef } from 'react'; import styled, { css } from 'reshadow'; import { Loader, useResource, useStyles } from '@cloudbeaver/core-blocks'; @@ -23,18 +22,18 @@ import { DNDProvider } from '@cloudbeaver/core-ui'; import { useAppVersion } from '@cloudbeaver/plugin-version'; const bodyStyles = css` - theme { - composes: theme-background-surface theme-text-on-surface theme-typography from global; - height: 100vh; - display: flex; - padding: 0 !important; /* fix additional padding with modal reakit menu */ - flex-direction: column; - overflow: hidden; - } - Loader { - height: 100vh; - } - `; + theme { + composes: theme-background-surface theme-text-on-surface theme-typography from global; + height: 100vh; + display: flex; + padding: 0 !important; /* fix additional padding with modal reakit menu */ + flex-direction: column; + overflow: hidden; + } + Loader { + height: 100vh; + } +`; export const Body = observer(function Body() { // const serverConfigLoader = useResource(Body, ServerConfigResource, undefined); @@ -61,13 +60,11 @@ export const Body = observer(function Body() { - - {Screen && } - + {Screen && } - + , ); }); diff --git a/webapp/packages/core-app/src/CoreSettingsService.ts b/webapp/packages/core-app/src/CoreSettingsService.ts index 53333b5db8..244591f2c5 100644 --- a/webapp/packages/core-app/src/CoreSettingsService.ts +++ b/webapp/packages/core-app/src/CoreSettingsService.ts @@ -5,7 +5,6 @@ * 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 { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin'; diff --git a/webapp/packages/core-app/src/index.ts b/webapp/packages/core-app/src/index.ts index f27293437d..234d80e3fb 100644 --- a/webapp/packages/core-app/src/index.ts +++ b/webapp/packages/core-app/src/index.ts @@ -9,4 +9,4 @@ export * from './AppLocaleService'; export * from './Body'; // Interfaces -export * from './manifest'; \ No newline at end of file +export * from './manifest'; diff --git a/webapp/packages/core-app/src/locales/en.ts b/webapp/packages/core-app/src/locales/en.ts index 82928d3791..fd517fa08b 100644 --- a/webapp/packages/core-app/src/locales/en.ts +++ b/webapp/packages/core-app/src/locales/en.ts @@ -5,10 +5,7 @@ export default [ ['app_shared_inlineEditor_dialog_title', 'Edit mode'], ['app_shared_inlineEditor_dialog_apply', 'Apply'], ['app_shared_inlineEditor_dialog_cancel', 'Cancel'], - [ - 'app_shared_navigationTabsBar_placeholder', - 'There are no objects to show. Double click on an object in the navigation tree to open it.', - ], + ['app_shared_navigationTabsBar_placeholder', 'There are no objects to show. Double click on an object in the navigation tree to open it.'], ['app_shared_sql_generators_panel_title', 'Generate SQL'], ['app_shared_sql_generators_dialog_title', 'Generated SQL'], ]; diff --git a/webapp/packages/core-app/src/locales/it.ts b/webapp/packages/core-app/src/locales/it.ts index baebf7d32f..00964e5d75 100644 --- a/webapp/packages/core-app/src/locales/it.ts +++ b/webapp/packages/core-app/src/locales/it.ts @@ -5,8 +5,5 @@ export default [ ['app_shared_inlineEditor_dialog_title', 'Modalità modifica'], ['app_shared_inlineEditor_dialog_apply', 'Applica'], ['app_shared_inlineEditor_dialog_cancel', 'Cancella'], - [ - 'app_shared_navigationTabsBar_placeholder', - 'Non ci sono oggetti da mostrare. Fai doppio click su un oggetto per aprirlo.', - ], + ['app_shared_navigationTabsBar_placeholder', 'Non ci sono oggetti da mostrare. Fai doppio click su un oggetto per aprirlo.'], ]; diff --git a/webapp/packages/core-app/src/locales/zh.ts b/webapp/packages/core-app/src/locales/zh.ts index a7e323732d..d66e8f7d82 100644 --- a/webapp/packages/core-app/src/locales/zh.ts +++ b/webapp/packages/core-app/src/locales/zh.ts @@ -5,10 +5,7 @@ export default [ ['app_shared_inlineEditor_dialog_title', '编辑模式'], ['app_shared_inlineEditor_dialog_apply', '应用'], ['app_shared_inlineEditor_dialog_cancel', '取消'], - [ - 'app_shared_navigationTabsBar_placeholder', - '没有要显示的对象。双击导航树中的对象将其打开。', - ], + ['app_shared_navigationTabsBar_placeholder', '没有要显示的对象。双击导航树中的对象将其打开。'], ['app_shared_sql_generators_panel_title', '生成SQL'], ['app_shared_sql_generators_dialog_title', '生成的SQL'], ]; diff --git a/webapp/packages/core-app/src/manifest.ts b/webapp/packages/core-app/src/manifest.ts index d8f154e278..5c8b4de424 100644 --- a/webapp/packages/core-app/src/manifest.ts +++ b/webapp/packages/core-app/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { AppLocaleService } from './AppLocaleService'; @@ -13,16 +12,10 @@ import { AppScreenBootstrap } from './AppScreen/AppScreenBootstrap'; import { AppScreenService } from './AppScreen/AppScreenService'; import { CoreSettingsService } from './CoreSettingsService'; - export const coreAppManifest: PluginManifest = { info: { name: 'Core App', }, - providers: [ - AppScreenService, - AppScreenBootstrap, - CoreSettingsService, - AppLocaleService, - ], + providers: [AppScreenService, AppScreenBootstrap, CoreSettingsService, AppLocaleService], }; diff --git a/webapp/packages/core-authentication/mocks/mockAuthentication.ts b/webapp/packages/core-authentication/mocks/mockAuthentication.ts index 2d8d8dba20..0c71cdefa6 100644 --- a/webapp/packages/core-authentication/mocks/mockAuthentication.ts +++ b/webapp/packages/core-authentication/mocks/mockAuthentication.ts @@ -5,13 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { graphql } from 'msw'; import { mockGetActiveUser } from './resolvers/mockGetActiveUser'; export function mockAuthentication(endpoint: ReturnType) { - return [ - endpoint.query('getActiveUser', mockGetActiveUser), - ]; -} \ No newline at end of file + return [endpoint.query('getActiveUser', mockGetActiveUser)]; +} diff --git a/webapp/packages/core-authentication/mocks/resolvers/mockGetActiveUser.ts b/webapp/packages/core-authentication/mocks/resolvers/mockGetActiveUser.ts index ac9602848b..04b2afa69e 100644 --- a/webapp/packages/core-authentication/mocks/resolvers/mockGetActiveUser.ts +++ b/webapp/packages/core-authentication/mocks/resolvers/mockGetActiveUser.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { GraphQLContext, GraphQLRequest, ResponseComposition } from 'msw'; import type { GetActiveUserQuery, GetActiveUserQueryVariables } from '@cloudbeaver/core-sdk'; @@ -13,11 +12,11 @@ import type { GetActiveUserQuery, GetActiveUserQueryVariables } from '@cloudbeav export function mockGetActiveUser( req: GraphQLRequest, res: ResponseComposition, - ctx: GraphQLContext + ctx: GraphQLContext, ) { return res( ctx.data({ - 'user': null as unknown as undefined, + user: null as unknown as undefined, }), ); } diff --git a/webapp/packages/core-authentication/src/AppAuthService.ts b/webapp/packages/core-authentication/src/AppAuthService.ts index 8373e5b7b9..8c46114bed 100644 --- a/webapp/packages/core-authentication/src/AppAuthService.ts +++ b/webapp/packages/core-authentication/src/AppAuthService.ts @@ -5,8 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { injectable, Bootstrap } from '@cloudbeaver/core-di'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { Executor, ExecutorInterrupter, IExecutor } from '@cloudbeaver/core-executor'; import { ServerConfigResource } from '@cloudbeaver/core-root'; import { CachedDataResourceKey, CachedResource, getCachedDataResourceLoaderState } from '@cloudbeaver/core-sdk'; @@ -19,11 +18,7 @@ export class AppAuthService extends Bootstrap { get authenticated(): boolean { const user = this.userInfoResource.data; - return ( - this.serverConfigResource.anonymousAccessEnabled - || this.serverConfigResource.configurationMode - || user !== null - ); + return this.serverConfigResource.anonymousAccessEnabled || this.serverConfigResource.configurationMode || user !== null; } get loaders(): ILoadableState[] { @@ -35,10 +30,7 @@ export class AppAuthService extends Bootstrap { readonly auth: IExecutor; - constructor( - private readonly serverConfigResource: ServerConfigResource, - private readonly userInfoResource: UserInfoResource, - ) { + constructor(private readonly serverConfigResource: ServerConfigResource, private readonly userInfoResource: UserInfoResource) { super(); this.auth = new Executor(); this.userInfoResource.onDataUpdate.addHandler(this.authUser.bind(this)); @@ -46,7 +38,7 @@ export class AppAuthService extends Bootstrap { requireAuthentication>( resource: CachedResource, - map?: (param: T | undefined) => T + map?: (param: T | undefined) => T, ): this { resource .preloadResource(this.userInfoResource, () => {}) @@ -61,14 +53,12 @@ export class AppAuthService extends Bootstrap { async isAuthNeeded(): Promise { const config = await this.serverConfigResource.load(); if (!config) { - throw new Error('Can\'t configure Authentication'); + throw new Error("Can't configure Authentication"); } const user = await this.userInfoResource.load(); - return !this.serverConfigResource.configurationMode - && !this.serverConfigResource.anonymousAccessEnabled - && user === null; + return !this.serverConfigResource.configurationMode && !this.serverConfigResource.anonymousAccessEnabled && user === null; } async authUser(): Promise { @@ -79,7 +69,7 @@ export class AppAuthService extends Bootstrap { return state; } - register(): void { } + register(): void {} - load(): void { } + load(): void {} } diff --git a/webapp/packages/core-authentication/src/AuthConfigurationParametersResource.ts b/webapp/packages/core-authentication/src/AuthConfigurationParametersResource.ts index d715a8194d..c495cd2688 100644 --- a/webapp/packages/core-authentication/src/AuthConfigurationParametersResource.ts +++ b/webapp/packages/core-authentication/src/AuthConfigurationParametersResource.ts @@ -5,20 +5,26 @@ * 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 { SessionPermissionsResource, SessionDataResource } from '@cloudbeaver/core-root'; -import { AuthProviderConfigurationParametersFragment, CachedMapResource, GetAuthProviderConfigurationParametersQueryVariables, GraphQLService, isResourceAlias, ResourceKey, ResourceKeyUtils } from '@cloudbeaver/core-sdk'; +import { SessionDataResource, SessionPermissionsResource } from '@cloudbeaver/core-root'; +import { + AuthProviderConfigurationParametersFragment, + CachedMapResource, + GetAuthProviderConfigurationParametersQueryVariables, + GraphQLService, + isResourceAlias, + ResourceKey, + ResourceKeyUtils, +} from '@cloudbeaver/core-sdk'; import { EAdminPermission } from './EAdminPermission'; @injectable() -export class AuthConfigurationParametersResource - extends CachedMapResource< +export class AuthConfigurationParametersResource extends CachedMapResource< string, AuthProviderConfigurationParametersFragment[], GetAuthProviderConfigurationParametersQueryVariables - > { +> { constructor( private readonly graphQLService: GraphQLService, private readonly sessionDataResource: SessionDataResource, @@ -30,9 +36,7 @@ export class AuthConfigurationParametersResource permissionsResource.require(this, EAdminPermission.admin); } - protected async loader( - key: ResourceKey - ): Promise> { + protected async loader(key: ResourceKey): Promise> { if (isResourceAlias(key)) { throw new Error('Aliases not supported by this resource.'); } diff --git a/webapp/packages/core-authentication/src/AuthConfigurationsResource.ts b/webapp/packages/core-authentication/src/AuthConfigurationsResource.ts index 24622e6774..92bc6f7538 100644 --- a/webapp/packages/core-authentication/src/AuthConfigurationsResource.ts +++ b/webapp/packages/core-authentication/src/AuthConfigurationsResource.ts @@ -5,12 +5,23 @@ * 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 { SessionPermissionsResource } from '@cloudbeaver/core-root'; -import { AdminAuthProviderConfiguration, CachedMapAllKey, CachedMapResource, GetAuthProviderConfigurationsQueryVariables, GraphQLService, isResourceAlias, ResourceKey, ResourceKeyList, resourceKeyList, ResourceKeySimple, ResourceKeyUtils } from '@cloudbeaver/core-sdk'; +import { + AdminAuthProviderConfiguration, + CachedMapAllKey, + CachedMapResource, + GetAuthProviderConfigurationsQueryVariables, + GraphQLService, + isResourceAlias, + ResourceKey, + ResourceKeyList, + resourceKeyList, + ResourceKeySimple, + ResourceKeyUtils, +} from '@cloudbeaver/core-sdk'; import type { AuthProviderConfiguration } from './AuthProvidersResource'; import { EAdminPermission } from './EAdminPermission'; @@ -22,17 +33,11 @@ export type AuthConfiguration = AdminAuthProviderConfiguration; type NewConfiguration = AuthConfiguration & { [NEW_CONFIGURATION_SYMBOL]: boolean; timestamp: number }; @injectable() -export class AuthConfigurationsResource - extends CachedMapResource { - constructor( - private readonly graphQLService: GraphQLService, - permissionsResource: SessionPermissionsResource, - ) { +export class AuthConfigurationsResource extends CachedMapResource { + constructor(private readonly graphQLService: GraphQLService, permissionsResource: SessionPermissionsResource) { super(() => new Map(), []); - permissionsResource - .require(this, EAdminPermission.admin) - .outdateResource(this); + permissionsResource.require(this, EAdminPermission.admin).outdateResource(this); } async saveConfiguration(config: AuthConfiguration): Promise { @@ -111,15 +116,11 @@ export class AuthConfigurationsResource } } -function isNewConfiguration( - configuration: AuthConfiguration | NewConfiguration -): configuration is NewConfiguration { +function isNewConfiguration(configuration: AuthConfiguration | NewConfiguration): configuration is NewConfiguration { return (configuration as NewConfiguration)[NEW_CONFIGURATION_SYMBOL]; } -export function compareAuthConfigurations( - a: AuthConfiguration, b: AuthConfiguration -): number { +export function compareAuthConfigurations(a: AuthConfiguration, b: AuthConfiguration): number { if (isNewConfiguration(a) && isNewConfiguration(b)) { return b.timestamp - a.timestamp; } diff --git a/webapp/packages/core-authentication/src/AuthInfoService.ts b/webapp/packages/core-authentication/src/AuthInfoService.ts index bbf9566b86..cec031c28c 100644 --- a/webapp/packages/core-authentication/src/AuthInfoService.ts +++ b/webapp/packages/core-authentication/src/AuthInfoService.ts @@ -5,14 +5,13 @@ * 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 { type ITask, AutoRunningTask } from '@cloudbeaver/core-executor'; +import { AutoRunningTask, type ITask } from '@cloudbeaver/core-executor'; import { WindowsService } from '@cloudbeaver/core-routing'; import { AuthInfo, AuthStatus, UserInfo } from '@cloudbeaver/core-sdk'; import { uuid } from '@cloudbeaver/core-utils'; -import { AuthProvidersResource, AuthProviderConfiguration } from './AuthProvidersResource'; +import { AuthProviderConfiguration, AuthProvidersResource } from './AuthProvidersResource'; import { type ILoginOptions, UserInfoResource } from './UserInfoResource'; export interface IUserAuthConfiguration { @@ -36,14 +35,10 @@ export class AuthInfoService { for (const token of tokens) { if (token.authConfiguration) { - const provider = this.authProvidersResource.values.find( - provider => provider.id === token.authProvider - ); + const provider = this.authProvidersResource.values.find(provider => provider.id === token.authProvider); if (provider) { - const configuration = provider.configurations?.find( - configuration => configuration.id === token.authConfiguration - ); + const configuration = provider.configurations?.find(configuration => configuration.id === token.authConfiguration); if (configuration) { result.push({ providerId: provider.id, configuration }); @@ -58,13 +53,13 @@ export class AuthInfoService { constructor( private readonly userInfoResource: UserInfoResource, private readonly authProvidersResource: AuthProvidersResource, - private readonly windowsService: WindowsService - ) { - } + private readonly windowsService: WindowsService, + ) {} login(providerId: string, options: ILoginOptions): ITask { - return new AutoRunningTask(async () => await this.userInfoResource.login(providerId, options)) - .then(authInfo => this.federatedAuthentication(providerId, options, authInfo)); + return new AutoRunningTask(async () => await this.userInfoResource.login(providerId, options)).then(authInfo => + this.federatedAuthentication(providerId, options, authInfo), + ); } async logout(): Promise { @@ -74,7 +69,7 @@ export class AuthInfoService { private federatedAuthentication( providerId: string, options: ILoginOptions, - { redirectLink, authId, authStatus }: AuthInfo + { redirectLink, authId, authStatus }: AuthInfo, ): ITask { let window: Window | null = null; let id = providerId; @@ -101,16 +96,19 @@ export class AuthInfoService { } } - return new AutoRunningTask(() => { - if (authId && authStatus === AuthStatus.InProgress) { - return this.userInfoResource.finishFederatedAuthentication(authId, options.linkUser); - } + return new AutoRunningTask( + () => { + if (authId && authStatus === AuthStatus.InProgress) { + return this.userInfoResource.finishFederatedAuthentication(authId, options.linkUser); + } - return AutoRunningTask.resolve(this.userInfoResource.data); - }, () => { - if (window) { - this.windowsService.close(window); - } - }); + return AutoRunningTask.resolve(this.userInfoResource.data); + }, + () => { + if (window) { + this.windowsService.close(window); + } + }, + ); } } diff --git a/webapp/packages/core-authentication/src/AuthProviderService.ts b/webapp/packages/core-authentication/src/AuthProviderService.ts index 4baaeb86f6..a16d17d450 100644 --- a/webapp/packages/core-authentication/src/AuthProviderService.ts +++ b/webapp/packages/core-authentication/src/AuthProviderService.ts @@ -5,7 +5,6 @@ * 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 { Executor, IExecutor } from '@cloudbeaver/core-executor'; import { md5, uuid } from '@cloudbeaver/core-utils'; @@ -39,9 +38,7 @@ export class AuthProviderService { private readonly serviceDescriptionLinker: IServiceDescriptionLink[]; // TODO: probably should be replaced by PlaceholderContainer - constructor( - private readonly authProvidersResource: AuthProvidersResource - ) { + constructor(private readonly authProvidersResource: AuthProvidersResource) { this.requestAuthProvider = new Executor(); this.serviceDescriptionLinker = []; } diff --git a/webapp/packages/core-authentication/src/AuthProvidersResource.ts b/webapp/packages/core-authentication/src/AuthProvidersResource.ts index 6edef333e1..7213aaada3 100644 --- a/webapp/packages/core-authentication/src/AuthProvidersResource.ts +++ b/webapp/packages/core-authentication/src/AuthProvidersResource.ts @@ -5,12 +5,21 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed, makeObservable, runInAction } from 'mobx'; import { injectable } from '@cloudbeaver/core-di'; import { ServerConfigResource } from '@cloudbeaver/core-root'; -import { GraphQLService, CachedMapResource, ResourceKey, resourceKeyList, ResourceKeyUtils, CachedMapAllKey, AuthProviderInfoFragment, AuthProviderConfigurationInfoFragment, ResourceKeySimple } from '@cloudbeaver/core-sdk'; +import { + AuthProviderConfigurationInfoFragment, + AuthProviderInfoFragment, + CachedMapAllKey, + CachedMapResource, + GraphQLService, + ResourceKey, + resourceKeyList, + ResourceKeySimple, + ResourceKeyUtils, +} from '@cloudbeaver/core-sdk'; import { AuthConfigurationsResource } from './AuthConfigurationsResource'; import { AuthSettingsService } from './AuthSettingsService'; @@ -28,11 +37,15 @@ export class AuthProvidersResource extends CachedMapResource {}, () => CachedMapAllKey); + this.sync( + serverConfigResource, + () => {}, + () => CachedMapAllKey, + ); this.authConfigurationsResource.onItemUpdate.addHandler(this.updateConfigurations.bind(this)); this.authConfigurationsResource.onItemDelete.addHandler(this.deleteConfigurations.bind(this)); @@ -42,7 +55,7 @@ export class AuthProvidersResource extends CachedMapResource) { const configurations = this.authConfigurationsResource.get(ResourceKeyUtils.toList(key)); - const providerIds = resourceKeyList( - configurations.filter(Boolean).map(configuration => configuration!.providerId) - ); + const providerIds = resourceKeyList(configurations.filter(Boolean).map(configuration => configuration!.providerId)); this.markOutdated(providerIds); } diff --git a/webapp/packages/core-authentication/src/AuthRolesResource.ts b/webapp/packages/core-authentication/src/AuthRolesResource.ts index c7ca994fdd..d48feab975 100644 --- a/webapp/packages/core-authentication/src/AuthRolesResource.ts +++ b/webapp/packages/core-authentication/src/AuthRolesResource.ts @@ -5,7 +5,6 @@ * 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 { SessionPermissionsResource } from '@cloudbeaver/core-root'; import { CachedDataResource, GraphQLService } from '@cloudbeaver/core-sdk'; @@ -14,15 +13,10 @@ import { EAdminPermission } from './EAdminPermission'; @injectable() export class AuthRolesResource extends CachedDataResource { - constructor( - private readonly graphQLService: GraphQLService, - sessionPermissionsResource: SessionPermissionsResource - ) { + constructor(private readonly graphQLService: GraphQLService, sessionPermissionsResource: SessionPermissionsResource) { super(() => []); - sessionPermissionsResource - .require(this, EAdminPermission.admin) - .outdateResource(this); + sessionPermissionsResource.require(this, EAdminPermission.admin).outdateResource(this); } protected async loader(): Promise { diff --git a/webapp/packages/core-authentication/src/AuthSettingsService.test.ts b/webapp/packages/core-authentication/src/AuthSettingsService.test.ts index d4d2cb296b..42186566ce 100644 --- a/webapp/packages/core-authentication/src/AuthSettingsService.test.ts +++ b/webapp/packages/core-authentication/src/AuthSettingsService.test.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import '@testing-library/jest-dom'; import { mockAuthentication } from '@cloudbeaver/core-authentication/mocks/mockAuthentication'; @@ -21,10 +20,7 @@ import { AuthSettings, AuthSettingsService } from './AuthSettingsService'; const endpoint = createGQLEndpoint(); const app = createApp(); -const server = mockGraphQL( - ...mockAppInit(endpoint), - ...mockAuthentication(endpoint) -); +const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint)); beforeAll(() => app.init()); @@ -42,13 +38,11 @@ test('Read settings', async () => { const settings = app.injector.getServiceByClass(AuthSettingsService); const config = app.injector.getServiceByClass(ServerConfigResource); - server.use( - endpoint.query('serverConfig', mockServerConfig(equalConfig)), - ); + server.use(endpoint.query('serverConfig', mockServerConfig(equalConfig))); await config.refresh(); expect(settings.settings.getValue('baseAuthProvider')).toBe('sd'); expect(settings.settings.getValue('primaryAuthProvider')).toBe('sd'); expect(settings.settings.getValue('disableAnonymousAccess')).toBe(true); -}); \ No newline at end of file +}); diff --git a/webapp/packages/core-authentication/src/AuthSettingsService.ts b/webapp/packages/core-authentication/src/AuthSettingsService.ts index 7d16d8fe8e..f18a8d8e27 100644 --- a/webapp/packages/core-authentication/src/AuthSettingsService.ts +++ b/webapp/packages/core-authentication/src/AuthSettingsService.ts @@ -5,7 +5,6 @@ * 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 { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin'; diff --git a/webapp/packages/core-authentication/src/DATA_CONTEXT_USER.ts b/webapp/packages/core-authentication/src/DATA_CONTEXT_USER.ts index 4f3009ec83..c37f85296d 100644 --- a/webapp/packages/core-authentication/src/DATA_CONTEXT_USER.ts +++ b/webapp/packages/core-authentication/src/DATA_CONTEXT_USER.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { UserInfo } from '@cloudbeaver/core-sdk'; import { createDataContext } from '@cloudbeaver/core-view'; diff --git a/webapp/packages/core-authentication/src/EAdminPermission.ts b/webapp/packages/core-authentication/src/EAdminPermission.ts index 332d7a0c91..bc7a4439b8 100644 --- a/webapp/packages/core-authentication/src/EAdminPermission.ts +++ b/webapp/packages/core-authentication/src/EAdminPermission.ts @@ -7,5 +7,5 @@ */ export enum EAdminPermission { - admin = 'admin' + admin = 'admin', } diff --git a/webapp/packages/core-authentication/src/ELMRole.ts b/webapp/packages/core-authentication/src/ELMRole.ts index 4d399f24c3..6a57db2501 100644 --- a/webapp/packages/core-authentication/src/ELMRole.ts +++ b/webapp/packages/core-authentication/src/ELMRole.ts @@ -12,4 +12,4 @@ export enum ELMRole { DATA_MANAGER = 'DATA_MANAGER', EDITOR = 'EDITOR', VIEWER = 'VIEWER', -} \ No newline at end of file +} diff --git a/webapp/packages/core-authentication/src/TeamMetaParametersResource.ts b/webapp/packages/core-authentication/src/TeamMetaParametersResource.ts index 930399e152..3079c0b470 100644 --- a/webapp/packages/core-authentication/src/TeamMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/TeamMetaParametersResource.ts @@ -5,7 +5,6 @@ * 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 { SessionResource } from '@cloudbeaver/core-root'; import { CachedDataResource, GraphQLService, ObjectPropertyInfo } from '@cloudbeaver/core-sdk'; @@ -14,13 +13,14 @@ export type TeamMetaParameter = ObjectPropertyInfo; @injectable() export class TeamMetaParametersResource extends CachedDataResource { - constructor( - private readonly graphQLService: GraphQLService, - sessionResource: SessionResource, - ) { + constructor(private readonly graphQLService: GraphQLService, sessionResource: SessionResource) { super(() => []); - this.sync(sessionResource, () => { }, () => { }); + this.sync( + sessionResource, + () => {}, + () => {}, + ); } protected async loader(): Promise { diff --git a/webapp/packages/core-authentication/src/TeamsManagerService.ts b/webapp/packages/core-authentication/src/TeamsManagerService.ts index 09cad9aed3..906ac725ba 100644 --- a/webapp/packages/core-authentication/src/TeamsManagerService.ts +++ b/webapp/packages/core-authentication/src/TeamsManagerService.ts @@ -5,15 +5,11 @@ * 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 { TeamsResource } from './TeamsResource'; @injectable() export class TeamsManagerService { - constructor( - readonly teams: TeamsResource - ) { - } + constructor(readonly teams: TeamsResource) {} } diff --git a/webapp/packages/core-authentication/src/TeamsResource.ts b/webapp/packages/core-authentication/src/TeamsResource.ts index c45b4b2720..2674b0b0cd 100644 --- a/webapp/packages/core-authentication/src/TeamsResource.ts +++ b/webapp/packages/core-authentication/src/TeamsResource.ts @@ -5,9 +5,20 @@ * 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 { GraphQLService, CachedMapResource, ResourceKey, ResourceKeyUtils, AdminTeamInfoFragment, AdminConnectionGrantInfo, CachedMapAllKey, GetTeamsListQueryVariables, ResourceKeySimple, resourceKeyList, isResourceAlias } from '@cloudbeaver/core-sdk'; +import { + AdminConnectionGrantInfo, + AdminTeamInfoFragment, + CachedMapAllKey, + CachedMapResource, + GetTeamsListQueryVariables, + GraphQLService, + isResourceAlias, + ResourceKey, + resourceKeyList, + ResourceKeySimple, + ResourceKeyUtils, +} from '@cloudbeaver/core-sdk'; import { isArraysEqual } from '@cloudbeaver/core-utils'; const NEW_TEAM_SYMBOL = Symbol('new-team'); @@ -23,13 +34,7 @@ export class TeamsResource extends CachedMapResource { + async createTeam({ teamId, teamPermissions, teamName, description, metaParameters }: TeamInfo): Promise { const response = await this.graphQLService.sdk.createTeam({ teamId, teamName, @@ -52,13 +57,7 @@ export class TeamsResource extends CachedMapResource { + async updateTeam({ teamId, teamPermissions, teamName, description, metaParameters }: TeamInfo): Promise { const { team } = await this.graphQLService.sdk.updateTeam({ teamId, teamName, @@ -105,9 +104,7 @@ export class TeamsResource extends CachedMapResource permission.id); @@ -121,10 +118,7 @@ export class TeamsResource extends CachedMapResource, - includes?: string[] - ): Promise> { + protected async loader(originalKey: ResourceKey, includes?: string[]): Promise> { const all = this.isAlias(originalKey, CachedMapAllKey); const teamsList: TeamInfo[] = []; diff --git a/webapp/packages/core-authentication/src/UserConfigurationBootstrap.ts b/webapp/packages/core-authentication/src/UserConfigurationBootstrap.ts index fae7d12ce1..46c9edd192 100644 --- a/webapp/packages/core-authentication/src/UserConfigurationBootstrap.ts +++ b/webapp/packages/core-authentication/src/UserConfigurationBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; import { SessionResource } from '@cloudbeaver/core-root'; @@ -18,12 +17,11 @@ const USER_APP_LANGUAGE = 'app.language'; @injectable() export class UserConfigurationBootstrap extends Bootstrap { - constructor( private readonly userInfoResource: UserInfoResource, private readonly themeService: ThemeService, private readonly localizationService: LocalizationService, - private readonly sessionResource: SessionResource + private readonly sessionResource: SessionResource, ) { super(); this.userInfoResource.onDataUpdate.addHandler(() => { @@ -58,10 +56,9 @@ export class UserConfigurationBootstrap extends Bootstrap { }); } - register(): void { } + register(): void {} async load(): Promise { await this.userInfoResource.load(); } - -} \ No newline at end of file +} diff --git a/webapp/packages/core-authentication/src/UserDataService.ts b/webapp/packages/core-authentication/src/UserDataService.ts index 5945a8c7a7..a6d3e08820 100644 --- a/webapp/packages/core-authentication/src/UserDataService.ts +++ b/webapp/packages/core-authentication/src/UserDataService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { makeObservable, observable } from 'mobx'; import { injectable } from '@cloudbeaver/core-di'; @@ -19,10 +18,7 @@ export class UserDataService { private readonly userData: Map>; private readonly tempData: TempMap>; - constructor( - private readonly userInfoResource: UserInfoResource, - private readonly autoSaveService: LocalStorageSaveService, - ) { + constructor(private readonly userInfoResource: UserInfoResource, private readonly autoSaveService: LocalStorageSaveService) { this.userData = new Map(); makeObservable(this, { @@ -31,11 +27,7 @@ export class UserDataService { this.tempData = new TempMap(this.userData); - this.autoSaveService.withAutoSave( - 'user_data', - this.userData, - () => new Map() - ); + this.autoSaveService.withAutoSave('user_data', this.userData, () => new Map()); } getUserData>(key: string, defaultValue: () => T, validate?: (data: T) => boolean): T { @@ -47,10 +39,7 @@ export class UserDataService { const data = this.tempData.get(userId)!; - if ( - !(key in data) - || validate?.(data[key]) === false - ) { + if (!(key in data) || validate?.(data[key]) === false) { data[key] = observable(defaultValue()); } diff --git a/webapp/packages/core-authentication/src/UserInfoResource.ts b/webapp/packages/core-authentication/src/UserInfoResource.ts index 93995283e0..aaa8ffcd7c 100644 --- a/webapp/packages/core-authentication/src/UserInfoResource.ts +++ b/webapp/packages/core-authentication/src/UserInfoResource.ts @@ -5,13 +5,22 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed, makeObservable, runInAction } from 'mobx'; import { injectable } from '@cloudbeaver/core-di'; -import { SyncExecutor, ISyncExecutor, ITask, AutoRunningTask, whileTask } from '@cloudbeaver/core-executor'; +import { AutoRunningTask, ISyncExecutor, ITask, SyncExecutor, whileTask } from '@cloudbeaver/core-executor'; import { SessionDataResource, SessionResource } from '@cloudbeaver/core-root'; -import { AuthInfo, AuthStatus, CachedDataResource, GetActiveUserQueryVariables, GraphQLService, ResourceKeySimple, ResourceKeyUtils, UserAuthToken, UserInfo } from '@cloudbeaver/core-sdk'; +import { + AuthInfo, + AuthStatus, + CachedDataResource, + GetActiveUserQueryVariables, + GraphQLService, + ResourceKeySimple, + ResourceKeyUtils, + UserAuthToken, + UserInfo, +} from '@cloudbeaver/core-sdk'; import { AUTH_PROVIDER_LOCAL_ID } from './AUTH_PROVIDER_LOCAL_ID'; import { AuthProviderService } from './AuthProviderService'; @@ -27,11 +36,7 @@ export interface ILoginOptions { } @injectable() -export class UserInfoResource extends CachedDataResource< -UserInfo | null, -void, -UserInfoIncludes -> { +export class UserInfoResource extends CachedDataResource { readonly onUserChange: ISyncExecutor; get authRole(): ELMRole | undefined { @@ -46,13 +51,17 @@ UserInfoIncludes private readonly graphQLService: GraphQLService, private readonly authProviderService: AuthProviderService, private readonly sessionResource: SessionResource, - private readonly sessionDataResource: SessionDataResource + private readonly sessionDataResource: SessionDataResource, ) { super(() => null, undefined, ['customIncludeOriginDetails', 'includeConfigurationParameters']); this.onUserChange = new SyncExecutor(); - this.sync(sessionResource, () => {}, () => {}); + this.sync( + sessionResource, + () => {}, + () => {}, + ); makeObservable(this, { parametersAvailable: computed, @@ -77,15 +86,10 @@ UserInfoIncludes } // TODO: will be changed due wrong origin in authTokens - return ( - this.data.authTokens.some(token => token.authProvider === providerId) - ); + return this.data.authTokens.some(token => token.authProvider === providerId); } - async login( - provider: string, - { credentials, configurationId, linkUser }: ILoginOptions - ): Promise { + async login(provider: string, { credentials, configurationId, linkUser }: ILoginOptions): Promise { let processedCredentials: Record | undefined; if (credentials) { @@ -106,7 +110,7 @@ UserInfoIncludes this.resetIncludes(); this.markOutdated(); } else { - this.data.authTokens.push(...authInfo.userTokens as UserAuthToken[]); + this.data.authTokens.push(...(authInfo.userTokens as UserAuthToken[])); } this.sessionDataResource.markOutdated(); @@ -118,49 +122,49 @@ UserInfoIncludes finishFederatedAuthentication(authId: string, linkUser?: boolean): ITask { let activeTask: ITask | undefined; - return new AutoRunningTask(() => this.performUpdate( - undefined, - [], - async () => { - activeTask = whileTask( - authInfo => { - if (authInfo.authStatus === AuthStatus.Success) { - return true; - } else if (authInfo.authStatus === AuthStatus.Error) { - throw new Error('Authentication error'); + return new AutoRunningTask( + () => + this.performUpdate(undefined, [], async () => { + activeTask = whileTask( + authInfo => { + if (authInfo.authStatus === AuthStatus.Success) { + return true; + } else if (authInfo.authStatus === AuthStatus.Error) { + throw new Error('Authentication error'); + } + + return false; + }, + async () => { + const { authInfo } = await this.graphQLService.sdk.getAuthStatus({ + authId, + linkUser, + customIncludeOriginDetails: true, + }); + return authInfo as AuthInfo; + }, + 1000, + ); + + const authInfo = await activeTask; + + if (authInfo.userTokens && authInfo.authStatus === AuthStatus.Success) { + if (this.data === null) { + this.resetIncludes(); + this.setData(await this.loader()); + } else { + this.data.authTokens.push(...(authInfo.userTokens as UserAuthToken[])); } - return false; - }, - async () => { - const { authInfo } = await this.graphQLService.sdk.getAuthStatus({ - authId, - linkUser, - customIncludeOriginDetails: true, - }); - return authInfo as AuthInfo; - }, - 1000 - ); - - const authInfo = await activeTask; - - if (authInfo.userTokens && authInfo.authStatus === AuthStatus.Success) { - if (this.data === null) { - this.resetIncludes(); - this.setData(await this.loader()); - } else { - this.data.authTokens.push(...authInfo.userTokens as UserAuthToken[]); + this.sessionDataResource.markOutdated(); } - this.sessionDataResource.markOutdated(); - } - - return this.data; - } - ), () => { - activeTask?.cancel(); - }); + return this.data; + }), + () => { + activeTask?.cancel(); + }, + ); } async logout(provider?: string, configuration?: string): Promise { @@ -230,10 +234,7 @@ UserInfoIncludes return this.data?.configurationParameters[key]; } - protected async loader( - key: void, - includes?: ReadonlyArray, - ): Promise { + protected async loader(key: void, includes?: ReadonlyArray): Promise { const { user } = await this.graphQLService.sdk.getActiveUser({ ...this.getDefaultIncludes(), ...this.getIncludesMap(key, includes), diff --git a/webapp/packages/core-authentication/src/UserMetaParametersResource.ts b/webapp/packages/core-authentication/src/UserMetaParametersResource.ts index 2a7f79e083..2ea613f163 100644 --- a/webapp/packages/core-authentication/src/UserMetaParametersResource.ts +++ b/webapp/packages/core-authentication/src/UserMetaParametersResource.ts @@ -5,7 +5,6 @@ * 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 { ExecutorInterrupter } from '@cloudbeaver/core-executor'; import { SessionResource } from '@cloudbeaver/core-root'; @@ -14,7 +13,7 @@ import { CachedDataResource, GraphQLService, UserConnectionAuthPropertiesFragmen import { UserInfoResource } from './UserInfoResource'; export type UserMetaParameter = UserConnectionAuthPropertiesFragment; -export interface IUserMetaParameterOptions{ +export interface IUserMetaParameterOptions { id: string; displayName: string; description?: string; @@ -23,17 +22,15 @@ export interface IUserMetaParameterOptions{ @injectable() export class UserMetaParametersResource extends CachedDataResource { - constructor( - private readonly graphQLService: GraphQLService, - sessionResource: SessionResource, - userInfoResource: UserInfoResource - ) { + constructor(private readonly graphQLService: GraphQLService, sessionResource: SessionResource, userInfoResource: UserInfoResource) { super(() => []); - this.sync(sessionResource, () => {}, () => {}); - this - .preloadResource(userInfoResource, () => {}) - .before(ExecutorInterrupter.interrupter(() => userInfoResource.data === null)); + this.sync( + sessionResource, + () => {}, + () => {}, + ); + this.preloadResource(userInfoResource, () => {}).before(ExecutorInterrupter.interrupter(() => userInfoResource.data === null)); } async add(options: IUserMetaParameterOptions): Promise { diff --git a/webapp/packages/core-authentication/src/UsersResource.ts b/webapp/packages/core-authentication/src/UsersResource.ts index 453ee1b2e7..768098cda5 100644 --- a/webapp/packages/core-authentication/src/UsersResource.ts +++ b/webapp/packages/core-authentication/src/UsersResource.ts @@ -5,25 +5,24 @@ * 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 { ServerConfigResource, SessionPermissionsResource } from '@cloudbeaver/core-root'; import { - GraphQLService, - CachedMapResource, - ResourceKey, AdminConnectionGrantInfo, - AdminUserInfoFragment, AdminUserInfo, - ResourceKeyUtils, - GetUsersListQueryVariables, + AdminUserInfoFragment, CachedMapAllKey, - resourceKeyList, + CachedMapResource, + GetUsersListQueryVariables, + GraphQLService, + isResourceAlias, isResourceKeyAlias, + ResourceKey, + resourceKeyList, ResourceKeySimple, - isResourceAlias + ResourceKeyUtils, } from '@cloudbeaver/core-sdk'; import { AUTH_PROVIDER_LOCAL_ID } from './AUTH_PROVIDER_LOCAL_ID'; @@ -56,13 +55,11 @@ export class UsersResource extends CachedMapResource { + async create({ userId, teams, credentials, metaParameters, grantedConnections, enabled, authRole }: UserCreateOptions): Promise { const { user } = await this.graphQLService.sdk.createUser({ userId, enabled, @@ -129,7 +120,7 @@ export class UsersResource extends CachedMapResource): Promise { await ResourceKeyUtils.forEachAsync(key, async key => { if (this.isActiveUser(key)) { - throw new Error('You can\'t delete current logged user'); + throw new Error("You can't delete current logged user"); } await this.graphQLService.sdk.deleteUser({ userId: key }); super.delete(key); @@ -214,10 +205,7 @@ export class UsersResource extends CachedMapResource, - includes?: string[] - ): Promise> { + protected async loader(originalKey: ResourceKey, includes?: string[]): Promise> { const all = this.isAlias(originalKey, CachedMapAllKey); const usersList: AdminUser[] = []; diff --git a/webapp/packages/core-authentication/src/index.ts b/webapp/packages/core-authentication/src/index.ts index af6c0d942c..6a16e93160 100644 --- a/webapp/packages/core-authentication/src/index.ts +++ b/webapp/packages/core-authentication/src/index.ts @@ -18,4 +18,4 @@ export * from './UserInfoResource'; export * from './UserMetaParametersResource'; export * from './UsersResource'; export * from './TeamMetaParametersResource'; -export * from './EAdminPermission'; \ No newline at end of file +export * from './EAdminPermission'; diff --git a/webapp/packages/core-authentication/src/manifest.ts b/webapp/packages/core-authentication/src/manifest.ts index a8c3cd4eed..b703aadf28 100644 --- a/webapp/packages/core-authentication/src/manifest.ts +++ b/webapp/packages/core-authentication/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { AppAuthService } from './AppAuthService'; diff --git a/webapp/packages/core-blocks/src/AppRefreshButton.tsx b/webapp/packages/core-blocks/src/AppRefreshButton.tsx index 7cbd179ac8..a9d7849d86 100644 --- a/webapp/packages/core-blocks/src/AppRefreshButton.tsx +++ b/webapp/packages/core-blocks/src/AppRefreshButton.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type React from 'react'; import styled, { css } from 'reshadow'; @@ -18,13 +17,14 @@ const style = css` background-color: #2a7cb4; padding: 5px 16px; border-radius: 4px; - letter-spacing: .08929em; - font-size: .875rem; + letter-spacing: 0.08929em; + font-size: 0.875rem; text-transform: uppercase; cursor: pointer; outline: none; border: none; - &:hover, &:focus { + &:hover, + &:focus { opacity: 0.8; } &:active { @@ -44,5 +44,9 @@ export const AppRefreshButton: React.FC = function AppRefreshButton({ cl app.start(); } - return styled(style)(); + return styled(style)( + , + ); }; diff --git a/webapp/packages/core-blocks/src/BlocksLocaleService.ts b/webapp/packages/core-blocks/src/BlocksLocaleService.ts index a2e29a8e4e..0df1b7f25a 100644 --- a/webapp/packages/core-blocks/src/BlocksLocaleService.ts +++ b/webapp/packages/core-blocks/src/BlocksLocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; diff --git a/webapp/packages/core-blocks/src/Button.tsx b/webapp/packages/core-blocks/src/Button.tsx index 8e2bbd13d5..f1e9fc37ed 100644 --- a/webapp/packages/core-blocks/src/Button.tsx +++ b/webapp/packages/core-blocks/src/Button.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable } from 'mobx'; import { observer } from 'mobx-react-lite'; import styled, { css, use } from 'reshadow'; @@ -18,84 +17,83 @@ import { useObservableRef } from './useObservableRef'; import { useStyles } from './useStyles'; const buttonStyles = css` - button-label { - composes: theme-button__label from global; + button-label { + composes: theme-button__label from global; + } + button-icon { + composes: theme-button__icon from global; + } + ripple { + composes: theme-button_ripple from global; + } + Button { + composes: theme-button from global; + display: flex; + + & IconOrImage { + width: 100%; } - button-icon { - composes: theme-button__icon from global; + + &[disabled] IconOrImage { + opacity: 0.5; } - ripple { - composes: theme-button_ripple from global; + + & Loader, + & button-label { + transition: opacity cubic-bezier(0.4, 0, 0.2, 1) 0.3s; } - Button { - composes: theme-button from global; - display: flex; - & IconOrImage { - width: 100%; - } + & Loader { + position: absolute; + opacity: 0 !important; + } - &[disabled] IconOrImage { - opacity: 0.5; - } - - & Loader, & button-label { - transition: opacity cubic-bezier(0.4, 0.0, 0.2, 1) 0.3s; - } + & button-label { + opacity: 1; + } + &[|loading] { & Loader { - position: absolute; - opacity: 0 !important; + opacity: 1 !important; } & button-label { - opacity: 1; - } - - &[|loading] { - & Loader { - opacity: 1 !important; - } - - & button-label { - opacity: 0; - } - } - - &[href] { - text-decoration: none !important; + opacity: 0; } } - `; + + &[href] { + text-decoration: none !important; + } + } +`; const buttonMod = { raised: css` Button { composes: theme-button_raised from global; } - `, + `, unelevated: css` Button { composes: theme-button_unelevated from global; } - `, + `, outlined: css` Button { composes: theme-button_outlined from global; } - `, + `, secondary: css` Button { composes: theme-button_secondary from global; } - `, + `, }; -type ButtonProps = ( - React.ButtonHTMLAttributes - & React.LinkHTMLAttributes - & React.HTMLAttributes -) & { +type ButtonProps = (React.ButtonHTMLAttributes & + React.LinkHTMLAttributes & + React.HTMLAttributes) & { loading?: boolean; icon?: string; viewBox?: string; @@ -105,9 +103,7 @@ type ButtonProps = ( href?: string; target?: '_blank' | '_self' | '_parent' | '_top'; loader?: boolean; - onClick?: React.MouseEventHandler< - HTMLButtonElement | HTMLAnchorElement | HTMLLinkElement | HTMLDivElement - > | (() => Promise); + onClick?: React.MouseEventHandler | (() => Promise); download?: boolean; }; @@ -126,24 +122,29 @@ export const Button = observer(function Button({ className, ...rest }) { - const state = useObservableRef(() => ({ - loading: false, - }), { - loading: observable.ref, - }, { - click(e: React.MouseEvent) { - const returnValue = onClick?.(e); - - if (returnValue instanceof Promise) { - if (loader) { - this.loading = true; - returnValue.finally(() => { - this.loading = false; - }); - } - } + const state = useObservableRef( + () => ({ + loading: false, + }), + { + loading: observable.ref, }, - }, ['click']); + { + click(e: React.MouseEvent) { + const returnValue = onClick?.(e); + + if (returnValue instanceof Promise) { + if (loader) { + this.loading = true; + returnValue.finally(() => { + this.loading = false; + }); + } + } + }, + }, + ['click'], + ); loading = state.loading || loading; @@ -153,18 +154,15 @@ export const Button = observer(function Button({ const Button = tag; return styled(useStyles(styles, buttonStyles, ...(mod || []).map(mod => buttonMod[mod])))( - + , ); }); diff --git a/webapp/packages/core-blocks/src/Cell.tsx b/webapp/packages/core-blocks/src/Cell.tsx index 2740e1a86b..9c1e5b1dd4 100644 --- a/webapp/packages/core-blocks/src/Cell.tsx +++ b/webapp/packages/core-blocks/src/Cell.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled, { css } from 'reshadow'; import type { ComponentStyle } from '@cloudbeaver/core-theming'; @@ -22,40 +21,40 @@ interface Props { } const styles = css` - main { - position: relative; - display: flex; - align-items: center; - padding: 8px; - } - before { - margin-right: 16px; - width: 24px; - height: 24px; - flex-shrink: 0; - } - after { - margin-left: 16px; - flex-shrink: 0; - } - info { - composes: theme-typography--body2 from global; - flex: 1; - line-height: 1.4; - display: flex; - flex-direction: column; - font-weight: 500; - } - description { - composes: theme-typography--caption from global; - line-height: 1.2; - } + main { + position: relative; + display: flex; + align-items: center; + padding: 8px; + } + before { + margin-right: 16px; + width: 24px; + height: 24px; + flex-shrink: 0; + } + after { + margin-left: 16px; + flex-shrink: 0; + } + info { + composes: theme-typography--body2 from global; + flex: 1; + line-height: 1.4; + display: flex; + flex-direction: column; + font-weight: 500; + } + description { + composes: theme-typography--caption from global; + line-height: 1.2; + } `; const RIPPLE_STYLES = css` cell { composes: theme-ripple from global; - } + } `; export const Cell: React.FC> = function Cell({ @@ -77,6 +76,6 @@ export const Cell: React.FC> = function Cell({ {after} - + , ); }; diff --git a/webapp/packages/core-blocks/src/Code.tsx b/webapp/packages/core-blocks/src/Code.tsx index b091c590f7..78067153c6 100644 --- a/webapp/packages/core-blocks/src/Code.tsx +++ b/webapp/packages/core-blocks/src/Code.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled, { css } from 'reshadow'; interface Props { @@ -13,19 +12,17 @@ interface Props { } const styles = css` - code-container { - composes: theme-background-secondary theme-text-on-secondary from global; - padding: 16px; - border-radius: var(--theme-group-element-radius); - } + code-container { + composes: theme-background-secondary theme-text-on-secondary from global; + padding: 16px; + border-radius: var(--theme-group-element-radius); + } `; export const Code: React.FC> = function Code({ children, className }) { return styled(styles)( - - {children} - - + {children} + , ); }; diff --git a/webapp/packages/core-blocks/src/ComplexLoader.tsx b/webapp/packages/core-blocks/src/ComplexLoader.tsx index 13f83b0ec5..0d134feadb 100644 --- a/webapp/packages/core-blocks/src/ComplexLoader.tsx +++ b/webapp/packages/core-blocks/src/ComplexLoader.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { LoadingError } from '@cloudbeaver/core-utils'; export interface IComplexLoaderData { @@ -65,7 +64,7 @@ export function createComplexLoader(loader: () => Promise): IComplexLoader this.data = await this.promise; return this.data; } catch (cause: any) { - this.error = new LoadingError(() => this.refresh(), 'Can\'t load element', { cause }); + this.error = new LoadingError(() => this.refresh(), "Can't load element", { cause }); throw this.error; } }, diff --git a/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionImageWithMask.tsx b/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionImageWithMask.tsx index 576e4c1c90..b1790c0003 100644 --- a/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionImageWithMask.tsx +++ b/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionImageWithMask.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { ConnectionImageWithMaskSvg } from './ConnectionImageWithMaskSvg'; import { ConnectionMark } from './ConnectionMark'; @@ -19,9 +18,7 @@ interface Props { className?: string; } -export const ConnectionImageWithMask: React.FC = ( - { icon, connected, maskId, size, markerRadius, paddingSize, className } -) => ( +export const ConnectionImageWithMask: React.FC = ({ icon, connected, maskId, size, markerRadius, paddingSize, className }) => ( <> = ( - { icon, connected, maskId, size = 16, markerRadius = 4, paddingSize = 0, className } -) => { +export const ConnectionImageWithMaskSvg: React.FC = ({ icon, connected, maskId, size = 16, markerRadius = 4, paddingSize = 0, className }) => { if (!icon) { return null; } @@ -42,7 +39,14 @@ export const ConnectionImageWithMaskSvg: React.FC = ( - + diff --git a/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionMark.tsx b/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionMark.tsx index d2cfbbe7c1..1f9ebb35a8 100644 --- a/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionMark.tsx +++ b/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionMark.tsx @@ -5,26 +5,25 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled, { css, use } from 'reshadow'; const styles = css` - status { - composes: theme-background-positive from global; - position: absolute; - opacity: 0; - transition: opacity 0.3s ease; - bottom: 0; - right: 0; - box-sizing: border-box; - width: 8px; - height: 8px; - border-radius: 50%; + status { + composes: theme-background-positive from global; + position: absolute; + opacity: 0; + transition: opacity 0.3s ease; + bottom: 0; + right: 0; + box-sizing: border-box; + width: 8px; + height: 8px; + border-radius: 50%; - &[|connected] { - opacity: 1; - } + &[|connected] { + opacity: 1; } + } `; interface Props { @@ -33,7 +32,5 @@ interface Props { } export const ConnectionMark: React.FC = function ConnectionMark({ connected, className }) { - return styled(styles)( - - ); -}; \ No newline at end of file + return styled(styles)(); +}; diff --git a/webapp/packages/core-blocks/src/Containers/BASE_CONTAINERS_STYLES.ts b/webapp/packages/core-blocks/src/Containers/BASE_CONTAINERS_STYLES.ts index bdc4c75958..db39c41229 100644 --- a/webapp/packages/core-blocks/src/Containers/BASE_CONTAINERS_STYLES.ts +++ b/webapp/packages/core-blocks/src/Containers/BASE_CONTAINERS_STYLES.ts @@ -5,217 +5,234 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { css } from 'reshadow'; export const BASE_CONTAINERS_STYLES = css` - Group { - composes: theme-background-surface theme-text-on-surface from global; + Group { + composes: theme-background-surface theme-text-on-surface from global; + } + ColoredContainer { + composes: theme-background-secondary theme-text-on-secondary from global; + } + GroupSubTitle { + composes: theme-text-text-hint-on-light from global; + } + Container, + ColoredContainer, + Group { + display: flex; + flex-direction: row; + align-content: baseline; + position: relative; + + &[hideEmpty]:empty { + display: none; } - ColoredContainer { - composes: theme-background-secondary theme-text-on-secondary from global; - } - GroupSubTitle { - composes: theme-text-text-hint-on-light from global; - } - Container, ColoredContainer, Group { - display: flex; - flex-direction: row; - align-content: baseline; - position: relative; - &[hideEmpty]:empty { - display: none; + &[vertical] { + flex-direction: column; + align-content: stretch; + + & > :global(*) { + flex-basis: 0 !important; } - - &[vertical] { - flex-direction: column; - align-content: stretch; - - & > :global(*) { - flex-basis: 0 !important; - } - & > [keepSize] { - flex-basis: auto !important; - } - } - - &[baseline] { - align-items: baseline; - } - - &[flexStart]{ - align-items: flex-start; - } - - &[center] { - align-items: center; - justify-content: center; - align-content: center; - } - - &[wrap] { - flex-wrap: wrap; - } - - &[overflow] { - overflow: auto; - } - - &[parent] { - padding: 24px; - - &[compact] { - padding: 16px; - } - - &[dense] { - padding: 8px; - } - } - - &[gap] { - gap: 24px; - - &[compact] { - gap: 16px; - } - - &[dense] { - gap: 8px; - } + & > [keepSize] { + flex-basis: auto !important; } } - Group { - align-content: baseline; - box-sizing: border-box; + &[baseline] { + align-items: baseline; + } + + &[flexStart] { + align-items: flex-start; + } + + &[center] { + align-items: center; + justify-content: center; + align-content: center; + } + + &[wrap] { + flex-wrap: wrap; + } + + &[overflow] { + overflow: auto; + } + + &[parent] { padding: 24px; - border-radius: var(--theme-group-element-radius); + + &[compact] { + padding: 16px; + } &[dense] { padding: 8px; } - - &[form] > :global(*) { - margin-right: 25%; - } - - &[box] { - padding: 0; - overflow: hidden; - } - - &[box="no-overflow"] { - padding: 0; - overflow: initial; - } - - &[center] { - margin: 0 auto; - } } - Container, ColoredContainer, Group { - &[grid] { - display: grid; + &[gap] { + gap: 24px; + + &[compact] { + gap: 16px; } - /* increase css specificity */ - &[grid]:nth-child(n) { - flex-basis: unset; - max-width: unset; - } - - &[grid][tiny] { - grid-template-columns: repeat(auto-fit, minmax(140px, max-content)); - } - - &[grid][small] { - grid-template-columns: repeat(auto-fit, minmax(260px, max-content)); - } - - &[grid][medium] { - grid-template-columns: repeat(auto-fit, minmax(460px, max-content)); - } - - &[grid][large] { - grid-template-columns: repeat(auto-fit, minmax(800px, max-content)); + &[dense] { + gap: 8px; } } + } - Container, ColoredContainer, Group { - flex-wrap: wrap; + Group { + align-content: baseline; + box-sizing: border-box; + padding: 24px; + border-radius: var(--theme-group-element-radius); + + &[dense] { + padding: 8px; + } + + &[form] > :global(*) { + margin-right: 25%; + } + + &[box] { + padding: 0; + overflow: hidden; + } + + &[box='no-overflow'] { + padding: 0; + overflow: initial; + } + + &[center] { + margin: 0 auto; + } + } + + Container, + ColoredContainer, + Group { + &[grid] { + display: grid; + } + + /* increase css specificity */ + &[grid]:nth-child(n) { + flex-basis: unset; + max-width: unset; + } + + &[grid][tiny] { + grid-template-columns: repeat(auto-fit, minmax(140px, max-content)); + } + + &[grid][small] { + grid-template-columns: repeat(auto-fit, minmax(260px, max-content)); + } + + &[grid][medium] { + grid-template-columns: repeat(auto-fit, minmax(460px, max-content)); + } + + &[grid][large] { + grid-template-columns: repeat(auto-fit, minmax(800px, max-content)); + } + } + + Container, + ColoredContainer, + Group { + flex-wrap: wrap; + flex: 1 1 100%; + + & > :global(*) { flex: 1 1 100%; - - & > :global(*) { - flex: 1 1 100%; - } - - &[keepSize], & > [keepSize] { - flex-grow: 0; - flex-basis: 0; - flex-basis: auto; /* test for layout */ - } - - &[tiny], & > [tiny], &[grid][tiny] > * { - flex-basis: 140px; - max-width: 210px; - } - - &[small], & > [small], &[grid][small] > * { - flex-basis: 260px; - max-width: 390px; - } - - &[medium], & > [medium], &[grid][medium] > * { - flex-basis: 460px; - max-width: 640px; - } - - &[large], & > [large], &[grid][large] > * { - flex-basis: 800px; - max-width: 800px; - } - - &[maximum], & > [maximum], &[grid][maximum] > * { - max-width: 100%; - } - - &[fill], & > [fill] { - max-width: none; - } } - GroupItem { - min-width: min-content; + &[keepSize], + & > [keepSize] { + flex-grow: 0; + flex-basis: 0; + flex-basis: auto; /* test for layout */ } - GroupTitle { - composes: theme-typography--body2 from global; - font-weight: 400; - margin: 0; - text-transform: uppercase; - opacity: 0.9; + &[tiny], + & > [tiny], + &[grid][tiny] > * { + flex-basis: 140px; + max-width: 210px; } - Group[box] > GroupTitle { - padding: 24px; + &[small], + & > [small], + &[grid][small] > * { + flex-basis: 260px; + max-width: 390px; } - GroupSubTitle { - composes: theme-typography--caption from global; - display: block; - text-transform: none; + &[medium], + & > [medium], + &[grid][medium] > * { + flex-basis: 460px; + max-width: 640px; } - GroupClose { - width: 18px; - height: 18px; - cursor: pointer; - display: flex; - position: absolute; - right: 24px; - margin-right: 0 !important; + &[large], + & > [large], + &[grid][large] > * { + flex-basis: 800px; + max-width: 800px; } - `; + + &[maximum], + & > [maximum], + &[grid][maximum] > * { + max-width: 100%; + } + + &[fill], + & > [fill] { + max-width: none; + } + } + + GroupItem { + min-width: min-content; + } + + GroupTitle { + composes: theme-typography--body2 from global; + font-weight: 400; + margin: 0; + text-transform: uppercase; + opacity: 0.9; + } + + Group[box] > GroupTitle { + padding: 24px; + } + + GroupSubTitle { + composes: theme-typography--caption from global; + display: block; + text-transform: none; + } + + GroupClose { + width: 18px; + height: 18px; + cursor: pointer; + display: flex; + position: absolute; + right: 24px; + margin-right: 0 !important; + } +`; diff --git a/webapp/packages/core-blocks/src/Containers/ColoredContainer.tsx b/webapp/packages/core-blocks/src/Containers/ColoredContainer.tsx index 644f3a65f4..5c63682d6d 100644 --- a/webapp/packages/core-blocks/src/Containers/ColoredContainer.tsx +++ b/webapp/packages/core-blocks/src/Containers/ColoredContainer.tsx @@ -5,13 +5,15 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { forwardRef } from 'react'; import { filterContainerFakeProps } from './filterContainerFakeProps'; import type { IContainerProps } from './IContainerProps'; -export const ColoredContainer = forwardRef>(function ColoredContainer(props, ref) { +export const ColoredContainer = forwardRef>(function ColoredContainer( + props, + ref, +) { const divProps = filterContainerFakeProps(props); return
; diff --git a/webapp/packages/core-blocks/src/Containers/Container.tsx b/webapp/packages/core-blocks/src/Containers/Container.tsx index 137c9df907..906ef247be 100644 --- a/webapp/packages/core-blocks/src/Containers/Container.tsx +++ b/webapp/packages/core-blocks/src/Containers/Container.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { forwardRef } from 'react'; import { filterContainerFakeProps } from './filterContainerFakeProps'; diff --git a/webapp/packages/core-blocks/src/Containers/Group.tsx b/webapp/packages/core-blocks/src/Containers/Group.tsx index e5c03df696..586f2a263c 100644 --- a/webapp/packages/core-blocks/src/Containers/Group.tsx +++ b/webapp/packages/core-blocks/src/Containers/Group.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { forwardRef } from 'react'; import { filterContainerFakeProps } from './filterContainerFakeProps'; @@ -17,12 +16,7 @@ interface Props extends IContainerProps { box?: boolean | 'no-overflow'; } -export const Group = forwardRef>(function Group({ - form, - center, - box, - ...rest -}, ref) { +export const Group = forwardRef>(function Group({ form, center, box, ...rest }, ref) { const divProps = filterContainerFakeProps(rest); return
; diff --git a/webapp/packages/core-blocks/src/Containers/GroupClose.tsx b/webapp/packages/core-blocks/src/Containers/GroupClose.tsx index 16173ebd81..5f27032eed 100644 --- a/webapp/packages/core-blocks/src/Containers/GroupClose.tsx +++ b/webapp/packages/core-blocks/src/Containers/GroupClose.tsx @@ -5,16 +5,16 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Icon } from '../Icon'; interface IProps { onClick?: () => void; } -export const GroupClose: React.FC> = function GroupClose({ - onClick, - ...rest -}) { - return
; +export const GroupClose: React.FC> = function GroupClose({ onClick, ...rest }) { + return ( +
+ +
+ ); }; diff --git a/webapp/packages/core-blocks/src/Containers/GroupItem.tsx b/webapp/packages/core-blocks/src/Containers/GroupItem.tsx index 212e55d44d..9e3404d1af 100644 --- a/webapp/packages/core-blocks/src/Containers/GroupItem.tsx +++ b/webapp/packages/core-blocks/src/Containers/GroupItem.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { filterLayoutFakeProps } from './filterLayoutFakeProps'; import type { ILayoutSizeProps } from './ILayoutSizeProps'; diff --git a/webapp/packages/core-blocks/src/Containers/GroupSubTitle.tsx b/webapp/packages/core-blocks/src/Containers/GroupSubTitle.tsx index b90e1012ac..13e155ecc3 100644 --- a/webapp/packages/core-blocks/src/Containers/GroupSubTitle.tsx +++ b/webapp/packages/core-blocks/src/Containers/GroupSubTitle.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { filterLayoutFakeProps } from './filterLayoutFakeProps'; import type { ILayoutSizeProps } from './ILayoutSizeProps'; diff --git a/webapp/packages/core-blocks/src/Containers/GroupTitle.tsx b/webapp/packages/core-blocks/src/Containers/GroupTitle.tsx index f63decd096..a622d1b383 100644 --- a/webapp/packages/core-blocks/src/Containers/GroupTitle.tsx +++ b/webapp/packages/core-blocks/src/Containers/GroupTitle.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { filterLayoutFakeProps } from './filterLayoutFakeProps'; import type { ILayoutSizeProps } from './ILayoutSizeProps'; diff --git a/webapp/packages/core-blocks/src/Containers/IContainerProps.ts b/webapp/packages/core-blocks/src/Containers/IContainerProps.ts index 8ac6018928..5839ff3f47 100644 --- a/webapp/packages/core-blocks/src/Containers/IContainerProps.ts +++ b/webapp/packages/core-blocks/src/Containers/IContainerProps.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { ILayoutSizeProps } from './ILayoutSizeProps'; export interface IContainerProps extends ILayoutSizeProps { diff --git a/webapp/packages/core-blocks/src/Containers/filterContainerFakeProps.ts b/webapp/packages/core-blocks/src/Containers/filterContainerFakeProps.ts index 4818f1db72..acb850f498 100644 --- a/webapp/packages/core-blocks/src/Containers/filterContainerFakeProps.ts +++ b/webapp/packages/core-blocks/src/Containers/filterContainerFakeProps.ts @@ -5,26 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { filterLayoutFakeProps } from './filterLayoutFakeProps'; import type { IContainerProps } from './IContainerProps'; export function filterContainerFakeProps(props: T): Omit { - const { - hideEmpty, - flexStart, - baseline, - center, - vertical, - wrap, - overflow, - parent, - gap, - grid, - dense, - compact, - ...rest - } = filterLayoutFakeProps(props); + const { hideEmpty, flexStart, baseline, center, vertical, wrap, overflow, parent, gap, grid, dense, compact, ...rest } = + filterLayoutFakeProps(props); return rest as Omit; } diff --git a/webapp/packages/core-blocks/src/Containers/filterLayoutFakeProps.ts b/webapp/packages/core-blocks/src/Containers/filterLayoutFakeProps.ts index ec547ad156..97d0a5d455 100644 --- a/webapp/packages/core-blocks/src/Containers/filterLayoutFakeProps.ts +++ b/webapp/packages/core-blocks/src/Containers/filterLayoutFakeProps.ts @@ -5,20 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { ILayoutSizeProps } from './ILayoutSizeProps'; export function filterLayoutFakeProps(props: T): Omit { - const { - keepSize, - tiny, - small, - medium, - large, - maximum, - fill, - ...rest - } = props; + const { keepSize, tiny, small, medium, large, maximum, fill, ...rest } = props; return rest; } diff --git a/webapp/packages/core-blocks/src/DisplayError.tsx b/webapp/packages/core-blocks/src/DisplayError.tsx index 08cf3c6338..f3d130246c 100644 --- a/webapp/packages/core-blocks/src/DisplayError.tsx +++ b/webapp/packages/core-blocks/src/DisplayError.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type React from 'react'; import styled, { css, use } from 'reshadow'; @@ -51,14 +50,7 @@ interface Props { styles?: ComponentStyle; } -export const DisplayError: React.FC> = function DisplayError({ - root, - children, - error, - errorInfo, - className, - styles, -}) { +export const DisplayError: React.FC> = function DisplayError({ root, children, error, errorInfo, className, styles }) { const stack = errorInfo?.componentStack || error?.stack; return styled(useStyles(style, styles))( @@ -76,6 +68,6 @@ export const DisplayError: React.FC> = function D )} - + , ); }; diff --git a/webapp/packages/core-blocks/src/ErrorBoundary.tsx b/webapp/packages/core-blocks/src/ErrorBoundary.tsx index 973842c2e8..907e9b1eb6 100644 --- a/webapp/packages/core-blocks/src/ErrorBoundary.tsx +++ b/webapp/packages/core-blocks/src/ErrorBoundary.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React, { ErrorInfo } from 'react'; import styled, { css } from 'reshadow'; @@ -43,15 +42,9 @@ interface IState { exceptions: IErrorData[]; } -export class ErrorBoundary - extends React.Component, IState> - implements IExceptionContext { +export class ErrorBoundary extends React.Component, IState> implements IExceptionContext { get canRefresh(): boolean { - return ( - !!this.props.remount - || !!this.props.onRefresh - || this.state.exceptions.some(error => errorOf(error.error, LoadingError)) - ); + return !!this.props.remount || !!this.props.onRefresh || this.state.exceptions.some(error => errorOf(error.error, LoadingError)); } constructor(props: Props) { super(props); @@ -69,12 +62,15 @@ export class ErrorBoundary if (state.exceptions.some(data => data.error === error)) { return state; } - return ({ - exceptions: [...state.exceptions, { - error, - errorInfo, - }], - }); + return { + exceptions: [ + ...state.exceptions, + { + error, + errorInfo, + }, + ], + }; }); } @@ -84,16 +80,18 @@ export class ErrorBoundary for (const errorData of this.state.exceptions) { if (root) { return styled(style)( - - {onClose && } - {this.canRefresh && } - + + {onClose && ( + + + + )} + {this.canRefresh && ( + + + + )} + , ); } else { return ( @@ -110,11 +108,7 @@ export class ErrorBoundary } } - return ( - - {children} - - ); + return {children}; } private refresh() { diff --git a/webapp/packages/core-blocks/src/ErrorContext.ts b/webapp/packages/core-blocks/src/ErrorContext.ts index 5b59603a3a..c021ec932b 100644 --- a/webapp/packages/core-blocks/src/ErrorContext.ts +++ b/webapp/packages/core-blocks/src/ErrorContext.ts @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createContext } from 'react'; export interface IExceptionContext { catch(exception: Error): void; } -export const ErrorContext = createContext(null); \ No newline at end of file +export const ErrorContext = createContext(null); diff --git a/webapp/packages/core-blocks/src/ErrorMessage.test.tsx b/webapp/packages/core-blocks/src/ErrorMessage.test.tsx index 9705a4ee69..d665b95b63 100644 --- a/webapp/packages/core-blocks/src/ErrorMessage.test.tsx +++ b/webapp/packages/core-blocks/src/ErrorMessage.test.tsx @@ -5,8 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import '@testing-library/jest-dom'; +import { screen } from '@testing-library/react'; import { mockAuthentication } from '@cloudbeaver/core-authentication/mocks/mockAuthentication'; import { createApp } from '@cloudbeaver/core-cli/tests/utils/createApp'; @@ -14,21 +14,17 @@ import { renderInApp } from '@cloudbeaver/core-cli/tests/utils/renderInApp'; import { createGQLEndpoint } from '@cloudbeaver/core-root/mocks/createGQLEndpoint'; import { mockAppInit } from '@cloudbeaver/core-root/mocks/mockAppInit'; import { mockGraphQL } from '@cloudbeaver/core-root/mocks/mockGraphQL'; -import { screen } from '@testing-library/react'; import { ErrorMessage } from './ErrorMessage'; const endpoint = createGQLEndpoint(); const app = createApp(); -mockGraphQL( - ...mockAppInit(endpoint), - ...mockAuthentication(endpoint) -); +mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint)); beforeAll(() => app.init()); test('icons.svg#name', () => { - renderInApp(, app); + renderInApp(, app); expect(screen.getByText('error')).not.toBeNull(); -}); \ No newline at end of file +}); diff --git a/webapp/packages/core-blocks/src/ErrorMessage.tsx b/webapp/packages/core-blocks/src/ErrorMessage.tsx index c7102d5e26..c771f390aa 100644 --- a/webapp/packages/core-blocks/src/ErrorMessage.tsx +++ b/webapp/packages/core-blocks/src/ErrorMessage.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -20,7 +19,7 @@ const styles = css` align-items: center; border-radius: var(--theme-group-element-radius); height: 50px; - padding: 8px 12px; + padding: 8px 12px; } IconOrImage { @@ -52,27 +51,20 @@ interface Props { onShowDetails?: () => void; } -export const ErrorMessage = observer(function ErrorMessage({ - text, - className, - hasDetails, - onShowDetails, -}) { +export const ErrorMessage = observer(function ErrorMessage({ text, className, hasDetails, onShowDetails }) { const translate = useTranslate(); return styled(styles)( - - {text} - + {text} {hasDetails && ( - )} - + , ); }); diff --git a/webapp/packages/core-blocks/src/ExceptionMessage.tsx b/webapp/packages/core-blocks/src/ExceptionMessage.tsx index 3fbf4ca488..368213a19c 100644 --- a/webapp/packages/core-blocks/src/ExceptionMessage.tsx +++ b/webapp/packages/core-blocks/src/ExceptionMessage.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css, use } from 'reshadow'; @@ -116,7 +115,15 @@ interface Props { } export const ExceptionMessage = observer(function ExceptionMessage({ - name, message, exception = null, icon, inline, className, styles, onRetry, onClose, + name, + message, + exception = null, + icon, + inline, + className, + styles, + onRetry, + onClose, }) { const translate = useTranslate(); const error = useErrorDetails(exception); @@ -146,12 +153,12 @@ export const ExceptionMessage = observer(function ExceptionMessage({ {message} {error.hasDetails && ( - )} {onRetry && ( - )} @@ -164,6 +171,6 @@ export const ExceptionMessage = observer(function ExceptionMessage({ )} )} - + , ); }); diff --git a/webapp/packages/core-blocks/src/Expand/EXPANDABLE_FORM_STYLES.ts b/webapp/packages/core-blocks/src/Expand/EXPANDABLE_FORM_STYLES.ts index b0407d7dd5..8876bd2e9b 100644 --- a/webapp/packages/core-blocks/src/Expand/EXPANDABLE_FORM_STYLES.ts +++ b/webapp/packages/core-blocks/src/Expand/EXPANDABLE_FORM_STYLES.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { css } from 'reshadow'; export const EXPANDABLE_FORM_STYLES = css` @@ -16,4 +15,4 @@ export const EXPANDABLE_FORM_STYLES = css` text-transform: uppercase; opacity: 0.9; } -`; \ No newline at end of file +`; diff --git a/webapp/packages/core-blocks/src/Expand/Expandable.tsx b/webapp/packages/core-blocks/src/Expand/Expandable.tsx index c345a6f9d0..8d393d024b 100644 --- a/webapp/packages/core-blocks/src/Expand/Expandable.tsx +++ b/webapp/packages/core-blocks/src/Expand/Expandable.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { forwardRef, ReactNode, useImperativeHandle } from 'react'; import { Disclosure, DisclosureContent, DisclosureStateReturn, useDisclosureState } from 'reakit'; @@ -60,28 +59,24 @@ const styles = css` } `; -export const Expandable = observer(forwardRef(function Expandable({ - label, - defaultExpanded, - disabled, - children, - style, -}, ref) { - const disclosure = useDisclosureState({ visible: defaultExpanded ?? false }); +export const Expandable = observer( + forwardRef(function Expandable({ label, defaultExpanded, disabled, children, style }, ref) { + const disclosure = useDisclosureState({ visible: defaultExpanded ?? false }); - useImperativeHandle(ref, () => disclosure); + useImperativeHandle(ref, () => disclosure); - return styled(useStyles(styles, style))( - <> - - - - - {label} - - - <>{children} - - - ); -})); \ No newline at end of file + return styled(useStyles(styles, style))( + <> + + + + + {label} + + + <>{children} + + , + ); + }), +); diff --git a/webapp/packages/core-blocks/src/FolderExplorer/FolderExplorer.tsx b/webapp/packages/core-blocks/src/FolderExplorer/FolderExplorer.tsx index 536bf039f2..f76a2a2a4c 100644 --- a/webapp/packages/core-blocks/src/FolderExplorer/FolderExplorer.tsx +++ b/webapp/packages/core-blocks/src/FolderExplorer/FolderExplorer.tsx @@ -5,20 +5,14 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { FolderExplorerContext, IFolderExplorerContext } from './FolderExplorerContext'; -interface Props{ +interface Props { state: IFolderExplorerContext; } -export const FolderExplorer = observer>(function FolderExplorer({ - state, - children, -}) { - return ( - {children} - ); +export const FolderExplorer = observer>(function FolderExplorer({ state, children }) { + return {children}; }); diff --git a/webapp/packages/core-blocks/src/FolderExplorer/FolderExplorerContext.ts b/webapp/packages/core-blocks/src/FolderExplorer/FolderExplorerContext.ts index 05f125c080..b99aa4d6cc 100644 --- a/webapp/packages/core-blocks/src/FolderExplorer/FolderExplorerContext.ts +++ b/webapp/packages/core-blocks/src/FolderExplorer/FolderExplorerContext.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createContext } from 'react'; export interface IFolderExplorerOptions { diff --git a/webapp/packages/core-blocks/src/FolderExplorer/FolderExplorerPath.tsx b/webapp/packages/core-blocks/src/FolderExplorer/FolderExplorerPath.tsx index 8f0daae043..7a11ad662f 100644 --- a/webapp/packages/core-blocks/src/FolderExplorer/FolderExplorerPath.tsx +++ b/webapp/packages/core-blocks/src/FolderExplorer/FolderExplorerPath.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useContext } from 'react'; import styled from 'reshadow'; @@ -20,11 +19,7 @@ interface Props { className?: string; } -export const FolderExplorerPath = observer(function FolderExplorerPath({ - getName, - canSkip, - className, -}) { +export const FolderExplorerPath = observer(function FolderExplorerPath({ getName, canSkip, className }) { const context = useContext(FolderExplorerContext); if (!context) { @@ -44,32 +39,12 @@ export const FolderExplorerPath = observer(function FolderExplorerPath({ const path = context.state.fullPath.slice(0, i); const skipFolder = !canSkip || canSkip(folder); - if ( - i === 0 - || i === context.state.fullPath.length - 1 - || !skipFolder - || context.state.fullPath.length < 5 - ) { + if (i === 0 || i === context.state.fullPath.length - 1 || !skipFolder || context.state.fullPath.length < 5) { if (skip) { - pathElements.push( - - ); + pathElements.push(); } - pathElements.push( - - ); + pathElements.push(); skip = false; skipTitle = ''; continue; @@ -79,15 +54,11 @@ export const FolderExplorerPath = observer(function FolderExplorerPath({ if (skipTitle !== '') { skipTitle += ' > '; } - skipTitle += (getName?.(folder) || folder); + skipTitle += getName?.(folder) || folder; skip = true; continue; } } - return styled(folderExplorerStyles)( - - {pathElements} - - ); + return styled(folderExplorerStyles)({pathElements}); }); diff --git a/webapp/packages/core-blocks/src/FolderExplorer/FolderName.tsx b/webapp/packages/core-blocks/src/FolderExplorer/FolderName.tsx index dab81866b9..6edbd1cfc5 100644 --- a/webapp/packages/core-blocks/src/FolderExplorer/FolderName.tsx +++ b/webapp/packages/core-blocks/src/FolderExplorer/FolderName.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useContext } from 'react'; import styled from 'reshadow'; @@ -36,14 +35,7 @@ interface ShortProps extends BaseProps { short: boolean; } -export const FolderName = observer(function FolderName({ - folder, - path, - title, - short, - last, - getName, -}) { +export const FolderName = observer(function FolderName({ folder, path, title, short, last, getName }) { const context = useContext(FolderExplorerContext); if (!context) { @@ -71,10 +63,8 @@ export const FolderName = observer(function FolderName - {last - ? name - : context.open(path, folder!)}>{name}} + {last ? name : context.open(path, folder!)}>{name}} - + , ); }); diff --git a/webapp/packages/core-blocks/src/FolderExplorer/folderExplorerStyles.ts b/webapp/packages/core-blocks/src/FolderExplorer/folderExplorerStyles.ts index b73c0c5602..e6dd4adf51 100644 --- a/webapp/packages/core-blocks/src/FolderExplorer/folderExplorerStyles.ts +++ b/webapp/packages/core-blocks/src/FolderExplorer/folderExplorerStyles.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { css } from 'reshadow'; export const folderExplorerStyles = css` @@ -33,8 +32,8 @@ export const folderExplorerStyles = css` text-overflow: ellipsis; padding: 0 4px; } - + folder-explorer-path-element:first-child folder-explorer-path-element-arrow { - display: none + display: none; } `; diff --git a/webapp/packages/core-blocks/src/FolderExplorer/useFolderExplorer.ts b/webapp/packages/core-blocks/src/FolderExplorer/useFolderExplorer.ts index e1aba0742d..f866859472 100644 --- a/webapp/packages/core-blocks/src/FolderExplorer/useFolderExplorer.ts +++ b/webapp/packages/core-blocks/src/FolderExplorer/useFolderExplorer.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, observable } from 'mobx'; import { useContext, useMemo } from 'react'; @@ -23,40 +22,42 @@ export function useFolderExplorer(root: string, options: IFolderExplorerOptions fullPath: [root], folder: root, }), - () => { }, - data => ( - typeof data === 'object' - && typeof data.folder === 'string' - && Array.isArray(data.path) - && Array.isArray(data.fullPath) - ) + () => {}, + data => typeof data === 'object' && typeof data.folder === 'string' && Array.isArray(data.path) && Array.isArray(data.fullPath), ); - useMemo(action(() => { - if (!options.saveState) { - userState.folder = root; - userState.fullPath = [root]; - userState.path = []; - } - }), [userState]); + useMemo( + action(() => { + if (!options.saveState) { + userState.folder = root; + userState.fullPath = [root]; + userState.path = []; + } + }), + [userState], + ); - const data = useObservableRef(() => ({ - root, - options, - open(path: string[], folder: string) { - this.state.path = path.slice(); - this.state.fullPath = [...path, folder]; - this.state.folder = folder; + const data = useObservableRef( + () => ({ + root, + options, + open(path: string[], folder: string) { + this.state.path = path.slice(); + this.state.fullPath = [...path, folder]; + this.state.folder = folder; + }, + }), + { + root: observable, + state: observable.ref, + options: observable.ref, + open: action.bound, }, - }), { - root: observable, - state: observable.ref, - options: observable.ref, - open: action.bound, - }, { - state: userState, - root, - }); + { + state: userState, + root, + }, + ); return context || data; } diff --git a/webapp/packages/core-blocks/src/FormControls/BASE_DROPDOWN_STYLES.ts b/webapp/packages/core-blocks/src/FormControls/BASE_DROPDOWN_STYLES.ts index f68095b6b8..1f29199361 100644 --- a/webapp/packages/core-blocks/src/FormControls/BASE_DROPDOWN_STYLES.ts +++ b/webapp/packages/core-blocks/src/FormControls/BASE_DROPDOWN_STYLES.ts @@ -5,51 +5,51 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { css } from 'reshadow'; export const BASE_DROPDOWN_STYLES = css` - MenuItem { - composes: theme-ripple from global; - } + MenuItem { + composes: theme-ripple from global; + } - Menu { - composes: theme-text-on-surface theme-background-surface theme-typography--caption theme-elevation-z3 from global; + Menu { + composes: theme-text-on-surface theme-background-surface theme-typography--caption theme-elevation-z3 from global; + display: flex; + flex-direction: column; + max-height: 300px; + overflow: auto; + outline: none; + z-index: 999; + border-radius: var(--theme-form-element-radius); + + & MenuItem { + background: transparent; display: flex; - flex-direction: column; - max-height: 300px; - overflow: auto; + flex-direction: row; + align-items: center; + padding: 8px 12px; + text-align: left; outline: none; - z-index: 999; - border-radius: var(--theme-form-element-radius); + color: inherit; + cursor: pointer; + gap: 8px; - & MenuItem { - background: transparent; - display: flex; - flex-direction: row; - align-items: center; - padding: 8px 12px; - text-align: left; - outline: none; - color: inherit; - cursor: pointer; - gap: 8px; + & item-icon, + & item-title { + position: relative; + } - & item-icon, & item-title { - position: relative; + & item-icon { + width: 16px; + height: 16px; + overflow: hidden; + flex-shrink: 0; + + & IconOrImage { + width: 100%; + height: 100%; } - - & item-icon { - width: 16px; - height: 16px; - overflow: hidden; - flex-shrink: 0; - - & IconOrImage { - width: 100%; - height: 100%; - } - } } } - `; \ No newline at end of file + } +`; diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Checkbox.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Checkbox.tsx index ba16e510dd..3063872aca 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Checkbox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Checkbox.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import type { ComponentStyle } from '@cloudbeaver/core-theming'; @@ -23,12 +22,16 @@ export interface CheckboxBaseProps { style?: ComponentStyle; } -export type CheckboxInputProps = Omit, 'onChange' | 'type' | 'value' | 'defaultValue' | 'checked' | 'defaultChecked' | 'style'> & ILayoutSizeProps & { - value?: string; - defaultValue?: string; - defaultChecked?: boolean; - label?: string; -}; +export type CheckboxInputProps = Omit< + React.InputHTMLAttributes, + 'onChange' | 'type' | 'value' | 'defaultValue' | 'checked' | 'defaultChecked' | 'style' +> & + ILayoutSizeProps & { + value?: string; + defaultValue?: string; + defaultChecked?: boolean; + label?: string; + }; export interface ICheckboxControlledProps extends CheckboxInputProps { state?: never; diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.tsx index 467cd550b4..42c8ef1868 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { useLayoutEffect, useRef } from 'react'; import styled, { css } from 'reshadow'; @@ -37,55 +36,55 @@ const checkboxStyles = css` checkbox-ripple { composes: theme-checkbox__ripple from global; } - checkbox-container { - display: flex; - align-items: center; - } - checkbox-label { - composes: theme-typography--body2 from global; - cursor: pointer; - } - `; + checkbox-container { + display: flex; + align-items: center; + } + checkbox-label { + composes: theme-typography--body2 from global; + cursor: pointer; + } +`; const checkboxMod: Record = { primary: css` - checkbox { - composes: theme-checkbox_primary from global; - } - `, + checkbox { + composes: theme-checkbox_primary from global; + } + `, surface: css` - checkbox { - composes: theme-checkbox_surface from global; - } - `, + checkbox { + composes: theme-checkbox_surface from global; + } + `, small: css` - checkbox { - composes: theme-checkbox_small from global; + checkbox { + composes: theme-checkbox_small from global; + } + checkbox-container { + & checkbox { + width: 14px; + height: 14px; } - checkbox-container { - & checkbox { - width: 14px; - height: 14px; - } - & checkbox-background { - width: 14px; - height: 14px; - } + & checkbox-background { + width: 14px; + height: 14px; } - `, + } + `, }; const checkboxState = { disabled: css` - checkbox { - composes: theme-checkbox--disabled from global; - } - `, + checkbox { + composes: theme-checkbox--disabled from global; + } + `, checked: css` - checkbox { - composes: theme-checkbox--checked from global; - } - `, + checkbox { + composes: theme-checkbox--checked from global; + } + `, }; interface ICheckboxMarkupProps extends Omit, 'style'> { @@ -97,7 +96,16 @@ interface ICheckboxMarkupProps extends Omit = function CheckboxMarkup({ - id, label, indeterminate, className, title, mod = ['primary'], ripple = true, style, readOnly, ...rest + id, + label, + indeterminate, + className, + title, + mod = ['primary'], + ripple = true, + style, + readOnly, + ...rest }) { const checkboxRef = useRef(null); @@ -113,30 +121,25 @@ export const CheckboxMarkup: React.FC = function CheckboxM ...(mod || []).map(mod => checkboxMod[mod]), rest.disabled && checkboxState.disabled, rest.checked && checkboxState.checked, - style - ) + style, + ), )( - + - - + + - {ripple && ( - - )} + {ripple && } - {label && (id || rest.name) && {label}} - + {label && (id || rest.name) && ( + + {label} + + )} + , ); }; diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx index 843d7946c0..e78b506ca6 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled, { css } from 'reshadow'; import { useStyles } from '../../useStyles'; @@ -30,7 +29,7 @@ const style = css` } } field-label { - composes: theme-typography--body2 from global; + composes: theme-typography--body2 from global; } Checkbox[disabled] + field-label { cursor: auto; @@ -51,13 +50,9 @@ export const FieldCheckbox: CheckboxType = function FieldCheckbox({ return styled(styles)( - + {children} - + , ); }; diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx index 85c6d23f70..974f739cde 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx @@ -5,12 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; - - import { filterLayoutFakeProps } from '../../Containers/filterLayoutFakeProps'; import { useStyles } from '../../useStyles'; import { baseFormControlStyles, baseValidFormControlStyles } from '../baseFormControlStyles'; @@ -19,72 +16,72 @@ import type { ICheckboxControlledProps, ICheckboxObjectProps } from './Checkbox' import { useCheckboxState } from './useCheckboxState'; const switchStyles = css` -switch-control { - composes: theme-switch from global; -} -switch-control-track { - composes: theme-switch__track from global; -} -switch-input { - composes: theme-switch_native-control from global; -} -switch-control-underlay { - composes: theme-switch__thumb-underlay from global; -} -switch-control-thumb { - composes: theme-switch__thumb from global; -} -radio-ripple { - composes: theme-radio_ripple from global; -} - switch-body { - display: flex; - align-items: center; - } - switch-body { - composes: theme-typography--body1 from global; - } - switch-body field-label { - cursor: pointer; - user-select: none; - display: block; - padding-left: 18px; - min-width: 50px; - white-space: pre-wrap; - font-weight: 500; - } - `; + switch-control { + composes: theme-switch from global; + } + switch-control-track { + composes: theme-switch__track from global; + } + switch-input { + composes: theme-switch_native-control from global; + } + switch-control-underlay { + composes: theme-switch__thumb-underlay from global; + } + switch-control-thumb { + composes: theme-switch__thumb from global; + } + radio-ripple { + composes: theme-radio_ripple from global; + } + switch-body { + display: flex; + align-items: center; + } + switch-body { + composes: theme-typography--body1 from global; + } + switch-body field-label { + cursor: pointer; + user-select: none; + display: block; + padding-left: 18px; + min-width: 50px; + white-space: pre-wrap; + font-weight: 500; + } +`; const switchMod = { primary: css` - switch-control { - composes: theme-switch_primary from global; - } - `, + switch-control { + composes: theme-switch_primary from global; + } + `, dense: css` - switch-body { - composes: theme-switch_dense from global; - } - field-label { - composes: theme-typography--body2 from global; - } - switch-body field-label { - font-weight: initial; - } - `, + switch-body { + composes: theme-switch_dense from global; + } + field-label { + composes: theme-typography--body2 from global; + } + switch-body field-label { + font-weight: initial; + } + `, }; const switchState = { disabled: css` - switch-control { - composes: theme-switch--disabled mdc-switch--disabled from global; - } - `, + switch-control { + composes: theme-switch--disabled mdc-switch--disabled from global; + } + `, checked: css` - switch-control { - composes: theme-switch--checked mdc-switch--checked from global; - } - `, + switch-control { + composes: theme-switch--checked mdc-switch--checked from global; + } + `, }; interface IBaseProps { @@ -130,7 +127,7 @@ export const Switch: SwitchType = observer(function Switch({ switchStyles, ...mod.map(mod => switchMod[mod]), disabled && switchState.disabled, - checkboxState.checked && switchState.checked + checkboxState.checked && switchState.checked, ); if (autoHide && !isControlPresented(name, state)) { @@ -145,7 +142,7 @@ export const Switch: SwitchType = observer(function Switch({ - {children} + + {children} + {description && {description}} - + , ); }); diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/useCheckboxState.ts b/webapp/packages/core-blocks/src/FormControls/Checkboxes/useCheckboxState.ts index 460bcbed33..dfd7700304 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/useCheckboxState.ts +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/useCheckboxState.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { useContext, useState } from 'react'; import { useObjectRef } from '../../useObjectRef'; @@ -19,16 +18,16 @@ export type CheckboxStateOptions = { checked: boolean | undefined; defaultChecked: boolean | undefined; } & ( - { - state: undefined; - name: string | undefined; - onChange: CheckboxOnChangeEvent | undefined; - } | { - state: Record | undefined; - name: TKey; - onChange: CheckboxOnChangeEvent | undefined; - } + state: undefined; + name: string | undefined; + onChange: CheckboxOnChangeEvent | undefined; + } + | { + state: Record | undefined; + name: TKey; + onChange: CheckboxOnChangeEvent | undefined; + } ); interface ICheckboxState { @@ -57,35 +56,39 @@ export function useCheckboxState(options: CheckboxStateOpti } } - return useObjectRef(() => ({ - checked, - change(event: React.ChangeEvent) { - const { state, name, value, onChange, count, context } = optionsRef; - const checked = event.target.checked; + return useObjectRef( + () => ({ + checked, + change(event: React.ChangeEvent) { + const { state, name, value, onChange, count, context } = optionsRef; + const checked = event.target.checked; - if (state !== undefined && name !== undefined) { - const currentState = state[name as TKey]; + if (state !== undefined && name !== undefined) { + const currentState = state[name as TKey]; - if (typeof value === 'string') { - if (Array.isArray(currentState)) { - const elementIndex = currentState.indexOf(value); - if (checked && elementIndex === -1) { - currentState.push(value); - } else if (elementIndex !== -1) { - currentState.splice(elementIndex, 1); + if (typeof value === 'string') { + if (Array.isArray(currentState)) { + const elementIndex = currentState.indexOf(value); + if (checked && elementIndex === -1) { + currentState.push(value); + } else if (elementIndex !== -1) { + currentState.splice(elementIndex, 1); + } + } else { + state[name as TKey] = value; } } else { - state[name as TKey] = value; + state[name as TKey] = checked; } - } else { - state[name as TKey] = checked; } - } - onChange?.(checked, name as TKey); - context?.change(checked, name); + onChange?.(checked, name as TKey); + context?.change(checked, name); - refresh(count + 1); - }, - }), { checked }, ['change']); + refresh(count + 1); + }, + }), + { checked }, + ['change'], + ); } diff --git a/webapp/packages/core-blocks/src/FormControls/Combobox.tsx b/webapp/packages/core-blocks/src/FormControls/Combobox.tsx index 8a2a16f46f..520a125bf1 100644 --- a/webapp/packages/core-blocks/src/FormControls/Combobox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Combobox.tsx @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { useLayoutEffect, useCallback, useState, useRef, useContext, useEffect } from 'react'; -import { useMenuState, Menu, MenuItem, MenuButton } from 'reakit/Menu'; +import { useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from 'react'; +import { Menu, MenuButton, MenuItem, useMenuState } from 'reakit/Menu'; import styled, { css, use } from 'reshadow'; import { filterLayoutFakeProps } from '../Containers/filterLayoutFakeProps'; @@ -23,131 +22,134 @@ import { baseFormControlStyles, baseValidFormControlStyles } from './baseFormCon import { FormContext } from './FormContext'; const styles = css` - field[|inline] { - display: flex; - align-items: center; + field[|inline] { + display: flex; + align-items: center; - & field-label { - padding-right: 8px; - padding-bottom: 0; - } + & field-label { + padding-right: 8px; + padding-bottom: 0; } - field input { - margin: 0; + } + field input { + margin: 0; + } + field-label { + display: block; + padding-bottom: 10px; + composes: theme-typography--body1 from global; + font-weight: 500; + } + input { + padding-right: 24px !important; + } + MenuButton { + position: absolute; + right: 0; + background: transparent; + outline: none; + display: flex; + align-items: center; + height: 100%; + padding: 0 8px 0 0; + cursor: pointer; + &:hover, + &:focus { + opacity: 0.7; } - field-label { - display: block; - padding-bottom: 10px; - composes: theme-typography--body1 from global; - font-weight: 500; - } - input { - padding-right: 24px !important; - } - MenuButton { - position: absolute; - right: 0; + } + MenuItem { + composes: theme-ripple from global; + } + + Menu { + composes: theme-text-on-surface theme-background-surface theme-typography--caption theme-elevation-z3 from global; + display: flex; + flex-direction: column; + max-height: 300px; + overflow: auto; + outline: none; + z-index: 999; + border-radius: var(--theme-form-element-radius); + + & MenuItem { background: transparent; - outline: none; display: flex; + flex-direction: row; align-items: center; - height: 100%; - padding: 0 8px 0 0; + padding: 8px 12px; + text-align: left; + outline: none; + color: inherit; cursor: pointer; - &:hover, &:focus { - opacity: 0.7; + gap: 8px; + + & item-icon, + & item-title { + position: relative; } - } - MenuItem { - composes: theme-ripple from global; - } - Menu { - composes: theme-text-on-surface theme-background-surface theme-typography--caption theme-elevation-z3 from global; - display: flex; - flex-direction: column; - max-height: 300px; - overflow: auto; - outline: none; - z-index: 999; - border-radius: var(--theme-form-element-radius); + & item-icon { + width: 16px; + height: 16px; + overflow: hidden; + flex-shrink: 0; - & MenuItem { - background: transparent; - display: flex; - flex-direction: row; - align-items: center; - padding: 8px 12px; - text-align: left; - outline: none; - color: inherit; - cursor: pointer; - gap: 8px; - - & item-icon, & item-title { - position: relative; - } - - & item-icon { - width: 16px; - height: 16px; - overflow: hidden; - flex-shrink: 0; - - & IconOrImage { - width: 100%; - height: 100%; - } + & IconOrImage { + width: 100%; + height: 100%; } } } - Icon { + } + Icon { + height: 16px; + display: block; + } + MenuButton Icon[|focus] { + transform: rotate(180deg); + } + input-box { + flex: 1; + position: relative; + display: flex; + align-items: center; + + & input-icon { + position: absolute; + left: 0; + width: 16px; height: 16px; - display: block; - } - MenuButton Icon[|focus] { - transform: rotate(180deg); - } - input-box { - flex: 1; - position: relative; - display: flex; - align-items: center; + margin-left: 12px; - & input-icon { - position: absolute; - left: 0; - width: 16px; - height: 16px; - margin-left: 12px; + & IconOrImage { + width: 100%; + height: 100%; + } - & IconOrImage { - width: 100%; - height: 100%; - } - - &:not(:empty) + input { - padding-left: 34px !important; - } + &:not(:empty) + input { + padding-left: 34px !important; } } - `; + } +`; -type BaseProps = Omit, 'onChange' | 'onSelect' | 'name' | 'value' | 'defaultValue'> & ILayoutSizeProps & { - propertyName?: string; - items: TValue[]; - searchable?: boolean; - defaultValue?: TKey; - loading?: boolean; - description?: string; - keySelector?: (item: TValue, index: number) => TKey; - valueSelector?: (item: TValue) => string; - titleSelector?: (item: TValue) => string | undefined; - iconSelector?: (item: TValue) => string | React.ReactElement | undefined; - isDisabled?: (item: TValue) => boolean; - onSwitch?: (state: boolean) => void; - inline?: boolean; -}; +type BaseProps = Omit, 'onChange' | 'onSelect' | 'name' | 'value' | 'defaultValue'> & + ILayoutSizeProps & { + propertyName?: string; + items: TValue[]; + searchable?: boolean; + defaultValue?: TKey; + loading?: boolean; + description?: string; + keySelector?: (item: TValue, index: number) => TKey; + valueSelector?: (item: TValue) => string; + titleSelector?: (item: TValue) => string | undefined; + iconSelector?: (item: TValue) => string | React.ReactElement | undefined; + isDisabled?: (item: TValue) => boolean; + onSwitch?: (state: boolean) => void; + inline?: boolean; + }; type ControlledProps = BaseProps & { name?: string; @@ -191,7 +193,7 @@ export const Combobox: ComboboxType = observer(function Combobox({ iconSelector, titleSelector, isDisabled, - onChange = () => { }, + onChange = () => {}, onSelect, onSwitch, ...rest @@ -217,9 +219,7 @@ export const Combobox: ComboboxType = observer(function Combobox({ const [searchValue, setSearchValue] = useState(null); const filteredItems = getComputed(() => { - const result = items.filter( - item => !searchValue || valueSelector(item).toUpperCase().includes(searchValue.toUpperCase()) - ); + const result = items.filter(item => !searchValue || valueSelector(item).toUpperCase().includes(searchValue.toUpperCase())); if (isDisabled) { return result.sort((a, b) => Number(isDisabled(a)) - Number(isDisabled(b))); @@ -252,61 +252,73 @@ export const Combobox: ComboboxType = observer(function Combobox({ } } - const handleChange = useCallback((event: React.ChangeEvent) => { - const value = event.target.value; - onChange(value, name); - setSearchValue(value); - }, [name, onChange]); + const handleChange = useCallback( + (event: React.ChangeEvent) => { + const value = event.target.value; + onChange(value, name); + setSearchValue(value); + }, + [name, onChange], + ); - const handleSelect = useCallback((id: any) => { - id = id ?? value ?? ''; - const changed = id !== value; + const handleSelect = useCallback( + (id: any) => { + id = id ?? value ?? ''; + const changed = id !== value; - menu.hide(); - if (state && changed) { - state[name] = id; - } - if (onSelect && changed) { - onSelect(id, name, value); - } - if (context && changed) { - context.change(id, name); - } - setSearchValue(null); - }, [value, state, name, menu, context, onSelect]); - - const matchItems = useCallback((input?: boolean) => { - if (searchValue === null) { - return; - } - - if (filteredItems.length === 0) { - setSearchValue(null); - return; - } - - const filteredItemIndex = items.indexOf(filteredItems[0]); - - if (filteredItems.length === 1) { - handleSelect(keySelector(filteredItems[0], filteredItemIndex)); - return; - } - - if (filteredItems.length > 0) { - if (input) { - handleSelect(keySelector(filteredItems[0], filteredItemIndex)); - } else { - setSearchValue(null); + menu.hide(); + if (state && changed) { + state[name] = id; } - } - }, [items, filteredItems, keySelector, handleSelect, searchValue]); + if (onSelect && changed) { + onSelect(id, name, value); + } + if (context && changed) { + context.change(id, name); + } + setSearchValue(null); + }, + [value, state, name, menu, context, onSelect], + ); - const handleKeyDown = useCallback((event: React.KeyboardEvent) => { - if (event.key === 'Enter') { - event.preventDefault(); - matchItems(true); - } - }, [matchItems]); + const matchItems = useCallback( + (input?: boolean) => { + if (searchValue === null) { + return; + } + + if (filteredItems.length === 0) { + setSearchValue(null); + return; + } + + const filteredItemIndex = items.indexOf(filteredItems[0]); + + if (filteredItems.length === 1) { + handleSelect(keySelector(filteredItems[0], filteredItemIndex)); + return; + } + + if (filteredItems.length > 0) { + if (input) { + handleSelect(keySelector(filteredItems[0], filteredItemIndex)); + } else { + setSearchValue(null); + } + } + }, + [items, filteredItems, keySelector, handleSelect, searchValue], + ); + + const handleKeyDown = useCallback( + (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + event.preventDefault(); + matchItems(true); + } + }, + [matchItems], + ); useEffect(() => { if (inputRef === document.activeElement) { @@ -353,16 +365,15 @@ export const Combobox: ComboboxType = observer(function Combobox({ return styled(useStyles(baseFormControlStyles, baseValidFormControlStyles, styles))( - {children && {children}{rest.required && ' *'}} + {children && ( + + {children} + {rest.required && ' *'} + + )} {(icon || loading) && ( - - {loading ? ( - - ) : ( - typeof icon === 'string' ? : icon - )} - + {loading ? : typeof icon === 'string' ? : icon} )} - {!filteredItems.length - ? ( - - {translate('combobox_no_results_placeholder')} - - ) - : (filteredItems.map((item, index) => { + {!filteredItems.length ? ( + + {translate('combobox_no_results_placeholder')} + + ) : ( + filteredItems.map((item, index) => { const icon = iconSelector?.(item); const title = titleSelector?.(item); const disabled = isDisabled?.(item); @@ -406,28 +416,21 @@ export const Combobox: ComboboxType = observer(function Combobox({ handleSelect(event.currentTarget.id)} > - {iconSelector && ( - - {icon && typeof icon === 'string' ? : icon} - - )} + {iconSelector && {icon && typeof icon === 'string' ? : icon}} {valueSelector(item)} ); - }))} + }) + )} - {description && ( - - {description} - - )} - + {description && {description}} + , ); }); diff --git a/webapp/packages/core-blocks/src/FormControls/Filter.tsx b/webapp/packages/core-blocks/src/FormControls/Filter.tsx index 13d67cf383..3d437f34f0 100644 --- a/webapp/packages/core-blocks/src/FormControls/Filter.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Filter.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback, useEffect, useState } from 'react'; import styled, { css, use } from 'reshadow'; @@ -51,10 +50,10 @@ const filterStyles = css` `; const toggleModeButtonStyle = css` - IconButton { - composes: theme-background-primary theme-text-on-primary from global; - cursor: pointer; - } + IconButton { + composes: theme-background-primary theme-text-on-primary from global; + cursor: pointer; + } `; const innerInputStyle = css` @@ -108,17 +107,20 @@ export const Filter = observer>(functio const [inputRef, ref] = useFocus({}); const [toggled, setToggled] = useState(!toggleMode); - const filter = useCallback((value: string | number, name?: string) => { - value = String(value); + const filter = useCallback( + (value: string | number, name?: string) => { + value = String(value); - if (state && name) { - state[name] = value; - } + if (state && name) { + state[name] = value; + } - if (onFilter) { - onFilter(value, name); - } - }, [onFilter, state]); + if (onFilter) { + onFilter(value, name); + } + }, + [onFilter, state], + ); const toggle = useCallback(() => { if (!toggleMode) { @@ -161,12 +163,7 @@ export const Filter = observer>(functio onKeyDown={onKeyDown} {...use({ toggled, max })} /> - - + + , ); }); diff --git a/webapp/packages/core-blocks/src/FormControls/FormBox.tsx b/webapp/packages/core-blocks/src/FormControls/FormBox.tsx index 05d5897795..4fd120e961 100644 --- a/webapp/packages/core-blocks/src/FormControls/FormBox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/FormBox.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled, { css } from 'reshadow'; const styles = css` @@ -21,9 +20,5 @@ interface Props { } export const FormBox: React.FC> = function FormBox({ children, className }) { - return styled(styles)( - - {children} - - ); + return styled(styles)({children}); }; diff --git a/webapp/packages/core-blocks/src/FormControls/FormBoxElement.tsx b/webapp/packages/core-blocks/src/FormControls/FormBoxElement.tsx index c3abc77746..2f3582111b 100644 --- a/webapp/packages/core-blocks/src/FormControls/FormBoxElement.tsx +++ b/webapp/packages/core-blocks/src/FormControls/FormBoxElement.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled, { css, use } from 'reshadow'; const styles = css` @@ -26,8 +25,8 @@ interface Props { export const FormBoxElement: React.FC> = function FormBoxElement({ children, className, max }) { return styled(styles)( - + {children} - + , ); }; diff --git a/webapp/packages/core-blocks/src/FormControls/FormContext.ts b/webapp/packages/core-blocks/src/FormControls/FormContext.ts index a93a43d856..6714dfb38b 100644 --- a/webapp/packages/core-blocks/src/FormControls/FormContext.ts +++ b/webapp/packages/core-blocks/src/FormControls/FormContext.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createContext } from 'react'; import type { IExecutor } from '@cloudbeaver/core-executor'; diff --git a/webapp/packages/core-blocks/src/FormControls/FormFieldDescription.tsx b/webapp/packages/core-blocks/src/FormControls/FormFieldDescription.tsx index 07de072ac5..32ec829d25 100644 --- a/webapp/packages/core-blocks/src/FormControls/FormFieldDescription.tsx +++ b/webapp/packages/core-blocks/src/FormControls/FormFieldDescription.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled, { css } from 'reshadow'; import { filterLayoutFakeProps } from '../Containers/filterLayoutFakeProps'; @@ -42,10 +41,8 @@ export const FormFieldDescription: React.FC> = fu return styled(styles)( - {label && {label}} - - {children} - - + {label && {label}} + {children} + , ); }; diff --git a/webapp/packages/core-blocks/src/FormControls/FormGroup.tsx b/webapp/packages/core-blocks/src/FormControls/FormGroup.tsx index 1b2d54902d..0859fff033 100644 --- a/webapp/packages/core-blocks/src/FormControls/FormGroup.tsx +++ b/webapp/packages/core-blocks/src/FormControls/FormGroup.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled, { css } from 'reshadow'; const styles = css` @@ -20,9 +19,5 @@ interface Props { } export const FormGroup: React.FC> = function FormGroup({ children, className }) { - return styled(styles)( - - {children} - - ); + return styled(styles)({children}); }; diff --git a/webapp/packages/core-blocks/src/FormControls/InputField.tsx b/webapp/packages/core-blocks/src/FormControls/InputField.tsx index b7e05d785d..9afde055a8 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputField.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputField.tsx @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { forwardRef, useCallback, useContext, useState } from 'react'; -import styled, { use, css } from 'reshadow'; +import styled, { css, use } from 'reshadow'; import type { ComponentStyle } from '@cloudbeaver/core-theming'; @@ -25,55 +24,57 @@ import { isControlPresented } from './isControlPresented'; import { useCapsLockTracker } from './useCapsLockTracker'; const INPUT_FIELD_STYLES = css` - Icon { - composes: theme-text-on-secondary from global; - } - field-label { - display: block; - composes: theme-typography--body1 from global; - font-weight: 500; - } - field-label:not(:empty) { - padding-bottom: 10px; - } - input-container { - position: relative; - } - loader-container, icon-container { - position: absolute; - right: 8px; - top: 50%; - transform: translateY(-50%); - width: 24px; - height: 24px; - display: flex; - } - icon-container { - cursor: pointer; - & Icon { - width: 100%; - height: 100%; - } - } - input[disabled] + icon-container { - cursor: auto; - opacity: 0.8; - } - input:not(:only-child) { - padding-right: 32px !important; + Icon { + composes: theme-text-on-secondary from global; + } + field-label { + display: block; + composes: theme-typography--body1 from global; + font-weight: 500; + } + field-label:not(:empty) { + padding-bottom: 10px; + } + input-container { + position: relative; + } + loader-container, + icon-container { + position: absolute; + right: 8px; + top: 50%; + transform: translateY(-50%); + width: 24px; + height: 24px; + display: flex; + } + icon-container { + cursor: pointer; + & Icon { + width: 100%; + height: 100%; } + } + input[disabled] + icon-container { + cursor: auto; + opacity: 0.8; + } + input:not(:only-child) { + padding-right: 32px !important; + } `; -type BaseProps = Omit, 'onChange' | 'name' | 'value' | 'style'> & ILayoutSizeProps & { - error?: boolean; - loading?: boolean; - description?: string; - labelTooltip?: string; - mod?: 'surface'; - ref?: React.Ref; - style?: ComponentStyle; - onCustomCopy?: () => void; -}; +type BaseProps = Omit, 'onChange' | 'name' | 'value' | 'style'> & + ILayoutSizeProps & { + error?: boolean; + loading?: boolean; + description?: string; + labelTooltip?: string; + mod?: 'surface'; + ref?: React.Ref; + style?: ComponentStyle; + onCustomCopy?: () => void; + }; type ControlledProps = BaseProps & { name?: string; @@ -100,134 +101,128 @@ interface InputFieldType { (props: ObjectProps): React.ReactElement | null; } -export const InputField: InputFieldType = observer(forwardRef(function InputField({ - name, - style, - value: valueControlled, - defaultValue, - required, - state, - mapState, - mapValue, - children, - className, - error, - loading, - description, - labelTooltip, - mod, - fill, - small, - medium, - large, - tiny, - autoHide, - onChange, - onCustomCopy, - ...rest -}: ControlledProps | ObjectProps, ref: React.Ref) { - const capsLock = useCapsLockTracker(); - const [passwordRevealed, setPasswordRevealed] = useState(false); - const translate = useTranslate(); - const styles = useStyles( - baseFormControlStyles, - error ? baseInvalidFormControlStyles : baseValidFormControlStyles, - INPUT_FIELD_STYLES, - style - ); - const context = useContext(FormContext); - loading = useStateDelay(loading ?? false, 300); +export const InputField: InputFieldType = observer( + forwardRef(function InputField( + { + name, + style, + value: valueControlled, + defaultValue, + required, + state, + mapState, + mapValue, + children, + className, + error, + loading, + description, + labelTooltip, + mod, + fill, + small, + medium, + large, + tiny, + autoHide, + onChange, + onCustomCopy, + ...rest + }: ControlledProps | ObjectProps, + ref: React.Ref, + ) { + const capsLock = useCapsLockTracker(); + const [passwordRevealed, setPasswordRevealed] = useState(false); + const translate = useTranslate(); + const styles = useStyles(baseFormControlStyles, error ? baseInvalidFormControlStyles : baseValidFormControlStyles, INPUT_FIELD_STYLES, style); + const context = useContext(FormContext); + loading = useStateDelay(loading ?? false, 300); - const revealPassword = useCallback(() => { - if (rest.disabled) { - return; + const revealPassword = useCallback(() => { + if (rest.disabled) { + return; + } + + setPasswordRevealed(prev => !prev); + }, [rest.disabled]); + + const handleChange = useCallback( + (event: React.ChangeEvent) => { + const value = mapValue?.(event.target.value) ?? event.target.value; + + if (state) { + state[name] = value; + } + if (onChange) { + onChange(value, name); + } + if (context) { + context.change(value, name); + } + }, + [state, name, context, onChange], + ); + + const handleBlur = useCombinedHandler(rest.onBlur, capsLock.handleBlur); + const handleKeyDown = useCombinedHandler(rest.onKeyDown, capsLock.handleKeyDown, context?.keyDown); + + if (autoHide && !isControlPresented(name, state, defaultValue)) { + return null; } - setPasswordRevealed(prev => !prev); - }, [rest.disabled]); + let value: any = valueControlled ?? defaultValue ?? undefined; - const handleChange = useCallback((event: React.ChangeEvent) => { - const value = mapValue?.(event.target.value) ?? event.target.value; - - if (state) { - state[name] = value; + if (state && name !== undefined && name in state) { + value = state[name]; } - if (onChange) { - onChange(value, name); + + if (mapState) { + value = mapState(value); } - if (context) { - context.change(value, name); + + const showRevealPasswordButton = rest.type === 'password' && !rest.readOnly; + + if (showRevealPasswordButton && capsLock.warn) { + description = translate('ui_capslock_on'); } - }, [state, name, context, onChange]); - const handleBlur = useCombinedHandler(rest.onBlur, capsLock.handleBlur); - const handleKeyDown = useCombinedHandler(rest.onKeyDown, capsLock.handleKeyDown, context?.keyDown); - - if (autoHide && !isControlPresented(name, state, defaultValue)) { - return null; - } - - let value: any = valueControlled ?? defaultValue ?? undefined; - - if (state && name !== undefined && name in state) { - value = state[name]; - } - - if (mapState) { - value = mapState(value); - } - - const showRevealPasswordButton = rest.type === 'password' && !rest.readOnly; - - if (showRevealPasswordButton && capsLock.warn) { - description = translate('ui_capslock_on'); - } - - return styled(styles)( - - {children}{required && ' *'} - - - {loading && ( - - - - )} - {showRevealPasswordButton && ( - - - - )} - {onCustomCopy && ( - - - - )} - - {(description || showRevealPasswordButton) && ( - - {description} - - )} - - ); -})); + return styled(styles)( + + + {children} + {required && ' *'} + + + + {loading && ( + + + + )} + {showRevealPasswordButton && ( + + + + )} + {onCustomCopy && ( + + + + )} + + {(description || showRevealPasswordButton) && {description}} + , + ); + }), +); diff --git a/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.tsx b/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.tsx index 2e38251621..d60caaaf90 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { ReactNode, useContext, useState } from 'react'; import styled, { css, use } from 'reshadow'; @@ -67,9 +66,7 @@ interface Props extends ILayoutSizeProps { mapValue?: (value: string) => string; } -type InputFileTextContentType = >( - props: Props -) => React.ReactElement; +type InputFileTextContentType = >(props: Props) => React.ReactElement; export const InputFileTextContent: InputFileTextContentType = observer(function InputFileTextContent({ name, @@ -97,12 +94,7 @@ export const InputFileTextContent: InputFileTextContentType = observer(function const [selected, setSelected] = useState(null); const [error, setError] = useState(null); - const styles = useStyles( - INPUT_FILE_FIELD_STYLES, - baseFormControlStyles, - style, - error ? baseInvalidFormControlStyles : baseValidFormControlStyles - ); + const styles = useStyles(INPUT_FILE_FIELD_STYLES, baseFormControlStyles, style, error ? baseInvalidFormControlStyles : baseValidFormControlStyles); const savedExternally = !!fileName && state[name] !== ''; const saved = savedExternally || !!state[name]; @@ -138,10 +130,12 @@ export const InputFileTextContent: InputFileTextContentType = observer(function const maxFileSizeBytes = maxFileSize * 1024; if (size > maxFileSizeBytes) { - throw new Error(translate('ui_file_size_exceeds', undefined, { - size: bytesToSize(size), - maxSize: bytesToSize(maxFileSizeBytes), - })); + throw new Error( + translate('ui_file_size_exceeds', undefined, { + size: bytesToSize(size), + maxSize: bytesToSize(maxFileSizeBytes), + }), + ); } } @@ -170,21 +164,19 @@ export const InputFileTextContent: InputFileTextContentType = observer(function return styled(styles)( - {children}{required && ' *'} + + {children} + {required && ' *'} + - {description} - {(selected || saved) && } + {(selected || saved) && } - + , ); -}); \ No newline at end of file +}); diff --git a/webapp/packages/core-blocks/src/FormControls/InputFiles.tsx b/webapp/packages/core-blocks/src/FormControls/InputFiles.tsx index 34f1038e6e..115419e09d 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputFiles.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputFiles.tsx @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { forwardRef, useContext, useEffect, useState } from 'react'; -import styled, { use, css } from 'reshadow'; +import styled, { css, use } from 'reshadow'; import type { ComponentStyle } from '@cloudbeaver/core-theming'; @@ -27,36 +26,37 @@ import { FormContext } from './FormContext'; import { isControlPresented } from './isControlPresented'; const INPUT_FIELD_STYLES = css` - field-label { - display: block; - composes: theme-typography--body1 from global; - font-weight: 500; - } - field-label:not(:empty) { - padding-bottom: 10px; - } - input-container { - position: relative; - } - Tags { - padding-top: 8px; + field-label { + display: block; + composes: theme-typography--body1 from global; + font-weight: 500; + } + field-label:not(:empty) { + padding-bottom: 10px; + } + input-container { + position: relative; + } + Tags { + padding-top: 8px; - &:empty { - display: none; - } + &:empty { + display: none; } + } `; -type BaseProps = Omit, 'onChange' | 'name' | 'value' | 'style'> & ILayoutSizeProps & { - error?: boolean; - loading?: boolean; - description?: string; - labelTooltip?: string; - hideTags?: boolean; - mod?: 'surface'; - ref?: React.Ref; - style?: ComponentStyle; -}; +type BaseProps = Omit, 'onChange' | 'name' | 'value' | 'style'> & + ILayoutSizeProps & { + error?: boolean; + loading?: boolean; + description?: string; + labelTooltip?: string; + hideTags?: boolean; + mod?: 'surface'; + ref?: React.Ref; + style?: ComponentStyle; + }; type ControlledProps = BaseProps & { name?: string; @@ -79,128 +79,114 @@ interface InputFilesType { (props: ObjectProps): React.ReactElement | null; } -export const InputFiles: InputFilesType = observer(forwardRef(function InputFiles({ - name, - style, - value: valueControlled, - required, - state, - children, - className, - error, - loading, - description, - labelTooltip, - hideTags, - mod, - fill, - small, - medium, - large, - tiny, - autoHide, - onChange, - ...rest -}: ControlledProps | ObjectProps, refInherit: React.Ref) { - const ref = useRefInherit(refInherit); - const [innerState, setInnerState] = useState(null); - const translate = useTranslate(); - const styles = useStyles( - baseFormControlStyles, - error ? baseInvalidFormControlStyles : baseValidFormControlStyles, - INPUT_FIELD_STYLES, - style - ); - const context = useContext(FormContext); - loading = useStateDelay(loading ?? false, 300); +export const InputFiles: InputFilesType = observer( + forwardRef(function InputFiles( + { + name, + style, + value: valueControlled, + required, + state, + children, + className, + error, + loading, + description, + labelTooltip, + hideTags, + mod, + fill, + small, + medium, + large, + tiny, + autoHide, + onChange, + ...rest + }: ControlledProps | ObjectProps, + refInherit: React.Ref, + ) { + const ref = useRefInherit(refInherit); + const [innerState, setInnerState] = useState(null); + const translate = useTranslate(); + const styles = useStyles(baseFormControlStyles, error ? baseInvalidFormControlStyles : baseValidFormControlStyles, INPUT_FIELD_STYLES, style); + const context = useContext(FormContext); + loading = useStateDelay(loading ?? false, 300); - let value = valueControlled ?? innerState; + let value = valueControlled ?? innerState; - if (state && name !== undefined && name in state) { - value = state[name]; - } - - function setValue(value: FileList | null) { - setInnerState(value); - if (state) { - state[name] = value; - } - if (onChange) { - onChange(value, name); - } - if (context) { - context.change(value, name); - } - } - - const removeFile = useCombinedHandler(function removeFile(index: number): void { - if (!value) { - return; + if (state && name !== undefined && name in state) { + value = state[name]; } - const dt = new DataTransfer(); - - for (let i = 0; i < value.length; i++) { - const file = value[i]; - if (index !== i) { - dt.items.add(file); + function setValue(value: FileList | null) { + setInnerState(value); + if (state) { + state[name] = value; + } + if (onChange) { + onChange(value, name); + } + if (context) { + context.change(value, name); } } - setValue(dt.files.length === 0 ? null : dt.files); - }); + const removeFile = useCombinedHandler(function removeFile(index: number): void { + if (!value) { + return; + } - const handleChange = useCombinedHandler((event: React.ChangeEvent) => { - setValue(event.target.files); - }); + const dt = new DataTransfer(); - useEffect(() => { - if (value !== innerState) { - setInnerState(value); + for (let i = 0; i < value.length; i++) { + const file = value[i]; + if (index !== i) { + dt.items.add(file); + } + } + + setValue(dt.files.length === 0 ? null : dt.files); + }); + + const handleChange = useCombinedHandler((event: React.ChangeEvent) => { + setValue(event.target.files); + }); + + useEffect(() => { + if (value !== innerState) { + setInnerState(value); + } + }); + + if (autoHide && !isControlPresented(name, state)) { + return null; } - }); - if (autoHide && !isControlPresented(name, state)) { - return null; - } + const files = Array.from(value ?? []); - const files = Array.from(value ?? []); - - return styled(styles)( - - {children}{required && ' *'} - - - - - {!hideTags && ( - - {files.map((file, i) => ( - - ))} - - )} - - {description && ( - - {description} - - )} - - ); -})); + return styled(styles)( + + + {children} + {required && ' *'} + + + + + + {!hideTags && ( + + {files.map((file, i) => ( + + ))} + + )} + + {description && {description}} + , + ); + }), +); diff --git a/webapp/packages/core-blocks/src/FormControls/Radio.tsx b/webapp/packages/core-blocks/src/FormControls/Radio.tsx index c22a77d063..42b7beaa33 100644 --- a/webapp/packages/core-blocks/src/FormControls/Radio.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Radio.tsx @@ -5,9 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { useContext, useCallback } from 'react'; +import { useCallback, useContext } from 'react'; import styled, { css, use } from 'reshadow'; import { filterLayoutFakeProps } from '../Containers/filterLayoutFakeProps'; @@ -18,38 +17,38 @@ import { FormContext } from './FormContext'; import { RadioGroupContext } from './RadioGroupContext'; const radioStyles = css` - radio { - composes: theme-radio from global; + radio { + composes: theme-radio from global; + } + radio-background { + composes: theme-radio_background from global; + } + input { + composes: theme-radio_native-control from global; + } + radio-outer-circle { + composes: theme-radio_outer-circle from global; + } + radio-inner-circle { + composes: theme-radio_inner-circle from global; + } + radio-ripple { + composes: theme-radio_ripple from global; + } + field { + display: inline-flex; + align-items: center; + font-weight: 500; + padding: 7px 12px; + vertical-align: middle; + } + label { + cursor: pointer; + &[|disabled] { + cursor: auto; } - radio-background { - composes: theme-radio_background from global; - } - input { - composes: theme-radio_native-control from global; - } - radio-outer-circle { - composes: theme-radio_outer-circle from global; - } - radio-inner-circle { - composes: theme-radio_inner-circle from global; - } - radio-ripple { - composes: theme-radio_ripple from global; - } - field { - display: inline-flex; - align-items: center; - font-weight: 500; - padding: 7px 12px; - vertical-align: middle; - } - label { - cursor: pointer; - &[|disabled] { - cursor: auto; - } - } - `; + } +`; const radioMod = { primary: css` @@ -78,35 +77,34 @@ const radioMod = { height: 14px; } & radio-inner-circle { - border-width: 7px; + border-width: 7px; } } `, }; const noRippleStyles = css` - radio { - composes: theme-radio_no-ripple from global; - } - `; + radio { + composes: theme-radio_no-ripple from global; + } +`; const radioState = { disabled: css` - radio { - composes: theme-radio--disabled from global; - } - input { - opacity: 0 !important; - } - `, + radio { + composes: theme-radio--disabled from global; + } + input { + opacity: 0 !important; + } + `, }; -type BaseProps = Omit, 'onChange' | 'value' | 'checked'> -& ILayoutSizeProps -& { - mod?: Array; - ripple?: boolean; -}; +type BaseProps = Omit, 'onChange' | 'value' | 'checked'> & + ILayoutSizeProps & { + mod?: Array; + ripple?: boolean; + }; type ControlledProps = BaseProps & { value?: string | number; @@ -147,25 +145,28 @@ export const Radio: RadioType = observer(function Radio({ const name = context?.name || controlledName; - const handleChange = useCallback((event: React.ChangeEvent) => { - if (!event.target.checked) { - return; - } + const handleChange = useCallback( + (event: React.ChangeEvent) => { + if (!event.target.checked) { + return; + } - if (state) { - state[name] = value; - } + if (state) { + state[name] = value; + } - if (context) { - context.onChange(value); - } else if (formContext) { - formContext.change(value, name); - } + if (context) { + context.onChange(value); + } else if (formContext) { + formContext.change(value, name); + } - if (onChange) { - onChange(value, name); - } - }, [value, context, state, name, formContext, onChange]); + if (onChange) { + onChange(value, name); + } + }, + [value, context, state, name, formContext, onChange], + ); const id = controlledId ?? `${name}_${value}`; let checked = controlledChecked; @@ -178,31 +179,27 @@ export const Radio: RadioType = observer(function Radio({ checked = state[name] === value; } - return styled(useStyles( - baseFormControlStyles, - radioStyles, - ...(mod || []).map(mod => radioMod[mod]), - !ripple && noRippleStyles, - rest.disabled && radioState.disabled - ))( + return styled( + useStyles( + baseFormControlStyles, + radioStyles, + ...(mod || []).map(mod => radioMod[mod]), + !ripple && noRippleStyles, + rest.disabled && radioState.disabled, + ), + )( - + {ripple && } - - + + , ); }); diff --git a/webapp/packages/core-blocks/src/FormControls/RadioGroup.tsx b/webapp/packages/core-blocks/src/FormControls/RadioGroup.tsx index d5f69518ad..5ef4fc22bf 100644 --- a/webapp/packages/core-blocks/src/FormControls/RadioGroup.tsx +++ b/webapp/packages/core-blocks/src/FormControls/RadioGroup.tsx @@ -5,14 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { - useCallback, useMemo, useState, useContext -} from 'react'; +import { useCallback, useContext, useMemo, useState } from 'react'; import { FormContext } from './FormContext'; -import { RadioGroupContext, IRadioGroupContext } from './RadioGroupContext'; +import { IRadioGroupContext, RadioGroupContext } from './RadioGroupContext'; type BaseProps = React.PropsWithChildren<{ name: string; @@ -48,33 +45,35 @@ export const RadioGroup: RadioGroupType = observer(function RadioGroup({ const formContext = useContext(FormContext); const [selfValue, setValue] = useState(); - const handleChange = useCallback((value: string | number) => { - if (state) { - state[name] = value; - } else { - setValue(value); - } + const handleChange = useCallback( + (value: string | number) => { + if (state) { + state[name] = value; + } else { + setValue(value); + } - if (onChange) { - onChange(value, name); - } + if (onChange) { + onChange(value, name); + } - if (formContext) { - formContext.change(value, name); - } - }, [name, state, formContext, onChange]); + if (formContext) { + formContext.change(value, name); + } + }, + [name, state, formContext, onChange], + ); const value = state ? state[name] : controlledValue ?? selfValue; - const context: IRadioGroupContext = useMemo(() => ({ - name, - value, - onChange: handleChange, - }), [value, value, handleChange]); - - return ( - - {children} - + const context: IRadioGroupContext = useMemo( + () => ({ + name, + value, + onChange: handleChange, + }), + [value, value, handleChange], ); + + return {children}; }); diff --git a/webapp/packages/core-blocks/src/FormControls/RadioGroupContext.ts b/webapp/packages/core-blocks/src/FormControls/RadioGroupContext.ts index 5e0979f4a2..1cc97975e1 100644 --- a/webapp/packages/core-blocks/src/FormControls/RadioGroupContext.ts +++ b/webapp/packages/core-blocks/src/FormControls/RadioGroupContext.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createContext } from 'react'; export interface IRadioGroupContext { diff --git a/webapp/packages/core-blocks/src/FormControls/ShadowInput.tsx b/webapp/packages/core-blocks/src/FormControls/ShadowInput.tsx index cdb9242bff..86ebd34c65 100644 --- a/webapp/packages/core-blocks/src/FormControls/ShadowInput.tsx +++ b/webapp/packages/core-blocks/src/FormControls/ShadowInput.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { forwardRef } from 'react'; type ShadowInputProps = Omit, 'onChange' | 'children'> & { @@ -14,17 +13,6 @@ type ShadowInputProps = Omit, 'onCha className?: string; }; -export const ShadowInput = forwardRef(function ShadowInput({ - onChange, - children, - ...rest -}, ref) { - return ( - onChange?.(e.target.value)} - {...rest} - /> - ); +export const ShadowInput = forwardRef(function ShadowInput({ onChange, children, ...rest }, ref) { + return onChange?.(e.target.value)} {...rest} />; }); diff --git a/webapp/packages/core-blocks/src/FormControls/SubmittingForm.tsx b/webapp/packages/core-blocks/src/FormControls/SubmittingForm.tsx index 226927faea..be627f6e76 100644 --- a/webapp/packages/core-blocks/src/FormControls/SubmittingForm.tsx +++ b/webapp/packages/core-blocks/src/FormControls/SubmittingForm.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React, { forwardRef, useContext, useState } from 'react'; import { Executor } from '@cloudbeaver/core-executor'; @@ -29,15 +28,8 @@ type FormDetailedProps = Omit(function SubmittingForm( - { - disabled: disabledProp, - disableEnterSubmit, - children, - onSubmit, - onChange = () => {}, - ...rest - }, - ref + { disabled: disabledProp, disableEnterSubmit, children, onSubmit, onChange = () => {}, ...rest }, + ref, ) { const [formRef, setFormInnerRef] = useState(null); const setFormRef = useCombinedRef(setFormInnerRef, ref); @@ -45,57 +37,63 @@ export const SubmittingForm = forwardRef(fun disabled = disabled || disabledProp || false; - const props = useObjectRef(() => ({ - handleSubmit(e: React.FormEvent) { - e.preventDefault(); + const props = useObjectRef( + () => ({ + handleSubmit(e: React.FormEvent) { + e.preventDefault(); - setDisabled(true); - const result = this.onSubmit?.(e); + setDisabled(true); + const result = this.onSubmit?.(e); - if (result instanceof Promise) { - result.finally(() => { setDisabled(false); }); - } else { - setDisabled(false); - } + if (result instanceof Promise) { + result.finally(() => { + setDisabled(false); + }); + } else { + setDisabled(false); + } + }, + }), + { + formRef, + disableEnterSubmit, + parentContext: useContext(FormContext), + onChange, + onSubmit, }, - }), { - formRef, - disableEnterSubmit, - parentContext: useContext(FormContext), - onChange, - onSubmit, - }, ['handleSubmit']); + ['handleSubmit'], + ); - const context = useObjectRef(() => ({ - changeExecutor: new Executor(), - change(value, name) { - props.onChange(value, name); - props.parentContext?.change(value, name); - this.changeExecutor.execute({ value, name }); - }, - keyDown(event: React.KeyboardEvent) { - if (event.key === 'Enter') { - const form = event.currentTarget.closest('form'); - if (form) { - event.preventDefault(); - const submitButton = form.querySelector( - 'button[type=submit]' - ); - if (submitButton) { - submitButton.click(); + const context = useObjectRef( + () => ({ + changeExecutor: new Executor(), + change(value, name) { + props.onChange(value, name); + props.parentContext?.change(value, name); + this.changeExecutor.execute({ value, name }); + }, + keyDown(event: React.KeyboardEvent) { + if (event.key === 'Enter') { + const form = event.currentTarget.closest('form'); + if (form) { + event.preventDefault(); + const submitButton = form.querySelector('button[type=submit]'); + if (submitButton) { + submitButton.click(); + } } } - } - props.parentContext?.keyDown(event); - }, - }), false, ['change', 'keyDown']); + props.parentContext?.keyDown(event); + }, + }), + false, + ['change', 'keyDown'], + ); return (
props.handleSubmit(e)}>
- - {children} - + {children}
+ - !grantedSubjects.includes(item)} - size='big' - > +
!grantedSubjects.includes(item)} size="big"> {!connections.length && filterState.filterValue && ( - - - {translate('ui_search_no_result_placeholder')} - + + {translate('ui_search_no_result_placeholder')} )} {connections.map(connection => { @@ -130,6 +120,6 @@ export const ConnectionList = observer(function ConnectionList({
- + , ); }); 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 b0dd484a89..2f65bbd2fb 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 @@ -5,14 +5,23 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useEffect } from 'react'; import styled, { css } from 'reshadow'; import { - BASE_CONTAINERS_STYLES, ColoredContainer, Container, getComputed, Group, - InfoItem, Loader, TextPlaceholder, useAutoLoad, useResource, useStyles, useTranslate + BASE_CONTAINERS_STYLES, + ColoredContainer, + Container, + getComputed, + Group, + InfoItem, + Loader, + TextPlaceholder, + useAutoLoad, + useResource, + useStyles, + useTranslate, } from '@cloudbeaver/core-blocks'; import { Connection, ConnectionInfoProjectKey, ConnectionInfoResource, DBDriverResource, isCloudConnection } from '@cloudbeaver/core-connections'; import type { TLocalizationToken } from '@cloudbeaver/core-localization'; @@ -41,10 +50,7 @@ const styles = css` } `; -export const GrantedConnections: TabContainerPanelComponent = observer(function GrantedConnections({ - tabId, - state: formState, -}) { +export const GrantedConnections: TabContainerPanelComponent = observer(function GrantedConnections({ tabId, state: formState }) { const style = useStyles(BASE_CONTAINERS_STYLES, styles); const translate = useTranslate(); @@ -55,30 +61,16 @@ export const GrantedConnections: TabContainerPanelComponent = ob const projects = useResource(GrantedConnections, ProjectInfoResource, CachedMapAllKey); const globalConnectionsKey = ConnectionInfoProjectKey( - ...(projects.data as Array) - .filter(isGlobalProject) - .map(project => project.id) + ...(projects.data as Array).filter(isGlobalProject).map(project => project.id), ); - useResource( - GrantedConnections, - DBDriverResource, - CachedMapAllKey, - { active: selected } - ); + useResource(GrantedConnections, DBDriverResource, CachedMapAllKey, { active: selected }); - const connectionsLoader = useResource( - GrantedConnections, - ConnectionInfoResource, - globalConnectionsKey, - { active: selected } - ); + const connectionsLoader = useResource(GrantedConnections, ConnectionInfoResource, globalConnectionsKey, { active: selected }); const connections = connectionsLoader.data as Connection[]; - const grantedConnections = getComputed(() => connections - .filter(connection => state.state.grantedSubjects.includes(connection.id)) - ); + const grantedConnections = getComputed(() => connections.filter(connection => state.state.grantedSubjects.includes(connection.id))); useAutoLoad(state, selected && !loaded); @@ -100,35 +92,37 @@ export const GrantedConnections: TabContainerPanelComponent = ob return styled(style)( - {() => styled(style)( - - {!connections.length ? ( - - {translate('administration_teams_team_granted_connections_empty')} - - ) : ( - <> - {info && } - - - {state.state.editing && ( - + styled(style)( + + {!connections.length ? ( + + {translate('administration_teams_team_granted_connections_empty')} + + ) : ( + <> + {info && } + + - )} - - - )} - - )} - + {state.state.editing && ( + + )} + + + )} + , + ) + } + , ); }); 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 ba8cb9f52f..adc825277b 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 @@ -5,59 +5,59 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useCallback, useState } from 'react'; import styled, { css } from 'reshadow'; import { + BASE_CONTAINERS_STYLES, + Button, + getComputed, + getSelectedItems, + Group, Table, TableBody, - TableItem, TableColumnValue, - BASE_CONTAINERS_STYLES, - Group, - Button, + TableItem, useObjectRef, - getSelectedItems, - getComputed, + useStyles, useTranslate, - useStyles } from '@cloudbeaver/core-blocks'; import { Connection, DBDriverResource } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import type { TLocalizationToken } from '@cloudbeaver/core-localization'; - import { getFilteredConnections } from './getFilteredConnections'; import { GrantedConnectionsTableHeader, IFilterState } from './GrantedConnectionsTableHeader/GrantedConnectionsTableHeader'; import { GrantedConnectionsTableInnerHeader } from './GrantedConnectionsTableHeader/GrantedConnectionsTableInnerHeader'; import { GrantedConnectionsTableItem } from './GrantedConnectionsTableItem'; const styles = css` - Group { - position: relative; - } - Group, container, table-container { - height: 100%; - } - container { - display: flex; - flex-direction: column; - width: 100%; - } - GrantedConnectionsTableHeader { - flex: 0 0 auto; - } - table-container { - overflow: auto; - } - Table { - composes: theme-background-surface theme-text-on-surface from global; - width: 100%; - } - `; + Group { + position: relative; + } + Group, + container, + table-container { + height: 100%; + } + container { + display: flex; + flex-direction: column; + width: 100%; + } + GrantedConnectionsTableHeader { + flex: 0 0 auto; + } + table-container { + overflow: auto; + } + Table { + composes: theme-background-surface theme-text-on-surface from global; + width: 100%; + } +`; interface Props { grantedConnections: Connection[]; @@ -66,12 +66,7 @@ interface Props { onEdit: () => void; } -export const GrantedConnectionList = observer(function GrantedConnectionList({ - grantedConnections, - disabled, - onRevoke, - onEdit, -}) { +export const GrantedConnectionList = observer(function GrantedConnectionList({ grantedConnections, disabled, onRevoke, onEdit }) { const props = useObjectRef({ onRevoke, onEdit }); const style = useStyles(styles, BASE_CONTAINERS_STYLES); const translate = useTranslate(); @@ -104,18 +99,20 @@ export const GrantedConnectionList = observer(function GrantedConnectionL - - + + - +
{tableInfoText && ( - - - {translate(tableInfoText)} - + + {translate(tableInfoText)} )} {connections.map(connection => { @@ -136,6 +133,6 @@ export const GrantedConnectionList = observer(function GrantedConnectionL
-
+ , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTabService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTabService.ts index c83c829490..2f8894c3d8 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTabService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTabService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; import { TeamsResource } from '@cloudbeaver/core-authentication'; @@ -35,7 +34,7 @@ export class GrantedConnectionsTabService extends Bootstrap { private readonly teamsResource: TeamsResource, private readonly graphQLService: GraphQLService, private readonly notificationService: NotificationService, - private readonly projectInfoResource: ProjectInfoResource + private readonly projectInfoResource: ProjectInfoResource, ) { super(); this.key = 'granted-connections'; @@ -52,15 +51,12 @@ export class GrantedConnectionsTabService extends Bootstrap { panel: () => GrantedConnections, }); - this.teamFormService.afterFormSubmittingTask.addHandler(executorHandlerFilter( - () => this.isEnabled(), - this.save.bind(this) - )); + this.teamFormService.afterFormSubmittingTask.addHandler(executorHandlerFilter(() => this.isEnabled(), this.save.bind(this))); this.teamFormService.configureTask.addHandler(() => this.projectInfoResource.load(CachedMapAllKey)); } - load(): Promise | void { } + load(): Promise | void {} private isEnabled(): boolean { return this.projectInfoResource.values.some(isGlobalProject); @@ -76,10 +72,7 @@ export class GrantedConnectionsTabService extends Bootstrap { }); } - private async save( - data: ITeamFormSubmitData, - contexts: IExecutionContextProvider - ) { + private async save(data: ITeamFormSubmitData, contexts: IExecutionContextProvider) { const config = contexts.getContext(teamContext); const status = contexts.getContext(this.teamFormService.configurationStatusContext); @@ -87,11 +80,7 @@ export class GrantedConnectionsTabService extends Bootstrap { return; } - const state = this.teamFormService.tabsContainer.getTabState( - data.state.partsState, - this.key, - { state: data.state } - ); + const state = this.teamFormService.tabsContainer.getTabState(data.state.partsState, this.key, { state: data.state }); if (!config.teamId || !state.loaded) { return; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableHeader.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableHeader.tsx index 8a54e85318..e99c1e56f7 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableHeader.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableHeader.tsx @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { Filter, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { Filter, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; export interface IFilterState { filterValue: string; @@ -22,24 +21,24 @@ interface Props extends React.PropsWithChildren { } const styles = css` - buttons { - display: flex; - gap: 16px; - } - header { - composes: theme-border-color-background theme-background-surface theme-text-on-surface from global; - overflow: hidden; - position: sticky; - top: 0; - z-index: 1; - display: flex; - align-items: center; - justify-content: space-between; - padding: 16px; - gap: 16px; - border-bottom: 1px solid; - } - `; + buttons { + display: flex; + gap: 16px; + } + header { + composes: theme-border-color-background theme-background-surface theme-text-on-surface from global; + overflow: hidden; + position: sticky; + top: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px; + gap: 16px; + border-bottom: 1px solid; + } +`; export const GrantedConnectionsTableHeader = observer(function GrantedConnectionsTableHeader({ filterState, disabled, className, children }) { const translate = useTranslate(); @@ -48,12 +47,10 @@ export const GrantedConnectionsTableHeader = observer(function GrantedCon - - {children} - - + {children} + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableInnerHeader.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableInnerHeader.tsx index c48c1d4bb5..0767ff42d0 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableInnerHeader.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableInnerHeader.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { TableColumnHeader, TableHeader, TableSelect, useTranslate } from '@cloudbeaver/core-blocks'; @@ -15,13 +14,12 @@ interface Props { className?: string; } - export const GrantedConnectionsTableInnerHeader = observer(function GrantedConnectionsTableInnerHeader({ disabled, className }) { const translate = useTranslate(); return ( - + {translate('connections_connection_name')} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableItem.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableItem.tsx index 7c1d71680d..efb35abf6d 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableItem.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableItem.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -30,22 +29,27 @@ const style = css` `; export const GrantedConnectionsTableItem = observer(function GrantedConnectionsTableItem({ - id, name, host, icon, iconTooltip, tooltip, disabled, className, + id, + name, + host, + icon, + iconTooltip, + tooltip, + disabled, + className, }) { return styled(style)( - + - {icon && } - {name} + + {icon && } + + + {name} + {host && host} - + , ); }); 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 047c3e36e8..2853036bb2 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,7 +5,6 @@ * 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 } from '@cloudbeaver/core-sdk'; @@ -13,13 +12,8 @@ import type { DatabaseConnectionFragment } from '@cloudbeaver/core-sdk'; * @param {DatabaseConnectionFragment[]} connections * @param {string} filter */ -export function getFilteredConnections( - connections: DatabaseConnectionFragment[], - filter: string -): DatabaseConnectionFragment[] { +export function getFilteredConnections(connections: DatabaseConnectionFragment[], filter: string): DatabaseConnectionFragment[] { return connections - .filter( - connection => connection.name.toLowerCase().includes(filter.toLowerCase()) && !isCloudConnection(connection) - ) - .sort((a, b) => (a.name).localeCompare(b.name)); + .filter(connection => connection.name.toLowerCase().includes(filter.toLowerCase()) && !isCloudConnection(connection)) + .sort((a, b) => a.name.localeCompare(b.name)); } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/useGrantedConnections.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/useGrantedConnections.tsx index 9a52c25c1e..66f3f2478e 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/useGrantedConnections.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/useGrantedConnections.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, computed, observable } from 'mobx'; import { TeamInfo, TeamsResource } from '@cloudbeaver/core-authentication'; @@ -32,51 +31,53 @@ export function useGrantedConnections(team: TeamInfo, mode: TeamFormMode): Reado const notificationService = useService(NotificationService); const state = useTabState(); - return useObservableRef(() => ({ - get changed() { - return !isArraysEqual(this.state.initialGrantedSubjects, this.state.grantedSubjects); - }, - isLoading() { - return this.state.loading; - }, - isLoaded() { - return this.state.loaded; - }, - isError() { - return false; - }, - edit() { - this.state.editing = !this.state.editing; - }, - grant(subjectIds: string[]) { - this.state.grantedSubjects.push(...subjectIds); - }, - revoke(subjectIds: string[]) { - this.state.grantedSubjects = this.state.grantedSubjects.filter(subject => !subjectIds.includes(subject)); - }, - async load() { - if (this.state.loaded || this.state.loading) { - return; - } - - try { - this.state.loading = true; - - if (this.mode === 'edit') { - const grantInfo = await this.resource.getSubjectConnectionAccess(this.team.teamId); - this.state.grantedSubjects = grantInfo.map(subject => subject.dataSourceId); - this.state.initialGrantedSubjects = this.state.grantedSubjects.slice(); + return useObservableRef( + () => ({ + get changed() { + return !isArraysEqual(this.state.initialGrantedSubjects, this.state.grantedSubjects); + }, + isLoading() { + return this.state.loading; + }, + isLoaded() { + return this.state.loaded; + }, + isError() { + return false; + }, + edit() { + this.state.editing = !this.state.editing; + }, + grant(subjectIds: string[]) { + this.state.grantedSubjects.push(...subjectIds); + }, + revoke(subjectIds: string[]) { + this.state.grantedSubjects = this.state.grantedSubjects.filter(subject => !subjectIds.includes(subject)); + }, + async load() { + if (this.state.loaded || this.state.loading) { + return; } - this.state.loaded = true; - } catch (exception: any) { - this.notificationService.logException(exception, `Error getting granted connections for "${this.team.teamId}"`); - } finally { - this.state.loading = false; - } - }, - }), - { state: observable.ref, changed: computed, grant: action.bound, revoke: action.bound, edit: action.bound }, - { state, team, mode, resource, notificationService }, - ['load']); + try { + this.state.loading = true; + + if (this.mode === 'edit') { + const grantInfo = await this.resource.getSubjectConnectionAccess(this.team.teamId); + this.state.grantedSubjects = grantInfo.map(subject => subject.dataSourceId); + this.state.initialGrantedSubjects = this.state.grantedSubjects.slice(); + } + + this.state.loaded = true; + } catch (exception: any) { + this.notificationService.logException(exception, `Error getting granted connections for "${this.team.teamId}"`); + } finally { + this.state.loading = false; + } + }, + }), + { state: observable.ref, changed: computed, grant: action.bound, revoke: action.bound, edit: action.bound }, + { state, team, mode, resource, notificationService }, + ['load'], + ); } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUserList.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUserList.tsx index eacbfb3ca4..3e8317b69e 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUserList.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUserList.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useCallback, useState } from 'react'; @@ -13,51 +12,52 @@ import styled, { css } from 'reshadow'; import { UsersResource } from '@cloudbeaver/core-authentication'; import { - Table, - TableBody, - TableItem, - TableColumnValue, BASE_CONTAINERS_STYLES, - Group, Button, - useObjectRef, getComputed, getSelectedItems, + Group, + Table, + TableBody, + TableColumnValue, + TableItem, + useObjectRef, + useStyles, useTranslate, - useStyles } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import type { TLocalizationToken } from '@cloudbeaver/core-localization'; import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; - import { getFilteredUsers } from './getFilteredUsers'; import { GrantedUsersTableHeader, IFilterState } from './GrantedUsersTableHeader/GrantedUsersTableHeader'; import { GrantedUsersTableInnerHeader } from './GrantedUsersTableHeader/GrantedUsersTableInnerHeader'; import { GrantedUsersTableItem } from './GrantedUsersTableItem'; const styles = css` - Table { - composes: theme-background-surface theme-text-on-surface from global; - } - Group { - position: relative; - } - Group, container, table-container { - height: 100%; - } - container { - display: flex; - flex-direction: column; - width: 100%; - } - GrantedUsersTableHeader { - flex: 0 0 auto; - } - table-container { - overflow: auto; - } - `; + Table { + composes: theme-background-surface theme-text-on-surface from global; + } + Group { + position: relative; + } + Group, + container, + table-container { + height: 100%; + } + container { + display: flex; + flex-direction: column; + width: 100%; + } + GrantedUsersTableHeader { + flex: 0 0 auto; + } + table-container { + overflow: auto; + } +`; interface Props { grantedUsers: AdminUserInfoFragment[]; @@ -66,9 +66,7 @@ interface Props { onEdit: () => void; } -export const GrantedUserList = observer(function GrantedUserList({ - grantedUsers, disabled, onRevoke, onEdit, -}) { +export const GrantedUserList = observer(function GrantedUserList({ grantedUsers, disabled, onRevoke, onEdit }) { const props = useObjectRef({ onRevoke, onEdit }); const style = useStyles(styles, BASE_CONTAINERS_STYLES); const translate = useTranslate(); @@ -101,22 +99,20 @@ export const GrantedUserList = observer(function GrantedUserList({ - - + + - !usersResource.isActiveUser(item)} - > +
!usersResource.isActiveUser(item)}> {tableInfoText && ( - - - {translate(tableInfoText)} - + + {translate(tableInfoText)} )} {users.map(user => { @@ -127,7 +123,7 @@ export const GrantedUserList = observer(function GrantedUserList({ id={user.userId} name={`${user.userId}${activeUser ? ' (you)' : ''}`} tooltip={activeUser ? translate('administration_teams_team_granted_users_permission_denied') : user.userId} - icon='/icons/user.svg' + icon="/icons/user.svg" iconTooltip={translate('authentication_user_icon_tooltip')} disabled={disabled} /> @@ -137,6 +133,6 @@ export const GrantedUserList = observer(function GrantedUserList({
-
+ , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.tsx index 903818861a..dcc3a85422 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.tsx @@ -5,19 +5,27 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; import { AdminUser, UsersResource } from '@cloudbeaver/core-authentication'; import { - BASE_CONTAINERS_STYLES, ColoredContainer, Container, getComputed, Group, - InfoItem, Loader, TextPlaceholder, useAutoLoad, useResource, useStyles, useTranslate + BASE_CONTAINERS_STYLES, + ColoredContainer, + Container, + getComputed, + Group, + InfoItem, + Loader, + TextPlaceholder, + useAutoLoad, + useResource, + useStyles, + useTranslate, } from '@cloudbeaver/core-blocks'; import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; import { TabContainerPanelComponent, useTab } from '@cloudbeaver/core-ui'; - import type { ITeamFormProps } from '../ITeamFormProps'; import { GrantedUserList } from './GrantedUserList'; import { useGrantedUsers } from './useGrantedUsers'; @@ -39,10 +47,7 @@ const styles = css` } `; -export const GrantedUsers: TabContainerPanelComponent = observer(function GrantedUsers({ - tabId, - state: formState, -}) { +export const GrantedUsers: TabContainerPanelComponent = observer(function GrantedUsers({ tabId, state: formState }) { const style = useStyles(BASE_CONTAINERS_STYLES, styles); const translate = useTranslate(); @@ -51,8 +56,8 @@ export const GrantedUsers: TabContainerPanelComponent = observer const users = useResource(GrantedUsers, UsersResource, CachedMapAllKey, { active: selected }); - const grantedUsers = getComputed(() => users.data - .filter((user): user is AdminUser => !!user && state.state.grantedUsers.includes(user.userId)) + const grantedUsers = getComputed(() => + users.data.filter((user): user is AdminUser => !!user && state.state.grantedUsers.includes(user.userId)), ); useAutoLoad(state, selected && !state.state.loaded); @@ -63,35 +68,32 @@ export const GrantedUsers: TabContainerPanelComponent = observer return styled(style)( - {() => styled(style)( - - {!users.resource.values.length ? ( - - {translate('administration_teams_team_granted_users_empty')} - - ) : ( - <> - {formState.mode === 'edit' && state.changed && } - - - {state.state.editing && ( - - )} - - - )} - - )} - + {() => + styled(style)( + + {!users.resource.values.length ? ( + + {translate('administration_teams_team_granted_users_empty')} + + ) : ( + <> + {formState.mode === 'edit' && state.changed && } + + + {state.state.editing && ( + + )} + + + )} + , + ) + } + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTabService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTabService.ts index 7b25c3d0e7..d5fd23360b 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTabService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTabService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; import { TeamsResource, UsersResource } from '@cloudbeaver/core-authentication'; @@ -32,7 +31,7 @@ export class GrantedUsersTabService extends Bootstrap { private readonly teamFormService: TeamFormService, private readonly usersResource: UsersResource, private readonly teamsResource: TeamsResource, - private readonly notificationService: NotificationService + private readonly notificationService: NotificationService, ) { super(); this.key = 'granted-users'; @@ -51,7 +50,7 @@ export class GrantedUsersTabService extends Bootstrap { this.teamFormService.afterFormSubmittingTask.addHandler(this.save.bind(this)); } - load(): void { } + load(): void {} private stateGetter(context: ITeamFormProps): MetadataValueGetter { return () => ({ @@ -63,10 +62,7 @@ export class GrantedUsersTabService extends Bootstrap { }); } - private async save( - data: ITeamFormSubmitData, - contexts: IExecutionContextProvider - ) { + private async save(data: ITeamFormSubmitData, contexts: IExecutionContextProvider) { const config = contexts.getContext(teamContext); const status = contexts.getContext(this.teamFormService.configurationStatusContext); @@ -74,11 +70,7 @@ export class GrantedUsersTabService extends Bootstrap { return; } - const state = this.teamFormService.tabsContainer.getTabState( - data.state.partsState, - this.key, - { state: data.state } - ); + const state = this.teamFormService.tabsContainer.getTabState(data.state.partsState, this.key, { state: data.state }); if (!config.teamId || !state.loaded) { return; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableHeader.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableHeader.tsx index 7945fd99af..daa9300d5f 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableHeader.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableHeader.tsx @@ -5,13 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { Filter, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; - - +import { Filter, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; export interface IFilterState { filterValue: string; @@ -24,24 +21,24 @@ interface Props extends React.PropsWithChildren { } const styles = css` - buttons { - display: flex; - gap: 16px; - } - header { - composes: theme-border-color-background theme-background-surface theme-text-on-surface from global; - overflow: hidden; - position: sticky; - top: 0; - z-index: 1; - display: flex; - align-items: center; - justify-content: space-between; - padding: 16px; - gap: 16px; - border-bottom: 1px solid; - } - `; + buttons { + display: flex; + gap: 16px; + } + header { + composes: theme-border-color-background theme-background-surface theme-text-on-surface from global; + overflow: hidden; + position: sticky; + top: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px; + gap: 16px; + border-bottom: 1px solid; + } +`; export const GrantedUsersTableHeader = observer(function GrantedUsersTableHeader({ filterState, disabled, className, children }) { const translate = useTranslate(); @@ -50,12 +47,10 @@ export const GrantedUsersTableHeader = observer(function GrantedUsersTabl - - {children} - - + {children} + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableInnerHeader.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableInnerHeader.tsx index 55f5de45bd..ad33b5345e 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableInnerHeader.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableInnerHeader.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { TableColumnHeader, TableHeader, TableSelect, useTranslate } from '@cloudbeaver/core-blocks'; @@ -21,7 +20,7 @@ export const GrantedUsersTableInnerHeader = observer(function GrantedUser return ( - + {translate('administration_teams_team_granted_users_user_id')} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableItem.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableItem.tsx index 20c0086b22..abb9f21102 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableItem.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableItem.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -28,22 +27,16 @@ const style = css` } `; -export const GrantedUsersTableItem = observer(function GrantedUsersTableItem({ - id, name, icon, iconTooltip, tooltip, disabled, className, -}) { +export const GrantedUsersTableItem = observer(function GrantedUsersTableItem({ id, name, icon, iconTooltip, tooltip, disabled, className }) { return styled(style)( - + - + + + {name} - + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/UserList.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/UserList.tsx index 33bea3aa3d..f46e665edf 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/UserList.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/UserList.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useCallback, useState } from 'react'; @@ -13,50 +12,51 @@ import styled, { css } from 'reshadow'; import { UsersResource } from '@cloudbeaver/core-authentication'; import { - Table, - TableBody, - TableItem, - TableColumnValue, BASE_CONTAINERS_STYLES, - Group, Button, - useObjectRef, getComputed, getSelectedItems, - useTranslate, + Group, + Table, + TableBody, + TableColumnValue, + TableItem, + useObjectRef, useStyles, + useTranslate, } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; - import { getFilteredUsers } from './getFilteredUsers'; import { GrantedUsersTableHeader, IFilterState } from './GrantedUsersTableHeader/GrantedUsersTableHeader'; import { GrantedUsersTableInnerHeader } from './GrantedUsersTableHeader/GrantedUsersTableInnerHeader'; import { GrantedUsersTableItem } from './GrantedUsersTableItem'; const styles = css` - Table { - composes: theme-background-surface theme-text-on-surface from global; - } - Group { - position: relative; - } - Group, container, table-container { - height: 100%; - } - container { - display: flex; - flex-direction: column; - width: 100%; - } - table-container { - overflow: auto; - } - GrantedUsersTableHeader { - flex: 0 0 auto; - } - `; + Table { + composes: theme-background-surface theme-text-on-surface from global; + } + Group { + position: relative; + } + Group, + container, + table-container { + height: 100%; + } + container { + display: flex; + flex-direction: column; + width: 100%; + } + table-container { + overflow: auto; + } + GrantedUsersTableHeader { + flex: 0 0 auto; + } +`; interface Props { userList: AdminUserInfoFragment[]; @@ -65,12 +65,7 @@ interface Props { onGrant: (subjectIds: string[]) => void; } -export const UserList = observer(function UserList({ - userList, - grantedUsers, - disabled, - onGrant, -}) { +export const UserList = observer(function UserList({ userList, grantedUsers, disabled, onGrant }) { const props = useObjectRef({ onGrant }); const style = useStyles(styles, BASE_CONTAINERS_STYLES); const translate = useTranslate(); @@ -94,7 +89,9 @@ export const UserList = observer(function UserList({ - + (function UserList({ {!users.length && filterState.filterValue && ( - - - {translate('ui_search_no_result_placeholder')} - + + {translate('ui_search_no_result_placeholder')} )} {users.map(user => { @@ -119,7 +114,7 @@ export const UserList = observer(function UserList({ id={user.userId} name={`${user.userId}${activeUser ? ' (you)' : ''}`} tooltip={activeUser ? translate('administration_teams_team_granted_users_permission_denied') : user.userId} - icon='/icons/user.svg' + icon="/icons/user.svg" iconTooltip={translate('authentication_user_icon_tooltip')} disabled={disabled} /> @@ -129,6 +124,6 @@ export const UserList = observer(function UserList({
-
+ , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/getFilteredUsers.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/getFilteredUsers.ts index 53d6711803..fd38bb2e84 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/getFilteredUsers.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/getFilteredUsers.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; /** @@ -15,5 +14,5 @@ import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; export function getFilteredUsers(users: AdminUserInfoFragment[], filter: string): AdminUserInfoFragment[] { return users .filter(user => user.enabled && user.userId.toLowerCase().includes(filter.toLowerCase())) - .sort((a, b) => (a.userId).localeCompare(b.userId)); + .sort((a, b) => a.userId.localeCompare(b.userId)); } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/useGrantedUsers.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/useGrantedUsers.tsx index 9cfa0010b7..db1035983b 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/useGrantedUsers.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/useGrantedUsers.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, computed, observable } from 'mobx'; import { TeamInfo, TeamsResource } from '@cloudbeaver/core-authentication'; @@ -32,51 +31,53 @@ export function useGrantedUsers(team: TeamInfo, mode: TeamFormMode): Readonly(); - return useObservableRef(() => ({ - get changed() { - return !isArraysEqual(this.state.initialGrantedUsers, this.state.grantedUsers); - }, - isLoading() { - return this.state.loading; - }, - isLoaded() { - return this.state.loaded; - }, - isError() { - return false; - }, - edit() { - this.state.editing = !this.state.editing; - }, - revoke(subjectIds: string[]) { - this.state.grantedUsers = this.state.grantedUsers.filter(subject => !subjectIds.includes(subject)); - }, - grant(subjectIds: string[]) { - this.state.grantedUsers.push(...subjectIds); - }, - async load() { - if (this.state.loaded || this.state.loading) { - return; - } - - try { - this.state.loading = true; - - if (this.mode === 'edit') { - const grantedUsers = await this.resource.loadGrantedUsers(this.team.teamId); - this.state.grantedUsers = grantedUsers; - this.state.initialGrantedUsers = this.state.grantedUsers.slice(); + return useObservableRef( + () => ({ + get changed() { + return !isArraysEqual(this.state.initialGrantedUsers, this.state.grantedUsers); + }, + isLoading() { + return this.state.loading; + }, + isLoaded() { + return this.state.loaded; + }, + isError() { + return false; + }, + edit() { + this.state.editing = !this.state.editing; + }, + revoke(subjectIds: string[]) { + this.state.grantedUsers = this.state.grantedUsers.filter(subject => !subjectIds.includes(subject)); + }, + grant(subjectIds: string[]) { + this.state.grantedUsers.push(...subjectIds); + }, + async load() { + if (this.state.loaded || this.state.loading) { + return; } - this.state.loaded = true; - } catch (exception: any) { - this.notificationService.logException(exception, "Can't load users info"); - } finally { - this.state.loading = false; - } - }, - }), - { state: observable.ref, changed: computed, edit: action.bound, revoke: action.bound, grant: action.bound }, - { state, team, mode, resource, notificationService }, - ['load']); + try { + this.state.loading = true; + + if (this.mode === 'edit') { + const grantedUsers = await this.resource.loadGrantedUsers(this.team.teamId); + this.state.grantedUsers = grantedUsers; + this.state.initialGrantedUsers = this.state.grantedUsers.slice(); + } + + this.state.loaded = true; + } catch (exception: any) { + this.notificationService.logException(exception, "Can't load users info"); + } finally { + this.state.loading = false; + } + }, + }), + { state: observable.ref, changed: computed, edit: action.bound, revoke: action.bound, grant: action.bound }, + { state, team, mode, resource, notificationService }, + ['load'], + ); } 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 e561a28be4..5a4c3561b0 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,7 +5,6 @@ * 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 { IExecutorHandlersCollection } from '@cloudbeaver/core-executor'; import type { MetadataMap } from '@cloudbeaver/core-utils'; @@ -29,9 +28,7 @@ export interface ITeamFormState { readonly load: () => Promise; readonly loadTeamInfo: () => Promise; readonly save: () => Promise; - readonly setOptions: ( - mode: TeamFormMode, - ) => this; + readonly setOptions: (mode: TeamFormMode) => this; } export interface ITeamFormProps { diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/Permissions.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/Permissions.tsx index b96435e44a..b4635ca821 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/Permissions.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/Permissions.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -53,7 +52,7 @@ export const Permissions = observer(function Permissions({ state id={permission.id} value={permission.id} title={tooltip} - name='teamPermissions' + name="teamPermissions" state={state.config} readOnly={state.readonly} disabled={state.disabled} @@ -63,6 +62,6 @@ export const Permissions = observer(function Permissions({ state ); })} - + , ); -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamMetaParameters.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamMetaParameters.tsx index bcf032f285..8a46db3dbd 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamMetaParameters.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamMetaParameters.tsx @@ -5,12 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; import { TeamMetaParametersResource } from '@cloudbeaver/core-authentication'; -import { BASE_CONTAINERS_STYLES, Group, useTranslate, useStyles, useResource, GroupTitle, ObjectPropertyInfoForm } from '@cloudbeaver/core-blocks'; +import { BASE_CONTAINERS_STYLES, Group, GroupTitle, ObjectPropertyInfoForm, useResource, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; import type { ITeamFormState } from '../ITeamFormProps'; @@ -18,9 +17,7 @@ interface IProps { state: ITeamFormState; } -export const TeamMetaParameters = observer(function TeamMetaParameters({ - state, -}) { +export const TeamMetaParameters = observer(function TeamMetaParameters({ state }) { const teamMetaParameters = useResource(TeamMetaParameters, TeamMetaParametersResource, undefined); const translate = useTranslate(); const style = useStyles(BASE_CONTAINERS_STYLES); @@ -32,13 +29,7 @@ export const TeamMetaParameters = observer(function TeamMetaParameters({ return styled(style)( {translate('authentication_team_meta_parameters')} - - + + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx index 78a98d44fe..7ddf4e780f 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx @@ -5,12 +5,24 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useRef } from 'react'; import styled, { css } from 'reshadow'; -import { BASE_CONTAINERS_STYLES, ColoredContainer, Group, InputField, SubmittingForm, Textarea, useTranslate, useStyles, useResource, Loader, GroupTitle, ObjectPropertyInfoForm } from '@cloudbeaver/core-blocks'; +import { + BASE_CONTAINERS_STYLES, + ColoredContainer, + Group, + GroupTitle, + InputField, + Loader, + ObjectPropertyInfoForm, + SubmittingForm, + Textarea, + useResource, + useStyles, + useTranslate, +} from '@cloudbeaver/core-blocks'; import { ServerConfigResource } from '@cloudbeaver/core-root'; import type { TabContainerPanelComponent } from '@cloudbeaver/core-ui'; @@ -25,9 +37,7 @@ const styles = css` } `; -export const TeamOptions: TabContainerPanelComponent = observer(function TeamOptions({ - state, -}) { +export const TeamOptions: TabContainerPanelComponent = observer(function TeamOptions({ state }) { const serverConfigResource = useResource(TeamOptions, ServerConfigResource, undefined); const style = useStyles(BASE_CONTAINERS_STYLES, styles); const formRef = useRef(null); @@ -38,41 +48,19 @@ export const TeamOptions: TabContainerPanelComponent = observer( - + {translate('administration_teams_team_id')} - + {translate('administration_teams_team_name')} - {!serverConfigResource.resource.distributed && } - + , ); }); 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 eede5ed7cc..74e39dcc45 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 @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; import { TeamsResource } from '@cloudbeaver/core-authentication'; @@ -28,7 +27,7 @@ export class TeamOptionsTabService extends Bootstrap { constructor( private readonly teamFormService: TeamFormService, private readonly teamResource: TeamsResource, - private readonly localizationService: LocalizationService + private readonly localizationService: LocalizationService, ) { super(); } @@ -41,27 +40,18 @@ export class TeamOptionsTabService extends Bootstrap { panel: () => TeamOptions, }); - this.teamFormService.prepareConfigTask - .addHandler(this.prepareConfig.bind(this)); + this.teamFormService.prepareConfigTask.addHandler(this.prepareConfig.bind(this)); - this.teamFormService.formValidationTask - .addHandler(this.validate.bind(this)); + this.teamFormService.formValidationTask.addHandler(this.validate.bind(this)); - this.teamFormService.formSubmittingTask - .addHandler(this.save.bind(this)); + this.teamFormService.formSubmittingTask.addHandler(this.save.bind(this)); - this.teamFormService.fillConfigTask - .addHandler(this.fillConfig.bind(this)); + this.teamFormService.fillConfigTask.addHandler(this.fillConfig.bind(this)); } - load(): void { } + load(): void {} - private async prepareConfig( - { - state, - }: ITeamFormSubmitData, - contexts: IExecutionContextProvider - ) { + private async prepareConfig({ state }: ITeamFormSubmitData, contexts: IExecutionContextProvider) { const config = contexts.getContext(teamContext); config.teamId = state.config.teamId; @@ -86,12 +76,7 @@ export class TeamOptionsTabService extends Bootstrap { config.teamPermissions = [...state.config.teamPermissions]; } - private async validate( - { - state, - }: ITeamFormSubmitData, - contexts: IExecutionContextProvider - ) { + private async validate({ state }: ITeamFormSubmitData, contexts: IExecutionContextProvider) { const validation = contexts.getContext(this.teamFormService.configurationValidationContext); if (state.mode === 'create') { @@ -100,19 +85,16 @@ export class TeamOptionsTabService extends Bootstrap { } if (this.teamResource.has(state.config.teamId)) { - validation.error(this.localizationService.translate('administration_teams_team_info_exists', undefined, { - teamId: state.config.teamId, - })); + validation.error( + this.localizationService.translate('administration_teams_team_info_exists', undefined, { + teamId: state.config.teamId, + }), + ); } } } - private async save( - { - state, - }: ITeamFormSubmitData, - contexts: IExecutionContextProvider - ) { + private async save({ state }: ITeamFormSubmitData, contexts: IExecutionContextProvider) { const status = contexts.getContext(this.teamFormService.configurationStatusContext); const config = contexts.getContext(teamContext); @@ -138,10 +120,7 @@ export class TeamOptionsTabService extends Bootstrap { } } - private fillConfig( - { state, updated }: ITeamFormFillConfigData, - contexts: IExecutionContextProvider - ) { + private fillConfig({ state, updated }: ITeamFormFillConfigData, contexts: IExecutionContextProvider) { if (!updated) { return; } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamForm.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamForm.tsx index 1fdaa39cf5..72d8f2a94e 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamForm.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamForm.tsx @@ -5,15 +5,23 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useEffect } from 'react'; import styled, { css } from 'reshadow'; import type { TeamInfo } from '@cloudbeaver/core-authentication'; -import { Placeholder, useObjectRef, useExecutor, BASE_CONTAINERS_STYLES, IconOrImage, useTranslate, useStyles, Loader } from '@cloudbeaver/core-blocks'; +import { + BASE_CONTAINERS_STYLES, + IconOrImage, + Loader, + Placeholder, + useExecutor, + useObjectRef, + useStyles, + useTranslate, +} from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; -import { TabsState, TabList, UNDERLINE_TAB_STYLES, TabPanelList, BASE_TAB_STYLES } from '@cloudbeaver/core-ui'; +import { BASE_TAB_STYLES, TabList, TabPanelList, TabsState, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui'; import { teamContext } from './Contexts/teamContext'; import type { ITeamFormState } from './ITeamFormProps'; @@ -26,72 +34,72 @@ const tabsStyles = css` align-items: center; } Tab { - height: 46px!important; + height: 46px !important; text-transform: uppercase; font-weight: 500 !important; } `; const topBarStyles = css` - team-top-bar { - composes: theme-border-color-background theme-background-secondary theme-text-on-secondary from global; - position: relative; - display: flex; - padding-top: 16px; + team-top-bar { + composes: theme-border-color-background theme-background-secondary theme-text-on-secondary from global; + position: relative; + display: flex; + padding-top: 16px; - &:before { - content: ''; - position: absolute; - bottom: 0; - width: 100%; - border-bottom: solid 2px; - border-color: inherit; - } - } - team-top-bar-tabs { - flex: 1; + &:before { + content: ''; + position: absolute; + bottom: 0; + width: 100%; + border-bottom: solid 2px; + border-color: inherit; } + } + team-top-bar-tabs { + flex: 1; + } - team-top-bar-actions { - display: flex; - align-items: center; - padding: 0 24px; - gap: 16px; - } + team-top-bar-actions { + display: flex; + align-items: center; + padding: 0 24px; + gap: 16px; + } - team-status-message { - composes: theme-typography--caption from global; + team-status-message { + composes: theme-typography--caption from global; + height: 24px; + padding: 0 16px; + display: flex; + align-items: center; + gap: 8px; + + & IconOrImage { height: 24px; - padding: 0 16px; - display: flex; - align-items: center; - gap: 8px; - - & IconOrImage { - height: 24px; - width: 24px; - } + width: 24px; } - `; + } +`; const formStyles = css` - box { - composes: theme-background-secondary theme-text-on-secondary from global; - display: flex; - flex-direction: column; - flex: 1; - height: 100%; - overflow: auto; - } - content-box { - composes: theme-background-secondary theme-border-color-background from global; - position: relative; - display: flex; - flex: 1; - flex-direction: column; - overflow: auto; - } - `; + box { + composes: theme-background-secondary theme-text-on-secondary from global; + display: flex; + flex-direction: column; + flex: 1; + height: 100%; + overflow: auto; + } + content-box { + composes: theme-background-secondary theme-border-color-background from global; + position: relative; + display: flex; + flex: 1; + flex-direction: column; + overflow: auto; + } +`; interface Props { state: ITeamFormState; @@ -100,12 +108,7 @@ interface Props { className?: string; } -export const TeamForm = observer(function TeamForm({ - state, - onCancel, - onSave = () => { }, - className, -}) { +export const TeamForm = observer(function TeamForm({ state, onCancel, onSave = () => {}, className }) { const translate = useTranslate(); const props = useObjectRef({ onSave }); const style = [BASE_TAB_STYLES, tabsStyles, UNDERLINE_TAB_STYLES]; @@ -114,15 +117,17 @@ export const TeamForm = observer(function TeamForm({ useExecutor({ executor: state.submittingTask, - postHandlers: [function save(data, contexts) { - const validation = contexts.getContext(service.configurationValidationContext); - const state = contexts.getContext(service.configurationStatusContext); - const config = contexts.getContext(teamContext); + postHandlers: [ + function save(data, contexts) { + const validation = contexts.getContext(service.configurationValidationContext); + const state = contexts.getContext(service.configurationStatusContext); + const config = contexts.getContext(teamContext); - if (validation.valid && state.saved) { - props.onSave(config); - } - }], + if (validation.valid && state.saved) { + props.onSave(config); + } + }, + ], }); useEffect(() => { @@ -130,19 +135,14 @@ export const TeamForm = observer(function TeamForm({ }, []); return styled(styles)( - + {state.statusMessage && ( <> - + {translate(state.statusMessage)} )} @@ -159,6 +159,6 @@ export const TeamForm = observer(function TeamForm({ - + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormBaseActions.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormBaseActions.tsx index 232cb644cb..b57d5dc92b 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormBaseActions.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormBaseActions.tsx @@ -5,39 +5,23 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { Button, PlaceholderComponent, useTranslate } from '@cloudbeaver/core-blocks'; - import type { ITeamFormProps } from './ITeamFormProps'; -export const TeamFormBaseActions: PlaceholderComponent = observer(function TeamFormBaseActions({ - state, - onCancel, -}) { +export const TeamFormBaseActions: PlaceholderComponent = observer(function TeamFormBaseActions({ state, onCancel }) { const translate = useTranslate(); return ( <> {onCancel && ( - )} - diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormService.ts index efeceee5a8..8e70c000cc 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; import { PlaceholderContainer } from '@cloudbeaver/core-blocks'; @@ -49,9 +48,7 @@ export class TeamFormService { readonly afterFormSubmittingTask: IExecutorHandlersCollection; readonly formStateTask: IExecutorHandlersCollection; - constructor( - private readonly notificationService: NotificationService, - ) { + constructor(private readonly notificationService: NotificationService) { this.tabsContainer = new TabsContainer('Team settings'); this.actionsContainer = new PlaceholderContainer(); this.configureTask = new ExecutorHandlersCollection(); @@ -62,13 +59,9 @@ export class TeamFormService { this.formValidationTask = new ExecutorHandlersCollection(); this.formStateTask = new ExecutorHandlersCollection(); - this.formSubmittingTask - .before(this.formValidationTask) - .before(this.prepareConfigTask) - .next(this.afterFormSubmittingTask); + this.formSubmittingTask.before(this.formValidationTask).before(this.prepareConfigTask).next(this.afterFormSubmittingTask); - this.formStateTask - .before(this.prepareConfigTask, state => ({ state, submitType: 'submit' })); + this.formStateTask.before(this.prepareConfigTask, state => ({ state, submitType: 'submit' })); this.formSubmittingTask.addPostHandler(this.showSubmittingStatusMessage); this.formValidationTask.addPostHandler(this.ensureValidation); @@ -113,16 +106,15 @@ export class TeamFormService { if (status.messages.length > 0) { if (status.exception) { - this.notificationService.logException( - status.exception, - status.messages[0], - status.messages.slice(1).join('\n') - ); + this.notificationService.logException(status.exception, status.messages[0], status.messages.slice(1).join('\n')); } else { - this.notificationService.notify({ - title: status.messages[0], - message: status.messages.slice(1).join('\n'), - }, status.saved ? ENotificationType.Success : ENotificationType.Error); + this.notificationService.notify( + { + title: status.messages[0], + message: status.messages.slice(1).join('\n'), + }, + status.saved ? ENotificationType.Success : ENotificationType.Error, + ); } } }; @@ -135,12 +127,16 @@ export class TeamFormService { } if (validation.messages.length > 0) { - this.notificationService.notify({ - title: data.state.mode === 'edit' - ? 'administration_identity_providers_provider_save_error' - : 'administration_identity_providers_provider_create_error', - message: validation.messages.join('\n'), - }, validation.valid ? ENotificationType.Info : ENotificationType.Error); + this.notificationService.notify( + { + title: + data.state.mode === 'edit' + ? 'administration_identity_providers_provider_save_error' + : 'administration_identity_providers_provider_create_error', + message: validation.messages.join('\n'), + }, + validation.valid ? ENotificationType.Info : ENotificationType.Error, + ); } }; } 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 83d10ad2f8..bc971028fe 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 @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed, makeObservable, observable } from 'mobx'; import type { TeamInfo, TeamsResource } from '@cloudbeaver/core-authentication'; @@ -52,10 +51,7 @@ export class TeamFormState implements ITeamFormState { private readonly loadTeamTask: IExecutor; private readonly formStateTask: IExecutor; - constructor( - service: TeamFormService, - resource: TeamsResource - ) { + constructor(service: TeamFormService, resource: TeamsResource) { this.resource = resource; this.config = { teamId: '', @@ -85,9 +81,7 @@ export class TeamFormState implements ITeamFormState { this.loadInfo = this.loadInfo.bind(this); this.updateFormState = this.updateFormState.bind(this); - this.formStateTask - .addCollection(service.formStateTask) - .addPostHandler(this.updateFormState); + this.formStateTask.addCollection(service.formStateTask).addPostHandler(this.updateFormState); this.loadTeamTask .before(service.configureTask) @@ -103,7 +97,7 @@ export class TeamFormState implements ITeamFormState { .next(this.formStateTask); } - async load(): Promise { } + async load(): Promise {} async loadTeamInfo(): Promise { await this.loadTeamTask.execute(this); @@ -111,9 +105,7 @@ export class TeamFormState implements ITeamFormState { return this.info; } - setOptions( - mode: TeamFormMode, - ): this { + setOptions(mode: TeamFormMode): this { this.mode = mode; return this; } @@ -128,14 +120,11 @@ export class TeamFormState implements ITeamFormState { { state: this, }, - this.service.formSubmittingTask + this.service.formSubmittingTask, ); } - private updateFormState( - data: ITeamFormState, - contexts: IExecutionContextProvider - ): void { + private updateFormState(data: ITeamFormState, contexts: IExecutionContextProvider): void { const context = contexts.getContext(teamFormStateContext); this.statusMessage = context.statusMessage; @@ -144,10 +133,7 @@ export class TeamFormState implements ITeamFormState { this.configured = true; } - private async loadInfo( - data: ITeamFormState, - contexts: IExecutionContextProvider - ) { + private async loadInfo(data: ITeamFormState, contexts: IExecutionContextProvider) { if (!data.config.teamId) { return; } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationNavService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationNavService.ts index d9fc245584..67b2dc463c 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationNavService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationNavService.ts @@ -5,16 +5,13 @@ * 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 { EUsersAdministrationSub, UsersAdministrationNavigationService } from '../UsersAdministrationNavigationService'; @injectable() export class TeamsAdministrationNavService { - constructor( - private readonly usersAdministrationNavigationService: UsersAdministrationNavigationService - ) { } + constructor(private readonly usersAdministrationNavigationService: UsersAdministrationNavigationService) {} navToRoot(): void { this.usersAdministrationNavigationService.navToSub(EUsersAdministrationSub.Teams); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationService.ts index 4913de34b2..cfedab4fe4 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationService.ts @@ -5,7 +5,6 @@ * 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 { PlaceholderContainer } from '@cloudbeaver/core-blocks'; import { injectable } from '@cloudbeaver/core-di'; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsPage.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsPage.tsx index f7480f4369..efb06ecc8c 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsPage.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsPage.tsx @@ -5,25 +5,31 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; import { ADMINISTRATION_TOOLS_PANEL_STYLES, IAdministrationItemSubItem } from '@cloudbeaver/core-administration'; -import { BASE_CONTAINERS_STYLES, ToolsAction, ToolsPanel, useTranslate, useStyles, ColoredContainer, Group, Container } from '@cloudbeaver/core-blocks'; +import { + BASE_CONTAINERS_STYLES, + ColoredContainer, + Container, + Group, + ToolsAction, + ToolsPanel, + useStyles, + useTranslate, +} from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; - - import { CreateTeam } from './CreateTeam'; import { CreateTeamService } from './CreateTeamService'; import { TeamsTable } from './TeamsTable/TeamsTable'; import { useTeamsTable } from './TeamsTable/useTeamsTable'; -const styles = css` - ToolsPanel { - border-bottom: none; - } +const styles = css` + ToolsPanel { + border-bottom: none; + } `; interface Props { @@ -31,10 +37,7 @@ interface Props { param?: string | null; } -export const TeamsPage = observer(function TeamsPage({ - sub, - param, -}) { +export const TeamsPage = observer(function TeamsPage({ sub, param }) { const translate = useTranslate(); const style = useStyles(BASE_CONTAINERS_STYLES, styles, ADMINISTRATION_TOOLS_PANEL_STYLES); const service = useService(CreateTeamService); @@ -82,15 +85,10 @@ export const TeamsPage = observer(function TeamsPage({ )} - - + + - + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/Team.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/Team.tsx index 7c52cf74c0..1fca98933d 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/Team.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/Team.tsx @@ -5,15 +5,13 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css, use } from 'reshadow'; import type { TeamInfo } from '@cloudbeaver/core-authentication'; -import { TableItem, TableColumnValue, TableItemSelect, TableItemExpand, Placeholder, useStyles, Loader } from '@cloudbeaver/core-blocks'; +import { Loader, Placeholder, TableColumnValue, TableItem, TableItemExpand, TableItemSelect, useStyles } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; - import { TeamsAdministrationService } from '../TeamsAdministrationService'; import { TeamEdit } from './TeamEdit'; @@ -49,14 +47,20 @@ export const Team = observer(function Team({ team }) { - {team.teamId} - {team.teamName || ''} - {team.description || ''} + + {team.teamId} + + + {team.teamName || ''} + + + {team.description || ''} + - + , ); }); 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 340a11a9f4..4d7340987f 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 @@ -5,37 +5,33 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { useRef, useEffect, useContext, useCallback } from 'react'; +import { useCallback, useContext, useEffect, useRef } from 'react'; import styled, { css } from 'reshadow'; import { TeamsResource } from '@cloudbeaver/core-authentication'; import { TableContext, useStyles } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; - import { TeamForm } from '../TeamForm'; import { useTeamFormState } from '../useTeamFormState'; const styles = css` - box { - composes: theme-background-secondary theme-text-on-secondary from global; - box-sizing: border-box; - padding-bottom: 24px; - display: flex; - flex-direction: column; - height: 664px; - } - `; + box { + composes: theme-background-secondary theme-text-on-secondary from global; + box-sizing: border-box; + padding-bottom: 24px; + display: flex; + flex-direction: column; + height: 664px; + } +`; interface Props { item: string; } -export const TeamEdit = observer(function TeamEdit({ - item, -}) { +export const TeamEdit = observer(function TeamEdit({ item }) { const resource = useService(TeamsResource); const boxRef = useRef(null); const tableContext = useContext(TableContext); @@ -51,19 +47,13 @@ export const TeamEdit = observer(function TeamEdit({ }); }, []); - const data = useTeamFormState( - resource, - state => state.setOptions('edit') - ); + const data = useTeamFormState(resource, state => state.setOptions('edit')); data.config.teamId = item; return styled(useStyles(styles))( - - + + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamsTable.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamsTable.tsx index b9c96033d6..536a6e1df7 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamsTable.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamsTable.tsx @@ -5,12 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { css } from 'reshadow'; import type { TeamInfo } from '@cloudbeaver/core-authentication'; -import { Table, TableHeader, TableColumnHeader, TableBody, TableSelect, Loader, useTranslate } from '@cloudbeaver/core-blocks'; +import { Loader, Table, TableBody, TableColumnHeader, TableHeader, TableSelect, useTranslate } from '@cloudbeaver/core-blocks'; import type { ILoadableState } from '@cloudbeaver/core-utils'; import { Team } from './Team'; @@ -34,7 +33,7 @@ export const TeamsTable = observer(function TeamsTable({ teams, state, se return ( - +
diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/useTeamsTable.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/useTeamsTable.tsx index e6f8618c8b..48142c1883 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/useTeamsTable.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/useTeamsTable.tsx @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed, observable } from 'mobx'; import { compareTeams, TeamInfo, TeamsResource } from '@cloudbeaver/core-authentication'; -import { TableState, useResource, useObservableRef, useTranslate } from '@cloudbeaver/core-blocks'; +import { TableState, useObservableRef, useResource, useTranslate } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { CommonDialogService, ConfirmationDialogDelete, DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; @@ -32,65 +31,70 @@ export function useTeamsTable(): Readonly { const translate = useTranslate(); - return useObservableRef(() => ({ - tableState: new TableState(), - processing: false, - state: resource, - get teams() { - return resource.resource.values.slice().sort(compareTeams); + return useObservableRef( + () => ({ + tableState: new TableState(), + processing: false, + state: resource, + get teams() { + return resource.resource.values.slice().sort(compareTeams); + }, + async update() { + if (this.processing) { + return; + } + + try { + this.processing = true; + await resource.resource.refresh(CachedMapAllKey); + notificationService.logSuccess({ title: 'administration_teams_team_list_update_success' }); + } catch (exception: any) { + notificationService.logException(exception, 'administration_teams_team_list_update_fail'); + } finally { + this.processing = false; + } + }, + async delete() { + if (this.processing) { + return; + } + + const deletionList = this.tableState.selectedList; + + if (deletionList.length === 0) { + return; + } + + const teamNames = deletionList.map(name => `"${name}"`).join(', '); + const message = `${translate('administration_teams_delete_confirmation')}${teamNames}. ${translate('ui_are_you_sure')}`; + const result = await dialogService.open(ConfirmationDialogDelete, { + title: 'ui_data_delete_confirmation', + message, + confirmActionText: 'ui_delete', + }); + + if (result === DialogueStateResult.Rejected) { + return; + } + + try { + this.processing = true; + await resource.resource.deleteTeam(resourceKeyList(deletionList)); + + this.tableState.unselect(); + this.tableState.unexpand(deletionList); + } catch (exception: any) { + notificationService.logException(exception, 'Teams delete Error'); + } finally { + this.processing = false; + } + }, + }), + { + processing: observable.ref, + teams: computed, }, - async update() { - if (this.processing) { - return; - } - - try { - this.processing = true; - await resource.resource.refresh(CachedMapAllKey); - notificationService.logSuccess({ title: 'administration_teams_team_list_update_success' }); - } catch (exception: any) { - notificationService.logException(exception, 'administration_teams_team_list_update_fail'); - } finally { - this.processing = false; - } - }, - async delete() { - if (this.processing) { - return; - } - - const deletionList = this.tableState.selectedList; - - if (deletionList.length === 0) { - return; - } - - const teamNames = deletionList.map(name => `"${name}"`).join(', '); - const message = `${translate('administration_teams_delete_confirmation')}${teamNames}. ${translate('ui_are_you_sure')}`; - const result = await dialogService.open(ConfirmationDialogDelete, { - title: 'ui_data_delete_confirmation', - message, - confirmActionText: 'ui_delete', - }); - - if (result === DialogueStateResult.Rejected) { - return; - } - - try { - this.processing = true; - await resource.resource.deleteTeam(resourceKeyList(deletionList)); - - this.tableState.unselect(); - this.tableState.unexpand(deletionList); - } catch (exception: any) { - notificationService.logException(exception, 'Teams delete Error'); - } finally { - this.processing = false; - } - }, - }), { - processing: observable.ref, - teams: computed, - }, false, ['update', 'delete']); + false, + ['update', 'delete'], + ); } 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 729afc91e1..e5a1295f91 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 @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { useState } from 'react'; import type { TeamsResource } from '@cloudbeaver/core-authentication'; @@ -15,16 +14,10 @@ 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, configure?: (state: ITeamFormState) => any): ITeamFormState { const service = useService(TeamFormService); const [state] = useState(() => { - const state = new TeamFormState( - service, - resource, - ); + const state = new TeamFormState(service, resource); configure?.(state); state.load(); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/ConnectionAccess.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/ConnectionAccess.tsx index 4ad7a9fb89..2a939987a2 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/ConnectionAccess.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/ConnectionAccess.tsx @@ -5,16 +5,26 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useCallback, useMemo } from 'react'; import styled, { css } from 'reshadow'; import { - Table, TableHeader, TableColumnHeader, TableBody, - TableItem, TableColumnValue, TableItemSelect, StaticImage, - TextPlaceholder, ColoredContainer, BASE_CONTAINERS_STYLES, Group, useTranslate, useStyles + BASE_CONTAINERS_STYLES, + ColoredContainer, + Group, + StaticImage, + Table, + TableBody, + TableColumnHeader, + TableColumnValue, + TableHeader, + TableItem, + TableItemSelect, + TextPlaceholder, + useStyles, + useTranslate, } from '@cloudbeaver/core-blocks'; import { DBDriverResource, isCloudConnection } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; @@ -24,43 +34,39 @@ import type { TabContainerPanelComponent } from '@cloudbeaver/core-ui'; import type { IUserFormProps } from '../UserFormService'; const styles = css` - Table { - composes: theme-background-surface theme-text-on-surface from global; - width: 100%; - } - StaticImage { - display: flex; - width: 24px; - } - `; + Table { + composes: theme-background-surface theme-text-on-surface from global; + width: 100%; + } + StaticImage { + display: flex; + width: 24px; + } +`; -export const ConnectionAccess: TabContainerPanelComponent = observer(function ConnectionAccess({ - controller, - editing, -}) { +export const ConnectionAccess: TabContainerPanelComponent = observer(function ConnectionAccess({ controller, editing }) { const style = useStyles(styles, BASE_CONTAINERS_STYLES); const translate = useTranslate(); const driversResource = useService(DBDriverResource); const getConnectionPermission = useCallback( - (connectionId: string) => controller.grantedConnections - .find(connectionPermission => connectionPermission.dataSourceId === connectionId), - [controller.grantedConnections]); + (connectionId: string) => controller.grantedConnections.find(connectionPermission => connectionPermission.dataSourceId === connectionId), + [controller.grantedConnections], + ); const loading = controller.isLoading; const cloudExists = controller.connections.some(isCloudConnection); - const localConnections = useMemo(() => computed( - () => controller.connections.filter(connection => !isCloudConnection(connection)) - ), [controller.connections]); + const localConnections = useMemo( + () => computed(() => controller.connections.filter(connection => !isCloudConnection(connection))), + [controller.connections], + ); const isAdmin = controller.user.grantedTeams.includes('admin'); if (controller.connections.length === 0) { return styled(style)( - - {translate('authentication_administration_user_connections_empty')} - + {translate('authentication_administration_user_connections_empty')} - + , ); } @@ -68,18 +74,16 @@ export const ConnectionAccess: TabContainerPanelComponent = obse return styled(style)( - - {translate('connections_connection_access_admin_info')} - + {translate('connections_connection_access_admin_info')} - + , ); } return styled(style)( -
+
@@ -88,10 +92,8 @@ export const ConnectionAccess: TabContainerPanelComponent = obse {cloudExists && ( - - - {translate('cloud_connections_access_placeholder')} - + + {translate('cloud_connections_access_placeholder')} )} {localConnections.get().map(connection => { @@ -107,28 +109,23 @@ export const ConnectionAccess: TabContainerPanelComponent = obse } return ( - + - + - - {connection.name} - - {grantedBy} + + + + {connection.name} + + {grantedBy} ); })}
- + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/ConnectionAccessTabBootstrap.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/ConnectionAccessTabBootstrap.ts index 7601663af9..ef6da43c16 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/ConnectionAccessTabBootstrap.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/ConnectionAccessTabBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; @@ -21,10 +20,7 @@ const ConnectionAccess = React.lazy(async () => { @injectable() export class ConnectionAccessTabBootstrap extends Bootstrap { - constructor( - private readonly userFormService: UserFormService, - private readonly projectInfoResource: ProjectInfoResource, - ) { + constructor(private readonly userFormService: UserFormService, private readonly projectInfoResource: ProjectInfoResource) { super(); } @@ -42,5 +38,5 @@ export class ConnectionAccessTabBootstrap extends Bootstrap { this.userFormService.onFormInit.addHandler(() => this.projectInfoResource.load(CachedMapAllKey)); } - load(): void { } + load(): void {} } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/OriginInfoPanel.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/OriginInfoPanel.tsx index c91e6976ad..a30bb29a68 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/OriginInfoPanel.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/OriginInfoPanel.tsx @@ -5,12 +5,24 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; import { UsersResource } from '@cloudbeaver/core-authentication'; -import { TextPlaceholder, Loader, ExceptionMessage, BASE_CONTAINERS_STYLES, ColoredContainer, ObjectPropertyInfoForm, Group, useAutoLoad, useObjectRef, IAutoLoadable, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { + BASE_CONTAINERS_STYLES, + ColoredContainer, + ExceptionMessage, + Group, + IAutoLoadable, + Loader, + ObjectPropertyInfoForm, + TextPlaceholder, + useAutoLoad, + useObjectRef, + useStyles, + useTranslate, +} from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import type { AdminUserInfo, ObjectPropertyInfo } from '@cloudbeaver/core-sdk'; import { TabContainerPanelComponent, useTab, useTabState } from '@cloudbeaver/core-ui'; @@ -31,10 +43,7 @@ interface IState { exception: Error | null; } -export const OriginInfoPanel: TabContainerPanelComponent = observer(function OriginInfoPanel({ - tabId, - user, -}) { +export const OriginInfoPanel: TabContainerPanelComponent = observer(function OriginInfoPanel({ tabId, user }) { const style = useStyles(BASE_CONTAINERS_STYLES); const translate = useTranslate(); const usersResource = useService(UsersResource); @@ -53,55 +62,59 @@ export const OriginInfoPanel: TabContainerPanelComponent = obser origin = user.origins[0]; } - const loadableState = useObjectRef(() => ({ - get exception(): Error | null { - return this.state.exception; - }, - isLoaded(): boolean { - return this.state.loaded; - }, - isLoading(): boolean { - return this.state.loading; - }, - async load(reload = false) { - if ((this.state.loaded && !reload) || this.state.loading) { - return; - } - - this.state.loading = true; - this.state.exception = null; - - try { - usersResource.markOutdated(this.user.userId); - const userOrigin = await usersResource.load(this.user.userId, ['customIncludeOriginDetails']); - - let origin = userOrigin.origins.find(origin => getOriginTabId('origin', origin) === tabId); - - if (!origin) { - origin = user.origins[0]; + const loadableState = useObjectRef( + () => ({ + get exception(): Error | null { + return this.state.exception; + }, + isLoaded(): boolean { + return this.state.loaded; + }, + isLoading(): boolean { + return this.state.loading; + }, + async load(reload = false) { + if ((this.state.loaded && !reload) || this.state.loading) { + return; } - const propertiesState = {} as Record; + this.state.loading = true; + this.state.exception = null; - for (const property of origin.details!) { - propertiesState[property.id!] = property.value; + try { + usersResource.markOutdated(this.user.userId); + const userOrigin = await usersResource.load(this.user.userId, ['customIncludeOriginDetails']); + + let origin = userOrigin.origins.find(origin => getOriginTabId('origin', origin) === tabId); + + if (!origin) { + origin = user.origins[0]; + } + + const propertiesState = {} as Record; + + for (const property of origin.details!) { + propertiesState[property.id!] = property.value; + } + this.state.properties = origin.details!; + this.state.state = propertiesState; + this.state.loaded = true; + } catch (error: any) { + this.state.exception = error; + } finally { + this.state.loading = false; } - this.state.properties = origin.details!; - this.state.state = propertiesState; - this.state.loaded = true; - } catch (error: any) { - this.state.exception = error; - } finally { - this.state.loading = false; - } + }, + async reload() { + await this.load(); + }, + }), + { + state, + user, }, - async reload() { - await this.load(); - }, - }), { - state, - user, - }, ['reload', 'load', 'isLoaded', 'isLoading']); + ['reload', 'load', 'isLoaded', 'isLoading'], + ); const { selected } = useTab(tabId); @@ -117,7 +130,7 @@ export const OriginInfoPanel: TabContainerPanelComponent = obser - + , ); } @@ -127,7 +140,7 @@ export const OriginInfoPanel: TabContainerPanelComponent = obser loadableState.reload?.()} /> - + , ); } @@ -137,21 +150,15 @@ export const OriginInfoPanel: TabContainerPanelComponent = obser {translate('authentication_administration_user_origin_empty')} - + , ); } return styled(style)( - + - + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/OriginInfoTab.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/OriginInfoTab.tsx index 337729f2a3..2dea5f16d3 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/OriginInfoTab.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/OriginInfoTab.tsx @@ -5,12 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; import { Translate, useStyles } from '@cloudbeaver/core-blocks'; -import { TabTitle, Tab, TabContainerTabComponent } from '@cloudbeaver/core-ui'; +import { Tab, TabContainerTabComponent, TabTitle } from '@cloudbeaver/core-ui'; import { getOriginTabId } from './getOriginTabId'; import type { IUserFormProps } from './UserFormService'; @@ -25,12 +24,10 @@ export const OriginInfoTab: TabContainerTabComponent = observer( }) { const origin = user.origins.find(origin => getOriginTabId('origin', origin) === tabId); return styled(useStyles(style))( - - - + + + + + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserForm.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserForm.tsx index 470bce0673..1265ce23cf 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserForm.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserForm.tsx @@ -5,14 +5,13 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { Loader, SubmittingForm, Button, useFocus, StatusMessage, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { Button, Loader, StatusMessage, SubmittingForm, useFocus, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; import { useController, useService } from '@cloudbeaver/core-di'; import type { AdminUserInfo } from '@cloudbeaver/core-sdk'; -import { TabsState, TabList, TabPanelList, UNDERLINE_TAB_STYLES, BASE_TAB_STYLES } from '@cloudbeaver/core-ui'; +import { BASE_TAB_STYLES, TabList, TabPanelList, TabsState, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui'; import { UserFormController } from './UserFormController'; import { UserFormService } from './UserFormService'; @@ -24,69 +23,69 @@ const tabsStyles = css` align-items: center; } Tab { - height: 46px!important; + height: 46px !important; text-transform: uppercase; font-weight: 500 !important; } `; const formStyles = css` - FormBox { - composes: theme-background-secondary theme-text-on-secondary from global; - } - box { - display: flex; - flex-direction: column; - flex: 1; - height: 100%; - overflow: auto; - } - content-box { - composes: theme-background-secondary theme-text-on-secondary theme-border-color-background from global; - display: flex; - flex: 1; - flex-direction: column; - overflow: auto; - } - SubmittingForm { - flex: 1; - overflow: auto; - display: flex; - flex-direction: column; - } + FormBox { + composes: theme-background-secondary theme-text-on-secondary from global; + } + box { + display: flex; + flex-direction: column; + flex: 1; + height: 100%; + overflow: auto; + } + content-box { + composes: theme-background-secondary theme-text-on-secondary theme-border-color-background from global; + display: flex; + flex: 1; + flex-direction: column; + overflow: auto; + } + SubmittingForm { + flex: 1; + overflow: auto; + display: flex; + flex-direction: column; + } `; const topBarStyles = css` - connection-top-bar { - composes: theme-border-color-background theme-background-secondary theme-text-on-secondary from global; - position: relative; - display: flex; - padding-top: 16px; - margin-bottom: 24px; + connection-top-bar { + composes: theme-border-color-background theme-background-secondary theme-text-on-secondary from global; + position: relative; + display: flex; + padding-top: 16px; + margin-bottom: 24px; - &:before { - content: ''; - position: absolute; - bottom: 0; - width: 100%; - border-bottom: solid 2px; - border-color: inherit; - } + &:before { + content: ''; + position: absolute; + bottom: 0; + width: 100%; + border-bottom: solid 2px; + border-color: inherit; } - connection-top-bar-tabs { - overflow: hidden; - flex: 1; - } - StatusMessage { - padding: 0 16px; - } - connection-top-bar-actions { - display: flex; - align-items: center; - padding: 0 24px; - gap: 16px; - } - `; + } + connection-top-bar-tabs { + overflow: hidden; + flex: 1; + } + StatusMessage { + padding: 0 16px; + } + connection-top-bar-actions { + display: flex; + align-items: center; + padding: 0 24px; + gap: 16px; + } +`; interface Props { user: AdminUserInfo; @@ -94,11 +93,7 @@ interface Props { onCancel: () => void; } -export const UserForm = observer(function UserForm({ - user, - editing = false, - onCancel, -}) { +export const UserForm = observer(function UserForm({ user, editing = false, onCancel }) { const style = [BASE_TAB_STYLES, tabsStyles, UNDERLINE_TAB_STYLES]; const styles = useStyles(style, topBarStyles, formStyles); const translate = useTranslate(); @@ -109,13 +104,7 @@ export const UserForm = observer(function UserForm({ controller.update(user, editing, onCancel); return styled(styles)( - + @@ -127,20 +116,10 @@ export const UserForm = observer(function UserForm({ - - @@ -152,6 +131,6 @@ export const UserForm = observer(function UserForm({ - + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormBaseBootstrap.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormBaseBootstrap.ts index f139f61d11..eb0916abf9 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormBaseBootstrap.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormBaseBootstrap.ts @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; import { AUTH_PROVIDER_LOCAL_ID } from '@cloudbeaver/core-authentication'; -import { injectable, Bootstrap } from '@cloudbeaver/core-di'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { getOriginTabId } from './getOriginTabId'; import { UserFormService } from './UserFormService'; @@ -29,9 +28,7 @@ const UserInfo = React.lazy(async () => { @injectable() export class UserFormBaseBootstrap extends Bootstrap { - constructor( - private readonly userFormService: UserFormService, - ) { + constructor(private readonly userFormService: UserFormService) { super(); } @@ -61,5 +58,5 @@ export class UserFormBaseBootstrap extends Bootstrap { }); } - load(): void | Promise { } + load(): void | Promise {} } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormController.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormController.ts index 173761f817..bac68cbd4c 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormController.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormController.ts @@ -5,19 +5,24 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { observable, computed, makeObservable } from 'mobx'; +import { computed, makeObservable, observable } from 'mobx'; import { AdminUser, AuthRolesResource, compareTeams, isLocalUser, TeamInfo, TeamsResource, UsersResource } from '@cloudbeaver/core-authentication'; -import { compareConnectionsInfo, ConnectionInfoProjectKey, ConnectionInfoResource, DatabaseConnection, DBDriverResource } from '@cloudbeaver/core-connections'; -import { injectable, IInitializableController, IDestructibleController } from '@cloudbeaver/core-di'; +import { + compareConnectionsInfo, + ConnectionInfoProjectKey, + ConnectionInfoResource, + DatabaseConnection, + DBDriverResource, +} from '@cloudbeaver/core-connections'; +import { IDestructibleController, IInitializableController, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; import { ENotificationType, NotificationService } from '@cloudbeaver/core-events'; import { Executor, ExecutorInterrupter } from '@cloudbeaver/core-executor'; import type { TLocalizationToken } from '@cloudbeaver/core-localization'; import { ErrorDetailsDialog } from '@cloudbeaver/core-notifications'; import { isGlobalProject, ProjectInfoResource } from '@cloudbeaver/core-projects'; -import { GQLErrorCatcher, AdminConnectionGrantInfo, AdminSubjectType, AdminUserInfo, CachedMapAllKey } from '@cloudbeaver/core-sdk'; +import { AdminConnectionGrantInfo, AdminSubjectType, AdminUserInfo, CachedMapAllKey, GQLErrorCatcher } from '@cloudbeaver/core-sdk'; import { MetadataMap } from '@cloudbeaver/core-utils'; import { IUserFormState, UserFormService } from './UserFormService'; @@ -164,13 +169,10 @@ export class UserFormController implements IInitializableController, IDestructib this.notificationService.logSuccess({ title: 'authentication_administration_user_created' }); } else { if (this.credentials.password) { - await this.usersResource.updateCredentials( - this.user.userId, - { - profile: '0', - credentials: { password: this.credentials.password }, - } - ); + await this.usersResource.updateCredentials(this.user.userId, { + profile: '0', + credentials: { password: this.credentials.password }, + }); } await this.updateTeams(); await this.saveUserRole(); @@ -219,7 +221,9 @@ export class UserFormController implements IInitializableController, IDestructib } }; - handleConnectionsAccessChange = () => { this.connectionAccessChanged = true; }; + handleConnectionsAccessChange = () => { + this.connectionAccessChanged = true; + }; loadConnectionsAccess = async () => { if (this.isLoading || this.connectionAccessLoaded) { @@ -308,14 +312,10 @@ export class UserFormController implements IInitializableController, IDestructib } private getGrantedConnections() { - return Array.from(this.selectedConnections.keys()) - .filter(connectionId => { - const connectionPermission = this.grantedConnections.find( - connectionPermission => connectionPermission.dataSourceId === connectionId - ); - return this.selectedConnections.get(connectionId) - && connectionPermission?.subjectType !== AdminSubjectType.Team; - }); + return Array.from(this.selectedConnections.keys()).filter(connectionId => { + const connectionPermission = this.grantedConnections.find(connectionPermission => connectionPermission.dataSourceId === connectionId); + return this.selectedConnections.get(connectionId) && connectionPermission?.subjectType !== AdminSubjectType.Team; + }); } private async saveMetaParameters() { @@ -351,7 +351,7 @@ export class UserFormController implements IInitializableController, IDestructib await this.teamsResource.load(CachedMapAllKey); await this.loadUser(); } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t load teams'); + this.notificationService.logException(exception, "Can't load teams"); } finally { this.isLoading = false; } @@ -361,11 +361,11 @@ export class UserFormController implements IInitializableController, IDestructib try { this.credentials.metaParameters = this.user.metaParameters; this.credentials.login = this.user.userId; - this.credentials.teams = new Map(this.user.grantedTeams.map(teamId => ([teamId, true]))); + this.credentials.teams = new Map(this.user.grantedTeams.map(teamId => [teamId, true])); this.credentials.authRole = this.user.authRole; this.enabled = this.user.enabled; } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t load user'); + this.notificationService.logException(exception, "Can't load user"); } } @@ -374,11 +374,7 @@ export class UserFormController implements IInitializableController, IDestructib await this.dbDriverResource.load(CachedMapAllKey); const projects = await this.projectInfoResource.load(CachedMapAllKey); - await this.connectionInfoResource.load(ConnectionInfoProjectKey( - ...projects - .filter(isGlobalProject) - .map(project => project.id) - )); + await this.connectionInfoResource.load(ConnectionInfoProjectKey(...projects.filter(isGlobalProject).map(project => project.id))); } catch (exception: any) { this.setStatusMessage('authentication_administration_user_connections_access_connections_load_fail', ENotificationType.Error); } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormService.ts index 19f8002f2f..7233793cb6 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { AdminUser } from '@cloudbeaver/core-authentication'; import { injectable } from '@cloudbeaver/core-di'; import { Executor } from '@cloudbeaver/core-executor'; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserInfo.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserInfo.tsx index 5cee374dc6..b5526e7866 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserInfo.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserInfo.tsx @@ -5,13 +5,26 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback } from 'react'; import styled, { css } from 'reshadow'; import { AuthRolesResource, UserMetaParametersResource } from '@cloudbeaver/core-authentication'; -import { BASE_CONTAINERS_STYLES, ColoredContainer, Container, FieldCheckbox, Group, GroupTitle, InputField, Loader, ObjectPropertyInfoForm, useResource, useTranslate, useStyles, Combobox } from '@cloudbeaver/core-blocks'; +import { + BASE_CONTAINERS_STYLES, + ColoredContainer, + Combobox, + Container, + FieldCheckbox, + Group, + GroupTitle, + InputField, + Loader, + ObjectPropertyInfoForm, + useResource, + useStyles, + useTranslate, +} from '@cloudbeaver/core-blocks'; import type { TabContainerPanelComponent } from '@cloudbeaver/core-ui'; import type { IUserFormProps } from './UserFormService'; @@ -22,19 +35,15 @@ const styles = css` } `; -export const UserInfo: TabContainerPanelComponent = observer(function UserInfo({ - controller, - editing, -}) { +export const UserInfo: TabContainerPanelComponent = observer(function UserInfo({ controller, editing }) { const style = useStyles(BASE_CONTAINERS_STYLES, styles); const translate = useTranslate(); const userMetaParameters = useResource(UserInfo, UserMetaParametersResource, undefined); const authRoles = useResource(UserInfo, AuthRolesResource, undefined); - const handleTeamChange = useCallback( - (teamId: string, value: boolean) => { controller.credentials.teams.set(teamId, value); }, - [] - ); + const handleTeamChange = useCallback((teamId: string, value: boolean) => { + controller.credentials.teams.set(teamId, value); + }, []); return styled(style)( @@ -42,12 +51,12 @@ export const UserInfo: TabContainerPanelComponent = observer(fun {translate('authentication_user_credentials')} = observer(fun {controller.local && ( <> = observer(fun {translate('authentication_user_password')} = observer(fun {authRoles.data.length > 0 && ( value} @@ -101,12 +110,7 @@ export const UserInfo: TabContainerPanelComponent = observer(fun )} {translate('authentication_user_status')} - + {translate('authentication_user_enabled')} {translate('authentication_user_team')} @@ -118,7 +122,7 @@ export const UserInfo: TabContainerPanelComponent = observer(fun key={team.teamId} id={`${controller.user.userId}_${team.teamId}`} title={tooltip} - name='team' + name="team" checked={!!controller.credentials.teams.get(team.teamId)} disabled={controller.isSaving} onChange={checked => handleTeamChange(team.teamId, checked)} @@ -129,19 +133,22 @@ export const UserInfo: TabContainerPanelComponent = observer(fun })} - {() => userMetaParameters.data.length > 0 && styled(style)( - - {translate('authentication_user_meta_parameters')} - - - )} + {() => + userMetaParameters.data.length > 0 && + styled(style)( + + {translate('authentication_user_meta_parameters')} + + , + ) + } - + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/getOriginTabId.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/getOriginTabId.ts index e260c78a2a..e953239287 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/getOriginTabId.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/getOriginTabId.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { ObjectOrigin } from '@cloudbeaver/core-sdk'; export function getOriginTabId(tabId: string, origin: ObjectOrigin) { diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministration.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministration.tsx index 1b62bdf622..702d2880b3 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministration.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministration.tsx @@ -5,12 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { AdministrationItemContentComponent, ADMINISTRATION_TOOLS_PANEL_STYLES } from '@cloudbeaver/core-administration'; -import { ToolsPanel, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { ADMINISTRATION_TOOLS_PANEL_STYLES, AdministrationItemContentComponent } from '@cloudbeaver/core-administration'; +import { ToolsPanel, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { BASE_TAB_STYLES, ITabData, Tab, TabList, TabPanel, TabsState, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui'; @@ -27,7 +26,7 @@ const tabsStyles = css` height: 33px; } Tab { - height: 32px!important; + height: 32px !important; text-transform: uppercase; font-weight: 500 !important; } @@ -37,9 +36,7 @@ const tabsStyles = css` } `; -export const UsersAdministration: AdministrationItemContentComponent = observer(function UsersAdministration({ - sub, param, -}) { +export const UsersAdministration: AdministrationItemContentComponent = observer(function UsersAdministration({ sub, param }) { const translate = useTranslate(); const usersAdministrationNavigationService = useService(UsersAdministrationNavigationService); const subName = sub?.name || EUsersAdministrationSub.Users; @@ -60,9 +57,13 @@ export const UsersAdministration: AdministrationItemContentComponent = observer( return styled(style)( - - {translate('authentication_administration_item_users')} - {translate('administration_teams_tab_title')} + + + {translate('authentication_administration_item_users')} + + + {translate('administration_teams_tab_title')} + {/* - + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationNavigationService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationNavigationService.ts index 97986d8e60..08ad73ce6c 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationNavigationService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationNavigationService.ts @@ -5,23 +5,20 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { AdministrationScreenService } from '@cloudbeaver/core-administration'; import { injectable } from '@cloudbeaver/core-di'; export enum EUsersAdministrationSub { Users = 'users', Teams = 'teams', - MetaProperties = 'metaProperties' + MetaProperties = 'metaProperties', } @injectable() export class UsersAdministrationNavigationService { static ItemName = 'users'; - constructor( - private readonly administrationScreenService: AdministrationScreenService - ) { + constructor(private readonly administrationScreenService: AdministrationScreenService) { this.navToRoot = this.navToRoot.bind(this); } @@ -34,10 +31,6 @@ export class UsersAdministrationNavigationService { } navToSub(sub: EUsersAdministrationSub, param?: string): void { - this.administrationScreenService.navigateToItemSub( - UsersAdministrationNavigationService.ItemName, - sub, - param - ); + this.administrationScreenService.navigateToItemSub(UsersAdministrationNavigationService.ItemName, sub, param); } } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationService.ts index 49ed2f747b..e59319f154 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationService.ts @@ -5,13 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; import { AdministrationItemService } from '@cloudbeaver/core-administration'; import { AdminUser, TeamsResource } from '@cloudbeaver/core-authentication'; import { PlaceholderContainer } from '@cloudbeaver/core-blocks'; -import { injectable, Bootstrap } from '@cloudbeaver/core-di'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { CreateTeamService } from './Teams/CreateTeamService'; import { EUsersAdministrationSub, UsersAdministrationNavigationService } from './UsersAdministrationNavigationService'; @@ -78,7 +77,7 @@ export class UsersAdministrationService extends Bootstrap { this.userDetailsInfoPlaceholder.add(Origin, 0); } - load(): void | Promise { } + load(): void | Promise {} private async cancelCreate(param: string | null) { if (param === 'create') { diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersDrawerItem.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersDrawerItem.tsx index 7bf7cb0e0b..bef1632571 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersDrawerItem.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersDrawerItem.tsx @@ -5,28 +5,19 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled from 'reshadow'; import type { AdministrationItemDrawerProps } from '@cloudbeaver/core-administration'; import { Translate, useStyles } from '@cloudbeaver/core-blocks'; -import { Tab, TabTitle, TabIcon } from '@cloudbeaver/core-ui'; +import { Tab, TabIcon, TabTitle } from '@cloudbeaver/core-ui'; -export const UsersDrawerItem: React.FC = function UsersDrawerItem({ - item, - onSelect, - style, - disabled, -}) { +export const UsersDrawerItem: React.FC = function UsersDrawerItem({ item, onSelect, style, disabled }) { return styled(useStyles(style))( - onSelect(item.name)} - > - - - + onSelect(item.name)}> + + + + + , ); }; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/CreateUser.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/CreateUser.tsx index e8b84ec0e6..ec8759ff15 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/CreateUser.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/CreateUser.tsx @@ -5,62 +5,58 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled, { css } from 'reshadow'; - import { Translate } from '@cloudbeaver/core-blocks'; import type { AdminUserInfo } from '@cloudbeaver/core-sdk'; - import { UserForm } from '../UserForm/UserForm'; const styles = css` + user-create-footer, + user-create-content { + composes: theme-background-secondary theme-text-on-secondary from global; + } + user-create { + display: flex; + flex-direction: column; + height: 600px; + overflow: hidden; + } - user-create-footer, user-create-content { - composes: theme-background-secondary theme-text-on-secondary from global; - } - user-create { - display: flex; - flex-direction: column; - height: 600px; - overflow: hidden; - } + title-bar { + composes: theme-border-color-background theme-typography--headline6 from global; + box-sizing: border-box; + padding: 16px 24px; + align-items: center; + display: flex; + font-weight: 400; + flex: auto 0 0; + } - title-bar { - composes: theme-border-color-background theme-typography--headline6 from global; - box-sizing: border-box; - padding: 16px 24px; - align-items: center; - display: flex; - font-weight: 400; - flex: auto 0 0; - } - - user-create-content { - position: relative; - display: flex; - flex-direction: column; - flex: 1; - overflow: auto; - } - `; + user-create-content { + position: relative; + display: flex; + flex-direction: column; + flex: 1; + overflow: auto; + } +`; interface Props { user: AdminUserInfo; onCancel: () => void; } -export const CreateUser: React.FC = function CreateUser({ - user, - onCancel, -}) { +export const CreateUser: React.FC = function CreateUser({ user, onCancel }) { return styled(styles)( - + + + - + , ); }; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/CreateUserService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/CreateUserService.ts index 1b8f055412..095e2e98a6 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/CreateUserService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/CreateUserService.ts @@ -5,8 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { observable, makeObservable } from 'mobx'; +import { makeObservable, observable } from 'mobx'; import { UsersResource } from '@cloudbeaver/core-authentication'; import { injectable } from '@cloudbeaver/core-di'; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/Filters/UsersTableFilters.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/Filters/UsersTableFilters.tsx index dfbce9297d..609fdd3655 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/Filters/UsersTableFilters.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/Filters/UsersTableFilters.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useState } from 'react'; import styled, { css, use } from 'reshadow'; @@ -77,11 +76,8 @@ export const UsersTableFilters = observer(function UsersTableFilters({ fi onFilter={filters.setSearch} /> - @@ -99,17 +95,12 @@ export const UsersTableFilters = observer(function UsersTableFilters({ fi {translate('authentication_user_status')} {!!authRolesResource.data.length && ( - + {translate('authentication_user_role')} )} )} - + , ); -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/Filters/useUsersTableFilters.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/Filters/useUsersTableFilters.tsx index eb24630af7..5caf98418f 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/Filters/useUsersTableFilters.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/Filters/useUsersTableFilters.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, computed, observable } from 'mobx'; import type { AdminUser } from '@cloudbeaver/core-authentication'; @@ -16,7 +15,7 @@ import { isArraysEqual } from '@cloudbeaver/core-utils'; export enum EUserStatus { ENABLED = 'ENABLED', DISABLED = 'DISABLED', - ALL = 'ALL' + ALL = 'ALL', } interface IStatus { @@ -52,39 +51,42 @@ export interface IUserFilters { } export function useUsersTableFilters(users: AdminUser[]) { - const filters: IUserFilters = useObservableRef(() => ({ - search: '', - role: USER_ROLE_ALL, - status: EUserStatus.ENABLED, - get filteredUsers() { - return this.users.filter(user => { - const matchSearch = user.userId.toLowerCase().includes(this.search.trim().toLowerCase()); - const matchStatus = this.status === EUserStatus.ALL - || (this.status === EUserStatus.ENABLED ? user.enabled : !user.enabled); - const matchRole = this.role === USER_ROLE_ALL || this.role === user.authRole; + const filters: IUserFilters = useObservableRef( + () => ({ + search: '', + role: USER_ROLE_ALL, + status: EUserStatus.ENABLED, + get filteredUsers() { + return this.users.filter(user => { + const matchSearch = user.userId.toLowerCase().includes(this.search.trim().toLowerCase()); + const matchStatus = this.status === EUserStatus.ALL || (this.status === EUserStatus.ENABLED ? user.enabled : !user.enabled); + const matchRole = this.role === USER_ROLE_ALL || this.role === user.authRole; - return matchSearch && matchStatus && matchRole; - }); + return matchSearch && matchStatus && matchRole; + }); + }, + setSearch(value: string) { + this.search = value; + }, + setRole(role: string) { + this.role = role; + }, + setStatus(status: EUserStatus) { + this.status = status; + }, + }), + { + search: observable.ref, + role: observable.ref, + status: observable.ref, + users: observable.ref, + filteredUsers: computed({ equals: (first, second) => isArraysEqual(first, second, undefined, true) }), + setSearch: action.bound, + setRole: action.bound, + setStatus: action.bound, }, - setSearch(value: string) { - this.search = value; - }, - setRole(role: string) { - this.role = role; - }, - setStatus(status: EUserStatus) { - this.status = status; - }, - }), { - search: observable.ref, - role: observable.ref, - status: observable.ref, - users: observable.ref, - filteredUsers: computed({ equals: (first, second) => isArraysEqual(first, second, undefined, true) }), - setSearch: action.bound, - setRole: action.bound, - setStatus: action.bound, - }, { users }); + { users }, + ); return filters; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/User.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/User.tsx index e73f2a2ae2..8fdb3d96f4 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/User.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/User.tsx @@ -5,14 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css, use } from 'reshadow'; import { AdminUser, UsersResource } from '@cloudbeaver/core-authentication'; -import { - TableItem, TableColumnValue, TableItemSelect, TableItemExpand, Placeholder, Checkbox, useTranslate, Loader -} from '@cloudbeaver/core-blocks'; +import { Checkbox, Loader, Placeholder, TableColumnValue, TableItem, TableItemExpand, TableItemSelect, useTranslate } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; @@ -50,7 +47,8 @@ export const User = observer(function User({ user, displayAuthRole, selec } const enabledCheckboxTitle = usersService.isActiveUser(user.userId) - ? translate('administration_teams_team_granted_users_permission_denied') : undefined; + ? translate('administration_teams_team_granted_users_permission_denied') + : undefined; return styled(styles)( @@ -62,11 +60,17 @@ export const User = observer(function User({ user, displayAuthRole, selec - {user.userId} + + {user.userId} + {displayAuthRole && ( - {user.authRole} + + {user.authRole} + )} - {teams} + + {teams} + (function User({ user, displayAuthRole, selec - + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserDetailsInfo/Origin.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserDetailsInfo/Origin.tsx index bf83ef0172..b2f8af52b6 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserDetailsInfo/Origin.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserDetailsInfo/Origin.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -31,9 +30,7 @@ export const OriginIcon = observer(function Origin({ origin }) const icon = isLocal ? '/icons/local_connection.svg' : origin.icon; const title = isLocal ? 'Local user' : origin.displayName; - return styled(USER_DETAILS_STYLES)( - - ); + return styled(USER_DETAILS_STYLES)(); }); export const Origin: PlaceholderComponent = observer(function Origin({ user }) { diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserEdit.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserEdit.tsx index 38127a001f..7057536b33 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserEdit.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserEdit.tsx @@ -5,39 +5,32 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { useContext, useCallback, useEffect, useRef } from 'react'; +import { useCallback, useContext, useEffect, useRef } from 'react'; import styled, { css } from 'reshadow'; -import { - Loader, - TableContext -} from '@cloudbeaver/core-blocks'; +import { Loader, TableContext } from '@cloudbeaver/core-blocks'; import { useController } from '@cloudbeaver/core-di'; - import { UserForm } from '../UserForm/UserForm'; import { UserEditController } from './UserEditController'; const styles = css` - box { - composes: theme-background-secondary theme-text-on-secondary from global; - box-sizing: border-box; - padding-bottom: 24px; - height: 560px; - display: flex; - flex-direction: column; - } - `; + box { + composes: theme-background-secondary theme-text-on-secondary from global; + box-sizing: border-box; + padding-bottom: 24px; + height: 560px; + display: flex; + flex-direction: column; + } +`; interface Props { item: string; } -export const UserEdit = observer(function UserEdit({ - item, -}) { +export const UserEdit = observer(function UserEdit({ item }) { const boxRef = useRef(null); const controller = useController(UserEditController, item); const tableContext = useContext(TableContext); @@ -51,10 +44,8 @@ export const UserEdit = observer(function UserEdit({ }, []); return styled(styles)( - - {controller.user ? ( - - ) : } - + + {controller.user ? : } + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserEditController.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserEditController.ts index e89865cc7a..4e391c620e 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserEditController.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserEditController.ts @@ -5,19 +5,15 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { observable, computed, makeObservable } from 'mobx'; +import { computed, makeObservable, observable } from 'mobx'; import { UsersResource } from '@cloudbeaver/core-authentication'; -import { - injectable, IInitializableController, IDestructibleController -} from '@cloudbeaver/core-di'; +import { IDestructibleController, IInitializableController, injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; -import { GQLErrorCatcher, AdminUserInfo, ResourceKeyUtils, ResourceKey, ResourceKeySimple } from '@cloudbeaver/core-sdk'; +import { AdminUserInfo, GQLErrorCatcher, ResourceKey, ResourceKeySimple, ResourceKeyUtils } from '@cloudbeaver/core-sdk'; @injectable() -export class UserEditController -implements IInitializableController, IDestructibleController { +export class UserEditController implements IInitializableController, IDestructibleController { isLoading = true; user: AdminUserInfo | null = null; @@ -29,10 +25,7 @@ implements IInitializableController, IDestructibleController { readonly error = new GQLErrorCatcher(); - constructor( - private readonly notificationService: NotificationService, - private readonly usersResource: UsersResource - ) { + constructor(private readonly notificationService: NotificationService, private readonly usersResource: UsersResource) { makeObservable(this, { isLoading: observable, user: observable, diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UsersPage.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UsersPage.tsx index b304f1e4b8..10125e7623 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UsersPage.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UsersPage.tsx @@ -5,16 +5,22 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; import { ADMINISTRATION_TOOLS_PANEL_STYLES, IAdministrationItemSubItem } from '@cloudbeaver/core-administration'; -import { AuthProvidersResource, AuthRolesResource, AUTH_PROVIDER_LOCAL_ID, UsersResource } from '@cloudbeaver/core-authentication'; +import { AUTH_PROVIDER_LOCAL_ID, AuthProvidersResource, AuthRolesResource, UsersResource } from '@cloudbeaver/core-authentication'; import { - useResource, ToolsAction, - ToolsPanel, Loader, useTranslate, useStyles, - BASE_CONTAINERS_STYLES, ColoredContainer, Container, Group + BASE_CONTAINERS_STYLES, + ColoredContainer, + Container, + Group, + Loader, + ToolsAction, + ToolsPanel, + useResource, + useStyles, + useTranslate, } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; @@ -69,7 +75,7 @@ export const UsersPage = observer(function UsersPage({ sub, param }) { {isLocalProviderAvailable && ( (function UsersPage({ sub, param }) { )} @@ -109,7 +115,7 @@ export const UsersPage = observer(function UsersPage({ sub, param }) { )} - + (function UsersPage({ sub, param }) { - + , ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UsersTable.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UsersTable.tsx index 419c47a8d7..df337f534f 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UsersTable.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UsersTable.tsx @@ -5,11 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { - Table, TableHeader, TableColumnHeader, TableBody, useTranslate } from '@cloudbeaver/core-blocks'; +import { Table, TableBody, TableColumnHeader, TableHeader, useTranslate } from '@cloudbeaver/core-blocks'; import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; import { User } from './User'; @@ -22,22 +20,11 @@ interface Props { displayAuthRole: boolean; } -export const UsersTable = observer(function UsersTable({ - keys, - users, - selectedItems, - expandedItems, - displayAuthRole, -}) { +export const UsersTable = observer(function UsersTable({ keys, users, selectedItems, expandedItems, displayAuthRole }) { const translate = useTranslate(); return ( - +
{/* {isLocalProviderAvailable && ( @@ -46,9 +33,7 @@ export const UsersTable = observer(function UsersTable({ )} */} {translate('authentication_user_name')} - {displayAuthRole && ( - {translate('authentication_user_role')} - )} + {displayAuthRole && {translate('authentication_user_role')}} {translate('authentication_user_team')} {translate('authentication_user_enabled')} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/useUsersTable.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/useUsersTable.tsx index 53a93c53fe..163a8ec557 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/useUsersTable.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/useUsersTable.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, computed, observable } from 'mobx'; import type { AdminUser, UsersResource } from '@cloudbeaver/core-authentication'; @@ -29,13 +28,12 @@ export function useUsersTable(usersResource: UsersResource) { const notificationService = useService(NotificationService); const commonDialogService = useService(CommonDialogService); - const state: State = useObservableRef(() => ({ - loading: false, - state: new TableState(), - get users() { - return this.usersResource.values - .slice() - .sort((a, b) => { + const state: State = useObservableRef( + () => ({ + loading: false, + state: new TableState(), + get users() { + return this.usersResource.values.slice().sort((a, b) => { if (this.usersResource.isNew(a.userId) === this.usersResource.isNew(b.userId)) { return a.userId.localeCompare(b.userId); } @@ -44,60 +42,62 @@ export function useUsersTable(usersResource: UsersResource) { } return 1; }); - }, - async update() { - try { - await this.usersResource.refreshAll(); - notificationService.logSuccess({ title: 'authentication_administration_tools_refresh_success' }); - } catch (exception: any) { - notificationService.logException(exception, 'authentication_administration_tools_refresh_fail'); - } - }, - async delete() { - if (this.loading) { - return; - } - - const deletionList = this.state.selectedList.filter(([_, value]) => value).map(([userId]) => userId); - if (deletionList.length === 0) { - return; - } - - const userNames = deletionList.map(name => `"${name}"`).join(', '); - const message = `${translate('authentication_administration_users_delete_confirmation')}${userNames}. ${translate('ui_are_you_sure')}`; - - const result = await commonDialogService.open(ConfirmationDialogDelete, { - title: 'ui_data_delete_confirmation', - message, - confirmActionText: 'ui_delete', - }); - - if (result === DialogueStateResult.Rejected) { - return; - } - - this.loading = true; - - try { - await this.usersResource.delete(resourceKeyList(deletionList)); - this.state.unselect(); - - for (const id of deletionList) { - this.state.unexpand(id); + }, + async update() { + try { + await this.usersResource.refreshAll(); + notificationService.logSuccess({ title: 'authentication_administration_tools_refresh_success' }); + } catch (exception: any) { + notificationService.logException(exception, 'authentication_administration_tools_refresh_fail'); + } + }, + async delete() { + if (this.loading) { + return; } - } catch (exception: any) { - notificationService.logException(exception, 'authentication_administration_user_delete_fail'); - } finally { - this.loading = false; - } + const deletionList = this.state.selectedList.filter(([_, value]) => value).map(([userId]) => userId); + if (deletionList.length === 0) { + return; + } + + const userNames = deletionList.map(name => `"${name}"`).join(', '); + const message = `${translate('authentication_administration_users_delete_confirmation')}${userNames}. ${translate('ui_are_you_sure')}`; + + const result = await commonDialogService.open(ConfirmationDialogDelete, { + title: 'ui_data_delete_confirmation', + message, + confirmActionText: 'ui_delete', + }); + + if (result === DialogueStateResult.Rejected) { + return; + } + + this.loading = true; + + try { + await this.usersResource.delete(resourceKeyList(deletionList)); + this.state.unselect(); + + for (const id of deletionList) { + this.state.unexpand(id); + } + } catch (exception: any) { + notificationService.logException(exception, 'authentication_administration_user_delete_fail'); + } finally { + this.loading = false; + } + }, + }), + { + loading: observable.ref, + users: computed({ equals: (first, second) => isArraysEqual(first, second, undefined, true) }), + update: action.bound, + delete: action.bound, }, - }), { - loading: observable.ref, - users: computed({ equals: (first, second) => isArraysEqual(first, second, undefined, true) }), - update: action.bound, - delete: action.bound, - }, { usersResource }); + { usersResource }, + ); return state; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-authentication-administration/src/AuthenticationLocaleService.ts b/webapp/packages/plugin-authentication-administration/src/AuthenticationLocaleService.ts index 4990d5b851..742afeeb87 100644 --- a/webapp/packages/plugin-authentication-administration/src/AuthenticationLocaleService.ts +++ b/webapp/packages/plugin-authentication-administration/src/AuthenticationLocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class AuthenticationLocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-authentication-administration/src/PluginBootstrap.ts b/webapp/packages/plugin-authentication-administration/src/PluginBootstrap.ts index 93c961b99e..2a982a341c 100644 --- a/webapp/packages/plugin-authentication-administration/src/PluginBootstrap.ts +++ b/webapp/packages/plugin-authentication-administration/src/PluginBootstrap.ts @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; -import { injectable, Bootstrap } from '@cloudbeaver/core-di'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { ServerConfigurationAdministrationNavService, ServerConfigurationService } from '@cloudbeaver/plugin-administration'; import { AuthenticationService } from '@cloudbeaver/plugin-authentication'; @@ -25,20 +24,16 @@ export class PluginBootstrap extends Bootstrap { private readonly serverConfigurationService: ServerConfigurationService, private readonly serverConfigurationAdministrationNavService: ServerConfigurationAdministrationNavService, private readonly authConfigurationsAdministrationNavService: AuthConfigurationsAdministrationNavService, - private readonly authenticationService: AuthenticationService + private readonly authenticationService: AuthenticationService, ) { super(); } register(): void { this.serverConfigurationService.configurationContainer.add(AuthenticationProviders, 0); - this.authenticationService.setConfigureAuthProvider( - () => this.serverConfigurationAdministrationNavService.navToSettings() - ); - this.authenticationService.setConfigureIdentityProvider( - () => this.authConfigurationsAdministrationNavService.navToCreate() - ); + this.authenticationService.setConfigureAuthProvider(() => this.serverConfigurationAdministrationNavService.navToSettings()); + this.authenticationService.setConfigureIdentityProvider(() => this.authConfigurationsAdministrationNavService.navToCreate()); } - load(): void | Promise { } + load(): void | Promise {} } diff --git a/webapp/packages/plugin-authentication-administration/src/locales/en.ts b/webapp/packages/plugin-authentication-administration/src/locales/en.ts index 161e83ef8b..0f1ac4c8d0 100644 --- a/webapp/packages/plugin-authentication-administration/src/locales/en.ts +++ b/webapp/packages/plugin-authentication-administration/src/locales/en.ts @@ -1,7 +1,7 @@ export default [ ['authentication_administration_user_connections_user_add', 'User Creation'], ['authentication_administration_user_connections_user_new', 'New user'], - ['authentication_administration_user_connections_access_load_fail', 'User\'s granted connections loading failed'], + ['authentication_administration_user_connections_access_load_fail', "User's granted connections loading failed"], ['authentication_administration_user_connections_access_connections_load_fail', 'Connections loading failed'], ['authentication_administration_user_connections_access', 'Connections Access'], ['authentication_administration_user_connections_access_granted_by', 'Granted by'], @@ -39,7 +39,10 @@ export default [ ['administration_configuration_wizard_configuration_services_group', 'Services'], ['administration_configuration_wizard_configuration_services', 'Services'], ['administration_configuration_wizard_configuration_authentication', 'Enable users authentication'], - ['administration_configuration_wizard_configuration_authentication_description', 'Allows users to authenticate. Otherwise only anonymous access is enabled'], + [ + 'administration_configuration_wizard_configuration_authentication_description', + 'Allows users to authenticate. Otherwise only anonymous access is enabled', + ], ['administration_identity_providers_tab_title', 'Identity Providers'], ['administration_identity_providers_provider', 'Provider'], diff --git a/webapp/packages/plugin-authentication-administration/src/locales/it.ts b/webapp/packages/plugin-authentication-administration/src/locales/it.ts index 52c9cc25a0..e6b0ae7d00 100644 --- a/webapp/packages/plugin-authentication-administration/src/locales/it.ts +++ b/webapp/packages/plugin-authentication-administration/src/locales/it.ts @@ -1,7 +1,7 @@ export default [ ['authentication_administration_user_connections_user_add', 'Creazione di Utente'], ['authentication_administration_user_connections_user_new', 'Nuovo utente'], - ['authentication_administration_user_connections_access_load_fail', 'Errore in fase di caricamento delle connessioni autorizzate all\'utente'], + ['authentication_administration_user_connections_access_load_fail', "Errore in fase di caricamento delle connessioni autorizzate all'utente"], ['authentication_administration_user_connections_access_connections_load_fail', 'Errore in fase di caricamento delle connessioni'], ['authentication_administration_user_connections_access', 'Accesso alle connessioni'], ['authentication_administration_user_connections_access_granted_by', 'Permesso da'], @@ -34,10 +34,13 @@ export default [ ['administration_configuration_wizard_configuration_admin', 'Credenziali amministrative'], ['administration_configuration_wizard_configuration_admin_name', 'Login'], ['administration_configuration_wizard_configuration_admin_password', 'Password'], - ['administration_configuration_wizard_configuration_anonymous_access', 'Permetti l\'accesso anonimo'], + ['administration_configuration_wizard_configuration_anonymous_access', "Permetti l'accesso anonimo"], ['administration_configuration_wizard_configuration_anonymous_access_description', 'Permetti di lavorare con CloudBeaver senza autenticazione'], ['administration_configuration_wizard_configuration_authentication_group', 'Impostazioni di autenticazione'], ['administration_configuration_wizard_configuration_services', 'Servizi'], - ['administration_configuration_wizard_configuration_authentication', 'Abilita l\'autenticazione utente'], - ['administration_configuration_wizard_configuration_authentication_description', 'Permetti agli utenti di autenticarsi. In alternativa solo l\'accesso anonimo sarà attivo'], + ['administration_configuration_wizard_configuration_authentication', "Abilita l'autenticazione utente"], + [ + 'administration_configuration_wizard_configuration_authentication_description', + "Permetti agli utenti di autenticarsi. In alternativa solo l'accesso anonimo sarà attivo", + ], ]; diff --git a/webapp/packages/plugin-authentication-administration/src/locales/ru.ts b/webapp/packages/plugin-authentication-administration/src/locales/ru.ts index e5828b9155..f31162838b 100644 --- a/webapp/packages/plugin-authentication-administration/src/locales/ru.ts +++ b/webapp/packages/plugin-authentication-administration/src/locales/ru.ts @@ -34,11 +34,17 @@ export default [ ['administration_configuration_wizard_configuration_admin_name', 'Логин'], ['administration_configuration_wizard_configuration_admin_password', 'Пароль'], ['administration_configuration_wizard_configuration_anonymous_access', 'Разрешить анонимный доступ'], - ['administration_configuration_wizard_configuration_anonymous_access_description', 'Позволяет работать с CloudBeaver без пользовательской аутентификации'], + [ + 'administration_configuration_wizard_configuration_anonymous_access_description', + 'Позволяет работать с CloudBeaver без пользовательской аутентификации', + ], ['administration_configuration_wizard_configuration_authentication_group', 'Настройки аутентификации'], ['administration_configuration_wizard_configuration_services_group', 'Сервисы'], ['administration_configuration_wizard_configuration_authentication', 'Включить пользовательскую аутентификацию'], - ['administration_configuration_wizard_configuration_authentication_description', 'Позволяет пользователям аутентифицироваться. Иначе будет включен анонимный доступ'], + [ + 'administration_configuration_wizard_configuration_authentication_description', + 'Позволяет пользователям аутентифицироваться. Иначе будет включен анонимный доступ', + ], ['administration_identity_providers_tab_title', 'Провайдеры идентификации'], ['administration_identity_providers_provider', 'Провайдер'], diff --git a/webapp/packages/plugin-authentication-administration/src/manifest.ts b/webapp/packages/plugin-authentication-administration/src/manifest.ts index 7901338a55..1e4db34826 100644 --- a/webapp/packages/plugin-authentication-administration/src/manifest.ts +++ b/webapp/packages/plugin-authentication-administration/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { AuthConfigurationFormService } from './Administration/IdentityProviders/AuthConfigurationFormService'; diff --git a/webapp/packages/plugin-authentication/src/AuthenticationLocaleService.ts b/webapp/packages/plugin-authentication/src/AuthenticationLocaleService.ts index 4990d5b851..742afeeb87 100644 --- a/webapp/packages/plugin-authentication/src/AuthenticationLocaleService.ts +++ b/webapp/packages/plugin-authentication/src/AuthenticationLocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class AuthenticationLocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-authentication/src/AuthenticationService.ts b/webapp/packages/plugin-authentication/src/AuthenticationService.ts index 7d35ebcd66..5083ee18bc 100644 --- a/webapp/packages/plugin-authentication/src/AuthenticationService.ts +++ b/webapp/packages/plugin-authentication/src/AuthenticationService.ts @@ -5,12 +5,21 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable } from 'mobx'; import { AdministrationScreenService } from '@cloudbeaver/core-administration'; -import { AppAuthService, AuthInfoService, AuthProviderContext, AuthProviderService, AuthProvidersResource, AUTH_PROVIDER_LOCAL_ID, IUserAuthConfiguration, RequestedProvider, UserInfoResource } from '@cloudbeaver/core-authentication'; -import { injectable, Bootstrap } from '@cloudbeaver/core-di'; +import { + AppAuthService, + AUTH_PROVIDER_LOCAL_ID, + AuthInfoService, + AuthProviderContext, + AuthProviderService, + AuthProvidersResource, + IUserAuthConfiguration, + RequestedProvider, + UserInfoResource, +} from '@cloudbeaver/core-authentication'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import type { DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; import { Executor, ExecutorInterrupter, IExecutionContextProvider, IExecutorHandler } from '@cloudbeaver/core-executor'; @@ -85,8 +94,9 @@ export class AuthenticationService extends Bootstrap { let userAuthConfiguration: IUserAuthConfiguration | undefined = undefined; if (providerId) { - userAuthConfiguration = this.authInfoService.userAuthConfigurations - .find(c => c.providerId === providerId && c.configuration.id === configurationId); + userAuthConfiguration = this.authInfoService.userAuthConfigurations.find( + c => c.providerId === providerId && c.configuration.id === configurationId, + ); } else if (this.authInfoService.userAuthConfigurations.length > 0) { userAuthConfiguration = this.authInfoService.userAuthConfigurations[0]; } @@ -104,7 +114,7 @@ export class AuthenticationService extends Bootstrap { await this.onLogout.execute('after'); } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t logout'); + this.notificationService.logException(exception, "Can't logout"); } } @@ -139,7 +149,8 @@ export class AuthenticationService extends Bootstrap { options = observable(options); - this.authPromise = this.authDialogService.showLoginForm(persistent, options) + this.authPromise = this.authDialogService + .showLoginForm(persistent, options) .then(async state => { await this.onLogin.execute('after'); return state; @@ -151,8 +162,7 @@ export class AuthenticationService extends Bootstrap { if (this.serverConfigResource.redirectOnFederatedAuth) { await this.authProvidersResource.load(CachedMapAllKey); - const providers = this.authProvidersResource - .getEnabledProviders(); + const providers = this.authProvidersResource.getEnabledProviders(); if (providers.length === 1) { const configurableProvider = providers.find(provider => provider.configurable); @@ -186,7 +196,9 @@ export class AuthenticationService extends Bootstrap { // ); this.sessionActionService.onAction.addHandler(this.authSessionAction.bind(this)); - this.sessionDataResource.onDataUpdate.addPostHandler(() => { this.requireAuthentication(); }); + this.sessionDataResource.onDataUpdate.addPostHandler(() => { + this.requireAuthentication(); + }); this.screenService.routeChange.addHandler(() => this.requireAuthentication()); this.administrationScreenService.ensurePermissions.addHandler(async () => { @@ -202,12 +214,9 @@ export class AuthenticationService extends Bootstrap { this.authProviderService.requestAuthProvider.addHandler(this.requestAuthProviderHandler); } - load(): void { } + load(): void {} - private async authSessionAction( - data: ISessionAction | null, - contexts: IExecutionContextProvider - ) { + private async authSessionAction(data: ISessionAction | null, contexts: IExecutionContextProvider) { const action = contexts.getContext(sessionActionContext); if (isAutoLoginSessionAction(data)) { diff --git a/webapp/packages/plugin-authentication/src/Dialog/AuthDialog.tsx b/webapp/packages/plugin-authentication/src/Dialog/AuthDialog.tsx index a9866573c8..49121880d1 100644 --- a/webapp/packages/plugin-authentication/src/Dialog/AuthDialog.tsx +++ b/webapp/packages/plugin-authentication/src/Dialog/AuthDialog.tsx @@ -5,15 +5,21 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css, use } from 'reshadow'; import { AuthProvider, UserInfoResource } from '@cloudbeaver/core-authentication'; -import { SubmittingForm, ErrorMessage, TextPlaceholder, Link, useErrorDetails, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { ErrorMessage, Link, SubmittingForm, TextPlaceholder, useErrorDetails, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; -import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogService, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs'; -import { TabsState, TabList, Tab, TabTitle, UNDERLINE_TAB_STYLES, BASE_TAB_STYLES } from '@cloudbeaver/core-ui'; +import { + CommonDialogBody, + CommonDialogFooter, + CommonDialogHeader, + CommonDialogService, + CommonDialogWrapper, + DialogComponent, +} from '@cloudbeaver/core-dialogs'; +import { BASE_TAB_STYLES, Tab, TabList, TabsState, TabTitle, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui'; import { AuthenticationService } from '../AuthenticationService'; import type { IAuthOptions } from '../IAuthOptions'; @@ -24,50 +30,46 @@ import { FEDERATED_AUTH } from './FEDERATED_AUTH'; import { useAuthDialogState } from './useAuthDialogState'; const styles = css` - CommonDialogWrapper { - min-height: 520px !important; - max-height: max(100vh - 48px, 520px) !important; + CommonDialogWrapper { + min-height: 520px !important; + max-height: max(100vh - 48px, 520px) !important; + } + SubmittingForm { + overflow: auto; + &[|form] { + margin: auto; } - SubmittingForm { - overflow: auto; - &[|form] { - margin: auto; - } - } - SubmittingForm, AuthProviderForm { - flex: 1; - display: flex; - flex-direction: column; - } - TabList { - justify-content: center; - } - Tab { - text-transform: uppercase; - &:global([aria-selected=true]) { - font-weight: 500 !important; - } - } - AuthProviderForm { - flex-direction: column; - padding: 18px 24px; - } - ConfigurationsList { - margin-top: 12px; - } - ErrorMessage { - composes: theme-background-secondary theme-text-on-secondary from global; - flex: 1; + } + SubmittingForm, + AuthProviderForm { + flex: 1; + display: flex; + flex-direction: column; + } + TabList { + justify-content: center; + } + Tab { + text-transform: uppercase; + &:global([aria-selected='true']) { + font-weight: 500 !important; } + } + AuthProviderForm { + flex-direction: column; + padding: 18px 24px; + } + ConfigurationsList { + margin-top: 12px; + } + ErrorMessage { + composes: theme-background-secondary theme-text-on-secondary from global; + flex: 1; + } `; export const AuthDialog: DialogComponent = observer(function AuthDialog({ - payload: { - providerId, - configurationId, - linkUser = false, - accessRequest = false, - }, + payload: { providerId, configurationId, linkUser = false, accessRequest = false }, options, rejectDialog, }) { @@ -79,13 +81,9 @@ export const AuthDialog: DialogComponent = observer(function const translate = useTranslate(); const state = dialogData.state; - const additional = userInfo.data !== null - && state.activeProvider?.id !== undefined - && !userInfo.hasToken(state.activeProvider.id); + const additional = userInfo.data !== null && state.activeProvider?.id !== undefined && !userInfo.hasToken(state.activeProvider.id); - const showTabs = ( - (dialogData.providers.length + dialogData.configurations.length) > 1 - ); + const showTabs = dialogData.providers.length + dialogData.configurations.length > 1; const federate = state.tabId === FEDERATED_AUTH; let dialogTitle = translate('authentication_login_dialog_title'); @@ -98,7 +96,7 @@ export const AuthDialog: DialogComponent = observer(function icon = state.activeProvider.icon; if (state.activeConfiguration) { - dialogTitle += `: ${state.activeConfiguration.displayName}`; + dialogTitle += `: ${state.activeConfiguration.displayName}`; subTitle = state.activeConfiguration.description; icon = state.activeConfiguration.iconURL || icon; } @@ -132,7 +130,11 @@ export const AuthDialog: DialogComponent = observer(function {translate('authentication_provider_disabled')} {authenticationService.configureAuthProvider && ( - { navToSettings(); }}> + { + navToSettings(); + }} + > {translate('ui_configure')} )} @@ -140,34 +142,30 @@ export const AuthDialog: DialogComponent = observer(function ); } - return ( - - ); + return ; } return styled(useStyles(BASE_TAB_STYLES, styles, UNDERLINE_TAB_STYLES))( - { state.setTabId(tabData.tabId); }}> - - + { + state.setTabId(tabData.tabId); + }} + > + + {showTabs && ( - + {dialogData.providers.map(provider => ( { state.setActiveProvider(provider); }} + onClick={() => { + state.setActiveProvider(provider); + }} > {provider.label} @@ -178,7 +176,9 @@ export const AuthDialog: DialogComponent = observer(function tabId={FEDERATED_AUTH} title={translate('authentication_auth_federated')} disabled={dialogData.authenticating} - onClick={() => { state.setActiveProvider(null); }} + onClick={() => { + state.setActiveProvider(null); + }} > {translate('authentication_auth_federated')} @@ -196,16 +196,14 @@ export const AuthDialog: DialogComponent = observer(function }} onClose={rejectDialog} /> - ) : renderForm(state.activeProvider)} + ) : ( + renderForm(state.activeProvider) + )} {!federate && ( - + {errorDetails.name && ( = observer(function )} - + , ); }); diff --git a/webapp/packages/plugin-authentication/src/Dialog/AuthDialogFooter.tsx b/webapp/packages/plugin-authentication/src/Dialog/AuthDialogFooter.tsx index f43a955a59..a10d97bf84 100644 --- a/webapp/packages/plugin-authentication/src/Dialog/AuthDialogFooter.tsx +++ b/webapp/packages/plugin-authentication/src/Dialog/AuthDialogFooter.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -33,26 +32,15 @@ export interface Props extends React.PropsWithChildren { onLogin: () => void; } -export const AuthDialogFooter = observer(function AuthDialogFooter({ - authAvailable, - isAuthenticating, - onLogin, - children, -}) { +export const AuthDialogFooter = observer(function AuthDialogFooter({ authAvailable, isAuthenticating, onLogin, children }) { const translate = useTranslate(); return styled(styles)( {children} - - + , ); }); diff --git a/webapp/packages/plugin-authentication/src/Dialog/AuthDialogService.ts b/webapp/packages/plugin-authentication/src/Dialog/AuthDialogService.ts index 701eb18a28..f6d0e9fab0 100644 --- a/webapp/packages/plugin-authentication/src/Dialog/AuthDialogService.ts +++ b/webapp/packages/plugin-authentication/src/Dialog/AuthDialogService.ts @@ -5,7 +5,6 @@ * 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 { CommonDialogService, DialogueStateResult } from '@cloudbeaver/core-dialogs'; @@ -21,9 +20,7 @@ export class AuthDialogService { private persistent: boolean; private dialog: Promise | null; - constructor( - private readonly commonDialogService: CommonDialogService - ) { + constructor(private readonly commonDialogService: CommonDialogService) { this.persistent = false; this.dialog = null; } @@ -32,7 +29,7 @@ export class AuthDialogService { persistent = false, options: IAuthOptions = { providerId: null, - } + }, ): Promise { if (this.dialog) { return this.dialog; diff --git a/webapp/packages/plugin-authentication/src/Dialog/AuthProviderForm/AuthProviderForm.tsx b/webapp/packages/plugin-authentication/src/Dialog/AuthProviderForm/AuthProviderForm.tsx index 48e033ae81..e5cef781d1 100644 --- a/webapp/packages/plugin-authentication/src/Dialog/AuthProviderForm/AuthProviderForm.tsx +++ b/webapp/packages/plugin-authentication/src/Dialog/AuthProviderForm/AuthProviderForm.tsx @@ -5,25 +5,19 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; import type { AuthProvider, IAuthCredentials } from '@cloudbeaver/core-authentication'; import { BASE_CONTAINERS_STYLES, Combobox, Group, InputField, useFocus, useStyles } from '@cloudbeaver/core-blocks'; - interface Props { provider: AuthProvider; credentials: IAuthCredentials; authenticate: boolean; } -export const AuthProviderForm = observer(function AuthProviderForm({ - provider, - credentials, - authenticate, -}) { +export const AuthProviderForm = observer(function AuthProviderForm({ provider, credentials, authenticate }) { const [elementRef] = useFocus({ focusFirstChild: true }); function handleProfileSelect() { @@ -47,20 +41,23 @@ export const AuthProviderForm = observer(function AuthProviderForm({ onSelect={handleProfileSelect} /> )} - {profile.credentialParameters.map(parameter => parameter.user && ( - - {parameter.displayName} - - ))} - + {profile.credentialParameters.map( + parameter => + parameter.user && ( + + {parameter.displayName} + + ), + )} + , ); }); diff --git a/webapp/packages/plugin-authentication/src/Dialog/AuthProviderForm/ConfigurationsList.tsx b/webapp/packages/plugin-authentication/src/Dialog/AuthProviderForm/ConfigurationsList.tsx index 2fd0e97281..ff7ca66df6 100644 --- a/webapp/packages/plugin-authentication/src/Dialog/AuthProviderForm/ConfigurationsList.tsx +++ b/webapp/packages/plugin-authentication/src/Dialog/AuthProviderForm/ConfigurationsList.tsx @@ -5,53 +5,64 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useState } from 'react'; import styled, { css } from 'reshadow'; import { AuthInfoService, AuthProvider, AuthProviderConfiguration, comparePublicAuthConfigurations } from '@cloudbeaver/core-authentication'; -import { Filter, IconOrImage, Link, Cell, getComputed, TextPlaceholder, usePromiseState, Loader, Button, useTranslate, useStyles, Translate } from '@cloudbeaver/core-blocks'; +import { + Button, + Cell, + Filter, + getComputed, + IconOrImage, + Link, + Loader, + TextPlaceholder, + Translate, + usePromiseState, + useStyles, + useTranslate, +} from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; import type { ITask } from '@cloudbeaver/core-executor'; import type { UserInfo } from '@cloudbeaver/core-sdk'; - import { AuthenticationService } from '../../AuthenticationService'; const styles = css` - container { - display: flex; - flex-direction: column; - overflow: auto; - flex: 1; - } - Filter { - margin: 0 24px 12px 24px; - } - list { - overflow: auto; - } - Cell { - composes: theme-border-color-secondary from global; - border-bottom: 1px solid; - padding: 0 16px; - } - IconOrImage { - width: 100%; - height: 100%; - } - center { - margin: auto; - } + container { + display: flex; + flex-direction: column; + overflow: auto; + flex: 1; + } + Filter { + margin: 0 24px 12px 24px; + } + list { + overflow: auto; + } + Cell { + composes: theme-border-color-secondary from global; + border-bottom: 1px solid; + padding: 0 16px; + } + IconOrImage { + width: 100%; + height: 100%; + } + center { + margin: auto; + } `; const loaderStyle = css` - ExceptionMessage { - padding: 24px; - } - `; + ExceptionMessage { + padding: 24px; + } +`; interface IProviderConfiguration { provider: AuthProvider; @@ -84,17 +95,15 @@ export const ConfigurationsList = observer(function ConfigurationsList({ const [search, setSearch] = useState(''); const [authTask, setAuthTask] = useState | null>(null); const authTaskState = usePromiseState(authTask); - const configurations = getComputed(() => providers.map( - provider => ( - (provider.configurations || []) - .filter(configuration => configuration.signInLink) - .map(configuration => ({ provider, configuration })) - )).flat() + const configurations = getComputed(() => + providers + .map(provider => + (provider.configurations || []).filter(configuration => configuration.signInLink).map(configuration => ({ provider, configuration })), + ) + .flat(), ); - const sortedConfigurations = configurations - .slice() - .sort((a, b) => comparePublicAuthConfigurations(a.configuration, b.configuration)); + const sortedConfigurations = configurations.slice().sort((a, b) => comparePublicAuthConfigurations(a.configuration, b.configuration)); let filteredConfigurations: IProviderConfiguration[]; @@ -138,11 +147,7 @@ export const ConfigurationsList = observer(function ConfigurationsList({ return ( {translate('authentication_configure')} - {authenticationService.configureIdentityProvider && ( - - {translate('ui_configure')} - - )} + {authenticationService.configureIdentityProvider && {translate('ui_configure')}} ); } @@ -150,64 +155,36 @@ export const ConfigurationsList = observer(function ConfigurationsList({ if (activeProvider && activeConfiguration) { return styled(style)( - +
-
-
+ , ); } return styled(style)( {configurations.length >= 10 && ( - + )} {filteredConfigurations.map(({ provider, configuration }) => { const icon = configuration.iconURL || provider.icon; const title = `${configuration.displayName}\n${configuration.description || ''}`; return ( - auth({ provider, configuration })} - > - : undefined} - description={configuration.description} - > + auth({ provider, configuration })}> + : undefined} description={configuration.description}> {configuration.displayName} ); })} - - + + , ); }); diff --git a/webapp/packages/plugin-authentication/src/Dialog/useAuthDialogState.ts b/webapp/packages/plugin-authentication/src/Dialog/useAuthDialogState.ts index 361adcd535..dce7aaf7b5 100644 --- a/webapp/packages/plugin-authentication/src/Dialog/useAuthDialogState.ts +++ b/webapp/packages/plugin-authentication/src/Dialog/useAuthDialogState.ts @@ -5,13 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, computed, observable } from 'mobx'; import { useEffect } from 'react'; import { AdministrationScreenService } from '@cloudbeaver/core-administration'; import { AuthInfoService, AuthProvider, AuthProviderConfiguration, AuthProvidersResource, IAuthCredentials } from '@cloudbeaver/core-authentication'; -import { useResource, useObservableRef } from '@cloudbeaver/core-blocks'; +import { useObservableRef, useResource } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; @@ -50,72 +49,68 @@ export function useAuthDialogState(accessRequest: boolean, providerId: string | const primaryId = authProvidersResource.resource.getPrimary(); const adminPageActive = administrationScreenService.isAdministrationPageActive; - const providers = authProvidersResource.data - .filter(notEmptyProvider) - .sort(compareProviders); + const providers = authProvidersResource.data.filter(notEmptyProvider).sort(compareProviders); - const state = useObservableRef(() => ({ - tabId: null, - activeProvider: null, - activeConfiguration: null, - credentials: { - profile: '0', - credentials: {}, + const state = useObservableRef( + () => ({ + tabId: null, + activeProvider: null, + activeConfiguration: null, + credentials: { + profile: '0', + credentials: {}, + }, + + setTabId(tabId: string): void { + this.tabId = tabId; + }, + setActiveProvider(provider: AuthProvider | null): void { + this.activeProvider = provider; + this.credentials.profile = '0'; + this.credentials.credentials = {}; + this.activeConfiguration = null; + }, + setActiveConfiguration(provider: AuthProvider | null, configuration: AuthProviderConfiguration | null): void { + this.setActiveProvider(provider); + this.activeConfiguration = configuration; + }, + }), + { + tabId: observable.ref, + activeProvider: observable.ref, + activeConfiguration: observable.ref, + credentials: observable, + setActiveProvider: action, + setActiveConfiguration: action, }, + false, + ); - setTabId(tabId: string): void { - this.tabId = tabId; - }, - setActiveProvider(provider: AuthProvider | null): void { - this.activeProvider = provider; - this.credentials.profile = '0'; - this.credentials.credentials = {}; - this.activeConfiguration = null; - }, - setActiveConfiguration( - provider: AuthProvider | null, - configuration: AuthProviderConfiguration | null - ): void { - this.setActiveProvider(provider); - this.activeConfiguration = configuration; - }, - }), { - tabId: observable.ref, - activeProvider: observable.ref, - activeConfiguration: observable.ref, - credentials: observable, - setActiveProvider: action, - setActiveConfiguration: action, - }, false); - - const activeProviders = providers - .filter(provider => { - if (provider.id === primaryId && adminPageActive && accessRequest) { - return true; - } - - if (provider.configurable || provider.trusted || provider.private) { - return false; - } - - if (providerId !== null) { - return provider.id === providerId; - } - - const active = authProvidersResource.resource.isAuthEnabled(provider.id); - - if (active) { - return true; - } + const activeProviders = providers.filter(provider => { + if (provider.id === primaryId && adminPageActive && accessRequest) { + return true; + } + if (provider.configurable || provider.trusted || provider.private) { return false; - }); + } - const configurations = providers.filter(provider => ( - provider.configurable - && (provider.configurations?.length || 0) > 0 - && authProvidersResource.resource.isAuthEnabled(provider.id) - )); + if (providerId !== null) { + return provider.id === providerId; + } + + const active = authProvidersResource.resource.isAuthEnabled(provider.id); + + if (active) { + return true; + } + + return false; + }); + + const configurations = providers.filter( + provider => provider.configurable && (provider.configurations?.length || 0) > 0 && authProvidersResource.resource.isAuthEnabled(provider.id), + ); const tabIds = activeProviders.map(provider => provider.id); @@ -123,69 +118,72 @@ export function useAuthDialogState(accessRequest: boolean, providerId: string | tabIds.push(FEDERATED_AUTH); } - const data = useObservableRef(() => ({ - exception: null, - authenticating: false, - destroyed: false, + const data = useObservableRef( + () => ({ + exception: null, + authenticating: false, + destroyed: false, - get configure(): boolean { - if (state.activeProvider) { - if (this.adminPageActive && authProvidersResource.resource.isPrimary(state.activeProvider.id)) { - return false; + get configure(): boolean { + if (state.activeProvider) { + if (this.adminPageActive && authProvidersResource.resource.isPrimary(state.activeProvider.id)) { + return false; + } + return !authProvidersResource.resource.isAuthEnabled(state.activeProvider.id); } - return !authProvidersResource.resource.isAuthEnabled(state.activeProvider.id); - } - return false; - }, - async login(linkUser: boolean): Promise { - if (!state.activeProvider || this.authenticating) { - return; - } - - this.authenticating = true; - try { - await authInfoService.login(state.activeProvider.id, { - credentials: state.credentials, - linkUser, - }); - } catch (exception: any) { - if (this.destroyed) { - notificationService.logException(exception, 'Login failed'); - } else { - this.exception = exception; + return false; + }, + async login(linkUser: boolean): Promise { + if (!state.activeProvider || this.authenticating) { + return; } - throw exception; - } finally { - this.authenticating = false; - } - }, - }), { - state: observable.ref, - exception: observable.ref, - authenticating: observable.ref, - configure: computed, - adminPageActive: observable.ref, - }, { - state, - adminPageActive, - providers: activeProviders, - configurations, - }); - useEffect(() => () => { data.destroyed = true; }, []); + this.authenticating = true; + try { + await authInfoService.login(state.activeProvider.id, { + credentials: state.credentials, + linkUser, + }); + } catch (exception: any) { + if (this.destroyed) { + notificationService.logException(exception, 'Login failed'); + } else { + this.exception = exception; + } + throw exception; + } finally { + this.authenticating = false; + } + }, + }), + { + state: observable.ref, + exception: observable.ref, + authenticating: observable.ref, + configure: computed, + adminPageActive: observable.ref, + }, + { + state, + adminPageActive, + providers: activeProviders, + configurations, + }, + ); + + useEffect( + () => () => { + data.destroyed = true; + }, + [], + ); if (tabIds.length > 0 && (state.tabId === null || !tabIds.includes(state.tabId))) { const tabId = tabIds[0]; state.setTabId(tabId); - const provider = ( - activeProviders.find(provider => provider.id === tabId) - || providers.find(provider => provider.id === providerId) - || null - ); - const configuration = provider?.configurations?.find( - configuration => configuration.id === configurationId - ) ?? null; + const provider = activeProviders.find(provider => provider.id === tabId) || providers.find(provider => provider.id === providerId) || null; + const configuration = provider?.configurations?.find(configuration => configuration.id === configurationId) ?? null; state.setActiveConfiguration(provider, configuration); } diff --git a/webapp/packages/plugin-authentication/src/IAuthOptions.ts b/webapp/packages/plugin-authentication/src/IAuthOptions.ts index 65061ec2b4..1456c71860 100644 --- a/webapp/packages/plugin-authentication/src/IAuthOptions.ts +++ b/webapp/packages/plugin-authentication/src/IAuthOptions.ts @@ -11,4 +11,4 @@ export interface IAuthOptions { configurationId?: string; linkUser?: boolean; accessRequest?: boolean; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-authentication/src/IAutoLoginSessionAction.ts b/webapp/packages/plugin-authentication/src/IAutoLoginSessionAction.ts index 196d18a3b2..d2a3c87b30 100644 --- a/webapp/packages/plugin-authentication/src/IAutoLoginSessionAction.ts +++ b/webapp/packages/plugin-authentication/src/IAutoLoginSessionAction.ts @@ -9,4 +9,4 @@ export interface IAutoLoginSessionAction { action: 'auto-login'; 'auth-id': string; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-authentication/src/PluginBootstrap.ts b/webapp/packages/plugin-authentication/src/PluginBootstrap.ts index dcaee07dc5..814717d5fd 100644 --- a/webapp/packages/plugin-authentication/src/PluginBootstrap.ts +++ b/webapp/packages/plugin-authentication/src/PluginBootstrap.ts @@ -5,9 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { AuthInfoService } from '@cloudbeaver/core-authentication'; -import { injectable, Bootstrap } from '@cloudbeaver/core-di'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { ServerConfigResource } from '@cloudbeaver/core-root'; import { DATA_CONTEXT_MENU, MenuBaseItem, MenuService } from '@cloudbeaver/core-view'; import { TOP_NAV_BAR_SETTINGS_MENU } from '@cloudbeaver/plugin-settings-menu'; @@ -38,7 +37,7 @@ export class PluginBootstrap extends Bootstrap { label: 'authentication_login', tooltip: 'authentication_login', }, - { onSelect: () => this.authenticationService.authUser(null, false) } + { onSelect: () => this.authenticationService.authUser(null, false) }, ), ]; } @@ -52,7 +51,7 @@ export class PluginBootstrap extends Bootstrap { label: 'authentication_logout', tooltip: 'authentication_logout', }, - { onSelect: () => this.authenticationService.logout() } + { onSelect: () => this.authenticationService.logout() }, ), ]; } @@ -72,5 +71,5 @@ export class PluginBootstrap extends Bootstrap { }); } - load(): void | Promise { } + load(): void | Promise {} } diff --git a/webapp/packages/plugin-authentication/src/index.ts b/webapp/packages/plugin-authentication/src/index.ts index cd9fe02cc8..998e8e8c93 100644 --- a/webapp/packages/plugin-authentication/src/index.ts +++ b/webapp/packages/plugin-authentication/src/index.ts @@ -1,4 +1,5 @@ import { manifest } from './manifest'; + export * from './AuthenticationService'; export * from './Dialog/AuthDialogService'; export default manifest; diff --git a/webapp/packages/plugin-authentication/src/isAutoLoginSessionAction.ts b/webapp/packages/plugin-authentication/src/isAutoLoginSessionAction.ts index 17ba6ad15c..2cd07a11ca 100644 --- a/webapp/packages/plugin-authentication/src/isAutoLoginSessionAction.ts +++ b/webapp/packages/plugin-authentication/src/isAutoLoginSessionAction.ts @@ -5,9 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IAutoLoginSessionAction } from './IAutoLoginSessionAction'; export function isAutoLoginSessionAction(obj: any): obj is IAutoLoginSessionAction { return obj && 'action' in obj && obj.action === 'auto-login'; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-authentication/src/locales/en.ts b/webapp/packages/plugin-authentication/src/locales/en.ts index 0b7cc179f0..268017a9c5 100644 --- a/webapp/packages/plugin-authentication/src/locales/en.ts +++ b/webapp/packages/plugin-authentication/src/locales/en.ts @@ -22,7 +22,7 @@ export default [ ['authentication_user_team', 'User team'], ['authentication_user_status', 'User status'], ['authentication_user_enabled', 'Enabled'], - ['authentication_user_login_not_set', 'Login can\'t be empty'], + ['authentication_user_login_not_set', "Login can't be empty"], ['authentication_user_team_not_set', 'At least one team must be selected'], ['authentication_user_role_not_set', '{alias:authentication_user_role} is required'], ['authentication_user_password_not_set', '{alias:authentication_user_password} is required'], diff --git a/webapp/packages/plugin-authentication/src/manifest.ts b/webapp/packages/plugin-authentication/src/manifest.ts index ee8e3f3a5f..11ec90f8bf 100644 --- a/webapp/packages/plugin-authentication/src/manifest.ts +++ b/webapp/packages/plugin-authentication/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { AuthenticationLocaleService } from './AuthenticationLocaleService'; @@ -18,10 +17,5 @@ export const manifest: PluginManifest = { name: 'Plugin Authentication', }, - providers: [ - AuthenticationService, - AuthDialogService, - PluginBootstrap, - AuthenticationLocaleService, - ], + providers: [AuthenticationService, AuthDialogService, PluginBootstrap, AuthenticationLocaleService], }; diff --git a/webapp/packages/plugin-browser/src/LocaleService.ts b/webapp/packages/plugin-browser/src/LocaleService.ts index 3005f4bd55..e3649a06b4 100644 --- a/webapp/packages/plugin-browser/src/LocaleService.ts +++ b/webapp/packages/plugin-browser/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { @@ -33,4 +32,4 @@ export class LocaleService extends Bootstrap { return (await import('./locales/en')).default; } } -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-browser/src/PluginBrowserBootstrap.ts b/webapp/packages/plugin-browser/src/PluginBrowserBootstrap.ts index 0a2c9cc947..d424d15ba8 100644 --- a/webapp/packages/plugin-browser/src/PluginBrowserBootstrap.ts +++ b/webapp/packages/plugin-browser/src/PluginBrowserBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { ActionSnackbar } from '@cloudbeaver/core-blocks'; import { ServiceWorkerService } from '@cloudbeaver/core-browser'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; @@ -33,15 +32,18 @@ export class PluginBrowserBootstrap extends Bootstrap { return; } - this.notificationService.customNotification(() => ActionSnackbar, { - actionText: 'ui_processing_reload', - onAction: () => window.location.reload(), - }, { title: 'plugin_browser_update_dialog_title', persistent: true, type: ENotificationType.Info }); + this.notificationService.customNotification( + () => ActionSnackbar, + { + actionText: 'ui_processing_reload', + onAction: () => window.location.reload(), + }, + { title: 'plugin_browser_update_dialog_title', persistent: true, type: ENotificationType.Info }, + ); ExecutorInterrupter.interrupt(context); }); } - load(): void | Promise { - } -} \ No newline at end of file + load(): void | Promise {} +} diff --git a/webapp/packages/plugin-browser/src/index.ts b/webapp/packages/plugin-browser/src/index.ts index 510402b96b..eea6e3db82 100644 --- a/webapp/packages/plugin-browser/src/index.ts +++ b/webapp/packages/plugin-browser/src/index.ts @@ -1,3 +1,4 @@ import { browserPlugin } from './manifest'; + export default browserPlugin; export { browserPlugin }; diff --git a/webapp/packages/plugin-browser/src/locales/en.ts b/webapp/packages/plugin-browser/src/locales/en.ts index cffac5d368..ce245046d5 100644 --- a/webapp/packages/plugin-browser/src/locales/en.ts +++ b/webapp/packages/plugin-browser/src/locales/en.ts @@ -1,4 +1,4 @@ export default [ ['plugin_browser_update_dialog_title', 'Update available'], ['plugin_browser_update_dialog_message', 'New version of CloudBeaver is available. Do you want to update?'], -]; \ No newline at end of file +]; diff --git a/webapp/packages/plugin-browser/src/locales/it.ts b/webapp/packages/plugin-browser/src/locales/it.ts index 13ee1be3cd..d6d1738de6 100644 --- a/webapp/packages/plugin-browser/src/locales/it.ts +++ b/webapp/packages/plugin-browser/src/locales/it.ts @@ -1,3 +1 @@ -export default [ - -]; \ No newline at end of file +export default []; diff --git a/webapp/packages/plugin-browser/src/locales/ru.ts b/webapp/packages/plugin-browser/src/locales/ru.ts index 3f05dbc138..5f378f8b53 100644 --- a/webapp/packages/plugin-browser/src/locales/ru.ts +++ b/webapp/packages/plugin-browser/src/locales/ru.ts @@ -1,4 +1,4 @@ export default [ ['plugin_browser_update_dialog_title', 'Доступно обновление'], ['plugin_browser_update_dialog_message', 'Новая версия CloudBeaver доступна. Хотите обновить?'], -]; \ No newline at end of file +]; diff --git a/webapp/packages/plugin-browser/src/locales/zh.ts b/webapp/packages/plugin-browser/src/locales/zh.ts index 9f25cb126f..d6d1738de6 100644 --- a/webapp/packages/plugin-browser/src/locales/zh.ts +++ b/webapp/packages/plugin-browser/src/locales/zh.ts @@ -1,2 +1 @@ -export default [ -]; +export default []; diff --git a/webapp/packages/plugin-browser/src/manifest.ts b/webapp/packages/plugin-browser/src/manifest.ts index 0bbcf35d41..ea2fa587c0 100644 --- a/webapp/packages/plugin-browser/src/manifest.ts +++ b/webapp/packages/plugin-browser/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { LocaleService } from './LocaleService'; @@ -13,8 +12,5 @@ import { PluginBrowserBootstrap } from './PluginBrowserBootstrap'; export const browserPlugin: PluginManifest = { info: { name: 'Browser plugin' }, - providers: [ - PluginBrowserBootstrap, - LocaleService, - ], -}; \ No newline at end of file + providers: [PluginBrowserBootstrap, LocaleService], +}; diff --git a/webapp/packages/plugin-codemirror6/src/Editor.tsx b/webapp/packages/plugin-codemirror6/src/Editor.tsx index 9ab7da1a2f..d31c223b7a 100644 --- a/webapp/packages/plugin-codemirror6/src/Editor.tsx +++ b/webapp/packages/plugin-codemirror6/src/Editor.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { forwardRef } from 'react'; import styled from 'reshadow'; @@ -19,18 +18,16 @@ import { ReactCodemirror } from './ReactCodemirror'; import { EDITOR_BASE_STYLES } from './theme'; import { useEditorDefaultExtensions } from './useDefaultExtensions'; -export const Editor = observer(forwardRef(function Editor({ - lineNumbers, - extensions = [], - ...rest -}, ref) { - const defaultExtensions = useEditorDefaultExtensions({ lineNumbers }); - const combinedExtensions = [...defaultExtensions]; - combinedExtensions.push(...extensions); +export const Editor = observer( + forwardRef(function Editor({ lineNumbers, extensions = [], ...rest }, ref) { + const defaultExtensions = useEditorDefaultExtensions({ lineNumbers }); + const combinedExtensions = [...defaultExtensions]; + combinedExtensions.push(...extensions); - return styled(EDITOR_BASE_STYLES)( - - - - ); -})); \ No newline at end of file + return styled(EDITOR_BASE_STYLES)( + + + , + ); + }), +); diff --git a/webapp/packages/plugin-codemirror6/src/EditorLoader.tsx b/webapp/packages/plugin-codemirror6/src/EditorLoader.tsx index 487709b884..f00a0e6ea7 100644 --- a/webapp/packages/plugin-codemirror6/src/EditorLoader.tsx +++ b/webapp/packages/plugin-codemirror6/src/EditorLoader.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { forwardRef } from 'react'; import { ComplexLoader, createComplexLoader } from '@cloudbeaver/core-blocks'; @@ -20,9 +19,5 @@ const loader = createComplexLoader(async function loader() { }); export const EditorLoader = forwardRef(function EditorLoader(props, ref) { - return ( - - {({ Editor }) => } - - ); + return {({ Editor }) => }; }); diff --git a/webapp/packages/plugin-codemirror6/src/IEditorProps.ts b/webapp/packages/plugin-codemirror6/src/IEditorProps.ts index 3ac8d91844..03b38d14b9 100644 --- a/webapp/packages/plugin-codemirror6/src/IEditorProps.ts +++ b/webapp/packages/plugin-codemirror6/src/IEditorProps.ts @@ -5,9 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IReactCodeMirrorProps } from './IReactCodemirrorProps'; export interface IEditorProps extends IReactCodeMirrorProps { className?: string; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-codemirror6/src/IEditorRef.ts b/webapp/packages/plugin-codemirror6/src/IEditorRef.ts index a22ba1b5cc..d079d6fe67 100644 --- a/webapp/packages/plugin-codemirror6/src/IEditorRef.ts +++ b/webapp/packages/plugin-codemirror6/src/IEditorRef.ts @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { EditorView } from '@codemirror/view'; export interface IEditorRef { container: HTMLDivElement | null; view: EditorView | null; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-codemirror6/src/IReactCodemirrorProps.ts b/webapp/packages/plugin-codemirror6/src/IReactCodemirrorProps.ts index 6c32b5f0f0..f858d07cd2 100644 --- a/webapp/packages/plugin-codemirror6/src/IReactCodemirrorProps.ts +++ b/webapp/packages/plugin-codemirror6/src/IReactCodemirrorProps.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { Extension } from '@codemirror/state'; import type { ViewUpdate } from '@codemirror/view'; @@ -18,4 +17,4 @@ export interface IReactCodeMirrorProps { autoFocus?: boolean; onChange?: (value: string, update: ViewUpdate) => void; onUpdate?: (update: ViewUpdate) => void; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-codemirror6/src/ReactCodemirror.tsx b/webapp/packages/plugin-codemirror6/src/ReactCodemirror.tsx index ea814fb33a..11d41ade87 100644 --- a/webapp/packages/plugin-codemirror6/src/ReactCodemirror.tsx +++ b/webapp/packages/plugin-codemirror6/src/ReactCodemirror.tsx @@ -5,13 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - +import { Annotation, EditorState, StateEffect } from '@codemirror/state'; +import { EditorView, ViewUpdate } from '@codemirror/view'; import { observer } from 'mobx-react-lite'; import { forwardRef, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { useObjectRef } from '@cloudbeaver/core-blocks'; -import { Annotation, EditorState, StateEffect } from '@codemirror/state'; -import { ViewUpdate, EditorView } from '@codemirror/view'; import type { IEditorRef } from './IEditorRef'; import type { IReactCodeMirrorProps } from './IReactCodemirrorProps'; @@ -25,99 +24,99 @@ const defaultTheme = EditorView.theme({ }, }); -export const ReactCodemirror = observer(forwardRef(function ReactCodemirror({ - getValue, - value, - extensions, - readonly, - autoFocus, - onChange, - onUpdate, -}, ref) { - value = value ?? getValue?.(); - const [container, setContainer] = useState(null); - const [view, setView] = useState(null); - const lastValueUpdate = useRef(undefined); +export const ReactCodemirror = observer( + forwardRef(function ReactCodemirror({ getValue, value, extensions, readonly, autoFocus, onChange, onUpdate }, ref) { + value = value ?? getValue?.(); + const [container, setContainer] = useState(null); + const [view, setView] = useState(null); + const lastValueUpdate = useRef(undefined); - const ext = [defaultTheme]; - const callbackRef = useObjectRef({ onChange, onUpdate }); + const ext = [defaultTheme]; + const callbackRef = useObjectRef({ onChange, onUpdate }); - if (readonly) { - // can lead to missing state updates - ext.push(EditorState.readOnly.of(true)); - // ext.push(EditorView.editable.of(false)); - } - - if (extensions) { - ext.push(extensions); - } - - const updateListener = useMemo(() => EditorView.updateListener.of((update: ViewUpdate) => { - const remote = update.transactions.some(tr => tr.annotation(External)); - - if (update.docChanged && !remote) { - const doc = update.state.doc; - const value = doc.toString(); - - lastValueUpdate.current = value; - callbackRef.onChange?.(value, update); + if (readonly) { + // can lead to missing state updates + ext.push(EditorState.readOnly.of(true)); + // ext.push(EditorView.editable.of(false)); } - callbackRef.onUpdate?.(update); - }), []); - - ext.push(updateListener); - - useLayoutEffect(() => { - if (container) { - const ev = new EditorView({ - parent: container, - }); - - setView(ev); - - ev.dom.addEventListener('keydown', event => { - const newEvent = new KeyboardEvent('keydown', event); - document.dispatchEvent(newEvent); - }); - - return () => { - ev.destroy(); - setView(null); - }; + if (extensions) { + ext.push(extensions); } - return () => { }; - }, [container]); + const updateListener = useMemo( + () => + EditorView.updateListener.of((update: ViewUpdate) => { + const remote = update.transactions.some(tr => tr.annotation(External)); - useLayoutEffect(() => { - if (view && value !== lastValueUpdate.current) { - lastValueUpdate.current = value; - view.dispatch({ - changes: { from: 0, to: view.state.doc.length, insert: value }, - annotations: [External.of(true)], - }); - } - }, [value, view]); + if (update.docChanged && !remote) { + const doc = update.state.doc; + const value = doc.toString(); - useLayoutEffect(() => { - if (view) { - view.dispatch({ effects: StateEffect.reconfigure.of(ext) }); - } - }); + lastValueUpdate.current = value; + callbackRef.onChange?.(value, update); + } - useLayoutEffect(() => { - if (!readonly && autoFocus && view) { - view.focus(); - } - }, [autoFocus, view, readonly]); + callbackRef.onUpdate?.(update); + }), + [], + ); - useImperativeHandle(ref, () => ({ - container, - view, - }), [container, view]); + ext.push(updateListener); - return ( -
- ); -})); \ No newline at end of file + useLayoutEffect(() => { + if (container) { + const ev = new EditorView({ + parent: container, + }); + + setView(ev); + + ev.dom.addEventListener('keydown', event => { + const newEvent = new KeyboardEvent('keydown', event); + document.dispatchEvent(newEvent); + }); + + return () => { + ev.destroy(); + setView(null); + }; + } + + return () => {}; + }, [container]); + + useLayoutEffect(() => { + if (view && value !== lastValueUpdate.current) { + lastValueUpdate.current = value; + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: value }, + annotations: [External.of(true)], + }); + } + }, [value, view]); + + useLayoutEffect(() => { + if (view) { + view.dispatch({ effects: StateEffect.reconfigure.of(ext) }); + } + }); + + useLayoutEffect(() => { + if (!readonly && autoFocus && view) { + view.focus(); + } + }, [autoFocus, view, readonly]); + + useImperativeHandle( + ref, + () => ({ + container, + view, + }), + [container, view], + ); + + return
; + }), +); diff --git a/webapp/packages/plugin-codemirror6/src/getDefaultExtensions.ts b/webapp/packages/plugin-codemirror6/src/getDefaultExtensions.ts index c00d77f244..72fc911e3d 100644 --- a/webapp/packages/plugin-codemirror6/src/getDefaultExtensions.ts +++ b/webapp/packages/plugin-codemirror6/src/getDefaultExtensions.ts @@ -5,21 +5,27 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { GlobalConstants, clsx } from '@cloudbeaver/core-utils'; import { defaultKeymap, indentWithTab } from '@codemirror/commands'; -import { foldGutter, indentOnInput, syntaxHighlighting, bracketMatching } from '@codemirror/language'; +import { bracketMatching, foldGutter, indentOnInput, syntaxHighlighting } from '@codemirror/language'; import { highlightSelectionMatches } from '@codemirror/search'; import type { Extension } from '@codemirror/state'; -import { tooltips, lineNumbers, highlightSpecialChars, dropCursor, rectangularSelection, crosshairCursor, keymap, highlightActiveLineGutter, highlightActiveLine } from '@codemirror/view'; +import { + crosshairCursor, + dropCursor, + highlightActiveLine, + highlightActiveLineGutter, + highlightSpecialChars, + keymap, + lineNumbers, + rectangularSelection, + tooltips, +} from '@codemirror/view'; import { classHighlighter } from '@lezer/highlight'; +import { clsx, GlobalConstants } from '@cloudbeaver/core-utils'; + // @TODO allow to configure bindings outside of the component -const DEFAULT_KEY_MAP = defaultKeymap - .filter(binding => ( - binding.mac !== 'Ctrl-f' - && binding.key !== 'Mod-Enter' - )); +const DEFAULT_KEY_MAP = defaultKeymap.filter(binding => binding.mac !== 'Ctrl-f' && binding.key !== 'Mod-Enter'); DEFAULT_KEY_MAP.push(indentWithTab); @@ -72,4 +78,4 @@ export function getDefaultExtensions(options?: IDefaultExtensions): Record { diff --git a/webapp/packages/plugin-codemirror6/src/useDefaultExtensions.ts b/webapp/packages/plugin-codemirror6/src/useDefaultExtensions.ts index 7892fef28a..c1c554827e 100644 --- a/webapp/packages/plugin-codemirror6/src/useDefaultExtensions.ts +++ b/webapp/packages/plugin-codemirror6/src/useDefaultExtensions.ts @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - +import type { Extension } from '@codemirror/state'; import { useState } from 'react'; import { createComplexLoader, useComplexLoader } from '@cloudbeaver/core-blocks'; -import type { Extension } from '@codemirror/state'; import type { IDefaultExtensions } from './getDefaultExtensions'; @@ -50,4 +49,4 @@ export function useEditorDefaultExtensions(options?: IDefaultExtensions) { } return Object.values(extensions); -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-codemirror6/src/useEditorAutocompletion.ts b/webapp/packages/plugin-codemirror6/src/useEditorAutocompletion.ts index f2fc318830..bfabe842b0 100644 --- a/webapp/packages/plugin-codemirror6/src/useEditorAutocompletion.ts +++ b/webapp/packages/plugin-codemirror6/src/useEditorAutocompletion.ts @@ -5,12 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { useMemo, useState } from 'react'; - import { autocompletion, startCompletion } from '@codemirror/autocomplete'; import type { Extension } from '@codemirror/state'; import { keymap } from '@codemirror/view'; +import { useMemo, useState } from 'react'; export type CompletionConfig = Parameters[0]; @@ -19,16 +17,17 @@ export function useEditorAutocompletion(config?: CompletionConfig): Extension[] keymap.of([ { key: 'Alt-Space', run: startCompletion, preventDefault: true }, { key: 'Shift-Ctrl-Space', run: startCompletion, preventDefault: true }, - ]) + ]), ); - const autocompletionExtension = useMemo(() => autocompletion({ - ...config, - closeOnBlur: false, - }), [config]); + const autocompletionExtension = useMemo( + () => + autocompletion({ + ...config, + closeOnBlur: false, + }), + [config], + ); - return [ - autocompletionExtension, - autocompleteKeyMap, - ]; + return [autocompletionExtension, autocompleteKeyMap]; } diff --git a/webapp/packages/plugin-connection-custom/src/Actions/ACTION_CONNECTION_CUSTOM.ts b/webapp/packages/plugin-connection-custom/src/Actions/ACTION_CONNECTION_CUSTOM.ts index 13e52fd6a4..88faafa3ce 100644 --- a/webapp/packages/plugin-connection-custom/src/Actions/ACTION_CONNECTION_CUSTOM.ts +++ b/webapp/packages/plugin-connection-custom/src/Actions/ACTION_CONNECTION_CUSTOM.ts @@ -5,12 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; -export const ACTION_CONNECTION_CUSTOM = createAction( - 'connection-custom', - { - label: 'plugin_connection_custom_action_custom_label', - } -); +export const ACTION_CONNECTION_CUSTOM = createAction('connection-custom', { + label: 'plugin_connection_custom_action_custom_label', +}); diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnection/CustomConnectionController.ts b/webapp/packages/plugin-connection-custom/src/CustomConnection/CustomConnectionController.ts index 39236c0ac9..540238dd1d 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnection/CustomConnectionController.ts +++ b/webapp/packages/plugin-connection-custom/src/CustomConnection/CustomConnectionController.ts @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { observable, computed, makeObservable } from 'mobx'; +import { computed, makeObservable, observable } from 'mobx'; import { ConnectionsManagerService, DBDriver, DBDriverResource } from '@cloudbeaver/core-connections'; -import { injectable, IInitializableController } from '@cloudbeaver/core-di'; +import { IInitializableController, injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; import { ProjectsService } from '@cloudbeaver/core-projects'; import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; @@ -30,7 +29,7 @@ export class CustomConnectionController implements IInitializableController { private readonly notificationService: NotificationService, private readonly projectsService: ProjectsService, private readonly publicConnectionFormService: PublicConnectionFormService, - private readonly connectionsManagerService: ConnectionsManagerService + private readonly connectionsManagerService: ConnectionsManagerService, ) { this.isLoading = true; @@ -60,7 +59,7 @@ export class CustomConnectionController implements IInitializableController { const state = await this.publicConnectionFormService.open( projects[0].id, { driverId }, - this.drivers.map(driver => driver.id) + this.drivers.map(driver => driver.id), ); if (state) { @@ -72,7 +71,7 @@ export class CustomConnectionController implements IInitializableController { try { await this.dbDriverResource.load(CachedMapAllKey); } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t load database drivers'); + this.notificationService.logException(exception, "Can't load database drivers"); } finally { this.isLoading = false; } diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnection/CustomConnectionDialog.tsx b/webapp/packages/plugin-connection-custom/src/CustomConnection/CustomConnectionDialog.tsx index 5db2244a16..7322363994 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnection/CustomConnectionDialog.tsx +++ b/webapp/packages/plugin-connection-custom/src/CustomConnection/CustomConnectionDialog.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useTranslate } from '@cloudbeaver/core-blocks'; @@ -15,9 +14,7 @@ import type { DialogComponent } from '@cloudbeaver/core-dialogs'; import { CustomConnectionController } from './CustomConnectionController'; import { DriverSelectorDialog } from './DriverSelectorDialog/DriverSelectorDialog'; -export const CustomConnectionDialog: DialogComponent = observer(function CustomConnectionDialog({ - rejectDialog, -}) { +export const CustomConnectionDialog: DialogComponent = observer(function CustomConnectionDialog({ rejectDialog }) { const controller = useController(CustomConnectionController, rejectDialog); const translate = useTranslate(); diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnection/DriverSelectorDialog/Driver.tsx b/webapp/packages/plugin-connection-custom/src/CustomConnection/DriverSelectorDialog/Driver.tsx index b342ce5cb9..86ad83bf03 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnection/DriverSelectorDialog/Driver.tsx +++ b/webapp/packages/plugin-connection-custom/src/CustomConnection/DriverSelectorDialog/Driver.tsx @@ -5,14 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback } from 'react'; import styled, { css } from 'reshadow'; -import { - ListItem, ListItemIcon, ListItemName, ListItemDescription, StaticImage -} from '@cloudbeaver/core-blocks'; +import { ListItem, ListItemDescription, ListItemIcon, ListItemName, StaticImage } from '@cloudbeaver/core-blocks'; export interface IDriver { id: string; @@ -39,9 +36,11 @@ export const Driver = observer(function Driver({ driver, onSelect }) { return styled(styles)( - + + + {driver.name} {driver.description} - + , ); }); diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnection/DriverSelectorDialog/DriverSelector.tsx b/webapp/packages/plugin-connection-custom/src/CustomConnection/DriverSelectorDialog/DriverSelector.tsx index 07a9609ac7..28d2aaf44b 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnection/DriverSelectorDialog/DriverSelector.tsx +++ b/webapp/packages/plugin-connection-custom/src/CustomConnection/DriverSelectorDialog/DriverSelector.tsx @@ -5,12 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { useState, useMemo } from 'react'; +import { useMemo, useState } from 'react'; import styled, { css } from 'reshadow'; -import { ItemListSearch, ItemList, useFocus, useTranslate } from '@cloudbeaver/core-blocks'; +import { ItemList, ItemListSearch, useFocus, useTranslate } from '@cloudbeaver/core-blocks'; import { Driver, IDriver } from './Driver'; @@ -43,8 +42,10 @@ export const DriverSelector = observer(function DriverSelector({ drivers,
- {filteredDrivers.map(driver => )} + {filteredDrivers.map(driver => ( + + ))} -
+
, ); }); diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnection/DriverSelectorDialog/DriverSelectorDialog.tsx b/webapp/packages/plugin-connection-custom/src/CustomConnection/DriverSelectorDialog/DriverSelectorDialog.tsx index 90faff6523..b004afc35e 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnection/DriverSelectorDialog/DriverSelectorDialog.tsx +++ b/webapp/packages/plugin-connection-custom/src/CustomConnection/DriverSelectorDialog/DriverSelectorDialog.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -29,21 +28,14 @@ interface IProps { onClose: () => void; } -export const DriverSelectorDialog = observer(function DriverSelectorDialog({ - title, - drivers, - isLoading, - onSelect, - onClose, -}) { +export const DriverSelectorDialog = observer(function DriverSelectorDialog({ title, drivers, isLoading, onSelect, onClose }) { return styled(styles)( - + {isLoading && } {!isLoading && } - + , ); -} -); +}); diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnectionPluginBootstrap.ts b/webapp/packages/plugin-connection-custom/src/CustomConnectionPluginBootstrap.ts index 0dce7d4605..d408572fe3 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnectionPluginBootstrap.ts +++ b/webapp/packages/plugin-connection-custom/src/CustomConnectionPluginBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { ConnectionsManagerService } from '@cloudbeaver/core-connections'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; @@ -34,17 +33,12 @@ export class CustomConnectionPluginBootstrap extends Bootstrap { register(): void | Promise { this.menuService.addCreator({ menus: [MENU_CONNECTIONS], - getItems: (context, items) => [ - ...items, - ACTION_CONNECTION_CUSTOM, - ], + getItems: (context, items) => [...items, ACTION_CONNECTION_CUSTOM], }); this.actionService.addHandler({ id: 'connection-custom', - isActionApplicable: (context, action) => [ - ACTION_CONNECTION_CUSTOM, - ].includes(action), + isActionApplicable: (context, action) => [ACTION_CONNECTION_CUSTOM].includes(action), isHidden: (context, action) => { if (this.connectionsManagerService.createConnectionProjects.length === 0) { return true; @@ -59,10 +53,7 @@ export class CustomConnectionPluginBootstrap extends Bootstrap { getLoader: (context, action) => { const state = context.get(DATA_CONTEXT_LOADABLE_STATE); - return state.getState( - action.id, - () => getCachedMapResourceLoaderState(this.projectInfoResource, CachedMapAllKey) - ); + return state.getState(action.id, () => getCachedMapResourceLoaderState(this.projectInfoResource, CachedMapAllKey)); }, handler: async (context, action) => { switch (action) { @@ -75,7 +66,7 @@ export class CustomConnectionPluginBootstrap extends Bootstrap { }); } - load(): void | Promise { } + load(): void | Promise {} private async openConnectionsDialog() { await this.commonDialogService.open(CustomConnectionDialog, null); diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnectionSettingsService.ts b/webapp/packages/plugin-connection-custom/src/CustomConnectionSettingsService.ts index cb78d379c2..146767a629 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnectionSettingsService.ts +++ b/webapp/packages/plugin-connection-custom/src/CustomConnectionSettingsService.ts @@ -5,7 +5,6 @@ * 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 { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin'; diff --git a/webapp/packages/plugin-connection-custom/src/LocaleService.ts b/webapp/packages/plugin-connection-custom/src/LocaleService.ts index 144237a086..e3649a06b4 100644 --- a/webapp/packages/plugin-connection-custom/src/LocaleService.ts +++ b/webapp/packages/plugin-connection-custom/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-connection-custom/src/manifest.ts b/webapp/packages/plugin-connection-custom/src/manifest.ts index 7d8cbee961..0364a343d6 100644 --- a/webapp/packages/plugin-connection-custom/src/manifest.ts +++ b/webapp/packages/plugin-connection-custom/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { CustomConnectionPluginBootstrap } from './CustomConnectionPluginBootstrap'; @@ -17,9 +16,5 @@ export const customConnectionPluginManifest: PluginManifest = { name: 'Custom connection plugin', }, - providers: [ - LocaleService, - CustomConnectionPluginBootstrap, - CustomConnectionSettingsService, - ], + providers: [LocaleService, CustomConnectionPluginBootstrap, CustomConnectionSettingsService], }; diff --git a/webapp/packages/plugin-connection-search/src/Actions/ACTION_CONNECTION_SEARCH.ts b/webapp/packages/plugin-connection-search/src/Actions/ACTION_CONNECTION_SEARCH.ts index f794e07bdf..78187f10ee 100644 --- a/webapp/packages/plugin-connection-search/src/Actions/ACTION_CONNECTION_SEARCH.ts +++ b/webapp/packages/plugin-connection-search/src/Actions/ACTION_CONNECTION_SEARCH.ts @@ -5,12 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; -export const ACTION_CONNECTION_SEARCH = createAction( - 'connection-search', - { - label: 'plugin_connection_search_action_search_label', - } -); +export const ACTION_CONNECTION_SEARCH = createAction('connection-search', { + label: 'plugin_connection_search_action_search_label', +}); diff --git a/webapp/packages/plugin-connection-search/src/ConnectionSearchSettingsService.ts b/webapp/packages/plugin-connection-search/src/ConnectionSearchSettingsService.ts index 0a88002f58..a2738c6a8c 100644 --- a/webapp/packages/plugin-connection-search/src/ConnectionSearchSettingsService.ts +++ b/webapp/packages/plugin-connection-search/src/ConnectionSearchSettingsService.ts @@ -5,7 +5,6 @@ * 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 { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin'; diff --git a/webapp/packages/plugin-connection-search/src/LocaleService.ts b/webapp/packages/plugin-connection-search/src/LocaleService.ts index 144237a086..e3649a06b4 100644 --- a/webapp/packages/plugin-connection-search/src/LocaleService.ts +++ b/webapp/packages/plugin-connection-search/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts b/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts index 1180241dde..a4025a5864 100644 --- a/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts +++ b/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts @@ -5,8 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { observable, makeObservable } from 'mobx'; +import { makeObservable, observable } from 'mobx'; import { ConnectionInfoResource, ConnectionsManagerService, createConnectionParam } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; @@ -106,16 +105,11 @@ export class ConnectionSearchService { private async showUnsavedChangesDialog(): Promise { if ( - !this.formState - || !this.optionsPanelService.isOpen(formGetter) - || ( - this.formState.config.connectionId - && this.formState.projectId !== null - && !this.connectionInfoResource.has(createConnectionParam( - this.formState.projectId, - this.formState.config.connectionId - )) - ) + !this.formState || + !this.optionsPanelService.isOpen(formGetter) || + (this.formState.config.connectionId && + this.formState.projectId !== null && + !this.connectionInfoResource.has(createConnectionParam(this.formState.projectId, this.formState.config.connectionId))) ) { return true; } @@ -160,26 +154,20 @@ export class ConnectionSearchService { this.projectsService, this.projectInfoResource, this.connectionFormService, - this.connectionInfoResource + this.connectionInfoResource, ); this.formState.closeTask.addHandler(this.goBack.bind(this)); } this.formState - .setOptions( - 'create', - 'public' - ) - .setConfig( - projects[0].id, - { - ...this.connectionInfoResource.getEmptyConfig(), - driverId: database.defaultDriver, - host: database.host, - port: `${database.port}`, - } - ) + .setOptions('create', 'public') + .setConfig(projects[0].id, { + ...this.connectionInfoResource.getEmptyConfig(), + driverId: database.defaultDriver, + host: database.host, + port: `${database.port}`, + }) .setAvailableDrivers(database.possibleDrivers); this.formState.load(); diff --git a/webapp/packages/plugin-connection-search/src/Search/Database.tsx b/webapp/packages/plugin-connection-search/src/Search/Database.tsx index 2e2fd028ad..e045f2b47d 100644 --- a/webapp/packages/plugin-connection-search/src/Search/Database.tsx +++ b/webapp/packages/plugin-connection-search/src/Search/Database.tsx @@ -5,41 +5,37 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback, useMemo } from 'react'; import styled, { css } from 'reshadow'; -import { - ListItem, ListItemIcon, StaticImage, ListItemName -} from '@cloudbeaver/core-blocks'; +import { ListItem, ListItemIcon, ListItemName, StaticImage } from '@cloudbeaver/core-blocks'; import { DBDriverResource } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import type { AdminConnectionSearchInfo } from '@cloudbeaver/core-sdk'; - const styles = css` - ListItemIcon { - position: relative; - min-width: 80px; - justify-content: flex-end; - } + ListItemIcon { + position: relative; + min-width: 80px; + justify-content: flex-end; + } - StaticImage { - composes: theme-background-surface theme-border-color-surface from global; - box-sizing: border-box; - width: 32px; - border-radius: 50%; - border: solid 2px; + StaticImage { + composes: theme-background-surface theme-border-color-surface from global; + box-sizing: border-box; + width: 32px; + border-radius: 50%; + border: solid 2px; - &:hover { - z-index: 1; - } - &:not(:first-child) { - margin-left: -20px; - } + &:hover { + z-index: 1; } - `; + &:not(:first-child) { + margin-left: -20px; + } + } +`; interface Props { database: AdminConnectionSearchInfo; @@ -49,10 +45,9 @@ interface Props { export const Database = observer(function Database({ database, onSelect }) { const drivers = useService(DBDriverResource); const select = useCallback(() => onSelect(database), [database]); - const orderedDrivers = useMemo(() => ( - database.possibleDrivers - .slice() - .sort((a, b) => { + const orderedDrivers = useMemo( + () => + database.possibleDrivers.slice().sort((a, b) => { if (a === database.defaultDriver) { return 1; } @@ -60,8 +55,9 @@ export const Database = observer(function Database({ database, onSelect } return -1; } return a.localeCompare(b); - }) - ), [database]); + }), + [database], + ); const host = database.host + ':' + database.port; const name = database.displayName !== database.host ? database.displayName + ' (' + host + ')' : host; @@ -69,9 +65,11 @@ export const Database = observer(function Database({ database, onSelect } return styled(styles)( - {orderedDrivers.map(driverId => )} + {orderedDrivers.map(driverId => ( + + ))} {name} - + , ); }); diff --git a/webapp/packages/plugin-connection-search/src/Search/DatabaseList.tsx b/webapp/packages/plugin-connection-search/src/Search/DatabaseList.tsx index 27297aa24a..5d75cb2d58 100644 --- a/webapp/packages/plugin-connection-search/src/Search/DatabaseList.tsx +++ b/webapp/packages/plugin-connection-search/src/Search/DatabaseList.tsx @@ -5,28 +5,24 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback, useState } from 'react'; import styled, { css } from 'reshadow'; -import { - ItemListSearch, ItemList, SubmittingForm, TextPlaceholder, useFocus, useTranslate -} from '@cloudbeaver/core-blocks'; +import { ItemList, ItemListSearch, SubmittingForm, TextPlaceholder, useFocus, useTranslate } from '@cloudbeaver/core-blocks'; import type { AdminConnectionSearchInfo } from '@cloudbeaver/core-sdk'; - import { Database } from './Database'; const styles = css` - SubmittingForm { - composes: theme-background-surface theme-text-on-surface from global; - flex: 1; - display: flex; - flex-direction: column; - overflow: auto; - } - `; + SubmittingForm { + composes: theme-background-surface theme-text-on-surface from global; + flex: 1; + display: flex; + flex-direction: column; + overflow: auto; + } +`; interface Props { databases: AdminConnectionSearchInfo[]; @@ -38,9 +34,7 @@ interface Props { onSearch?: () => Promise; } -export const DatabaseList = observer(function DatabaseList({ - databases, hosts, disabled, className, onSelect, onChange, onSearch, -}) { +export const DatabaseList = observer(function DatabaseList({ databases, hosts, disabled, className, onSelect, onChange, onSearch }) { const [focusedRef] = useFocus({ focusFirstChild: true }); const translate = useTranslate(); const [isSearched, setIsSearched] = useState(false); @@ -57,13 +51,19 @@ export const DatabaseList = observer(function DatabaseList({ return styled(styles)( - + {databases.map(database => ( ))} {!databases.length && {translate(placeholderMessage)}} - + , ); }); diff --git a/webapp/packages/plugin-connection-search/src/Search/SearchDatabase.tsx b/webapp/packages/plugin-connection-search/src/Search/SearchDatabase.tsx index 9df24061c7..8f0f8c9131 100644 --- a/webapp/packages/plugin-connection-search/src/Search/SearchDatabase.tsx +++ b/webapp/packages/plugin-connection-search/src/Search/SearchDatabase.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -43,7 +42,7 @@ export const SearchDatabase: React.FC = observer(function SearchDatabase() { onSave={() => connectionSearchService.saveConnection()} onCancel={() => connectionSearchService.goBack()} /> - + , ); } diff --git a/webapp/packages/plugin-connection-search/src/SearchConnectionPluginBootstrap.ts b/webapp/packages/plugin-connection-search/src/SearchConnectionPluginBootstrap.ts index b9c74b7d8a..bf176be5b5 100644 --- a/webapp/packages/plugin-connection-search/src/SearchConnectionPluginBootstrap.ts +++ b/webapp/packages/plugin-connection-search/src/SearchConnectionPluginBootstrap.ts @@ -5,14 +5,13 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { EAdminPermission } from '@cloudbeaver/core-authentication'; import { ConnectionsManagerService } from '@cloudbeaver/core-connections'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { ProjectInfoResource } from '@cloudbeaver/core-projects'; import { PermissionsService } from '@cloudbeaver/core-root'; -import { getCachedMapResourceLoaderState, CachedMapAllKey } from '@cloudbeaver/core-sdk'; -import { MenuService, ActionService, DATA_CONTEXT_MENU, DATA_CONTEXT_LOADABLE_STATE } from '@cloudbeaver/core-view'; +import { CachedMapAllKey, getCachedMapResourceLoaderState } from '@cloudbeaver/core-sdk'; +import { ActionService, DATA_CONTEXT_LOADABLE_STATE, DATA_CONTEXT_MENU, MenuService } from '@cloudbeaver/core-view'; import { MENU_CONNECTIONS } from '@cloudbeaver/plugin-connections'; import { ACTION_CONNECTION_SEARCH } from './Actions/ACTION_CONNECTION_SEARCH'; @@ -36,20 +35,14 @@ export class SearchConnectionPluginBootstrap extends Bootstrap { register(): void | Promise { this.menuService.addCreator({ isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === MENU_CONNECTIONS, - getItems: (context, items) => [ - ...items, - ACTION_CONNECTION_SEARCH, - ], + getItems: (context, items) => [...items, ACTION_CONNECTION_SEARCH], }); this.actionService.addHandler({ id: 'connection-search', - isActionApplicable: (context, action) => [ - ACTION_CONNECTION_SEARCH, - ].includes(action), + isActionApplicable: (context, action) => [ACTION_CONNECTION_SEARCH].includes(action), isHidden: (context, action) => { - if (this.connectionsManagerService.createConnectionProjects.length === 0 - || !this.permissionsService.has(EAdminPermission.admin)) { + if (this.connectionsManagerService.createConnectionProjects.length === 0 || !this.permissionsService.has(EAdminPermission.admin)) { return true; } @@ -62,10 +55,7 @@ export class SearchConnectionPluginBootstrap extends Bootstrap { getLoader: (context, action) => { const state = context.get(DATA_CONTEXT_LOADABLE_STATE); - return state.getState( - action.id, - () => getCachedMapResourceLoaderState(this.projectInfoResource, CachedMapAllKey) - ); + return state.getState(action.id, () => getCachedMapResourceLoaderState(this.projectInfoResource, CachedMapAllKey)); }, handler: async (context, action) => { switch (action) { @@ -78,5 +68,5 @@ export class SearchConnectionPluginBootstrap extends Bootstrap { }); } - load(): void | Promise { } + load(): void | Promise {} } diff --git a/webapp/packages/plugin-connection-search/src/index.ts b/webapp/packages/plugin-connection-search/src/index.ts index 5e6de37178..22f185f033 100644 --- a/webapp/packages/plugin-connection-search/src/index.ts +++ b/webapp/packages/plugin-connection-search/src/index.ts @@ -2,4 +2,4 @@ import { connectionSearchPlugin } from './manifest'; export default connectionSearchPlugin; -export * from './ConnectionSearchSettingsService'; \ No newline at end of file +export * from './ConnectionSearchSettingsService'; diff --git a/webapp/packages/plugin-connection-search/src/locales/en.ts b/webapp/packages/plugin-connection-search/src/locales/en.ts index 1e83566e27..db83b12b1c 100644 --- a/webapp/packages/plugin-connection-search/src/locales/en.ts +++ b/webapp/packages/plugin-connection-search/src/locales/en.ts @@ -1,3 +1 @@ -export default [ - ['plugin_connection_search_action_search_label', 'Search'], -]; +export default [['plugin_connection_search_action_search_label', 'Search']]; diff --git a/webapp/packages/plugin-connection-search/src/locales/it.ts b/webapp/packages/plugin-connection-search/src/locales/it.ts index 1e83566e27..db83b12b1c 100644 --- a/webapp/packages/plugin-connection-search/src/locales/it.ts +++ b/webapp/packages/plugin-connection-search/src/locales/it.ts @@ -1,3 +1 @@ -export default [ - ['plugin_connection_search_action_search_label', 'Search'], -]; +export default [['plugin_connection_search_action_search_label', 'Search']]; diff --git a/webapp/packages/plugin-connection-search/src/locales/ru.ts b/webapp/packages/plugin-connection-search/src/locales/ru.ts index 1cb0672ad7..c8c837efdf 100644 --- a/webapp/packages/plugin-connection-search/src/locales/ru.ts +++ b/webapp/packages/plugin-connection-search/src/locales/ru.ts @@ -1,3 +1 @@ -export default [ - ['plugin_connection_search_action_search_label', 'Поиск'], -]; +export default [['plugin_connection_search_action_search_label', 'Поиск']]; diff --git a/webapp/packages/plugin-connection-search/src/locales/zh.ts b/webapp/packages/plugin-connection-search/src/locales/zh.ts index 1e83566e27..db83b12b1c 100644 --- a/webapp/packages/plugin-connection-search/src/locales/zh.ts +++ b/webapp/packages/plugin-connection-search/src/locales/zh.ts @@ -1,3 +1 @@ -export default [ - ['plugin_connection_search_action_search_label', 'Search'], -]; +export default [['plugin_connection_search_action_search_label', 'Search']]; diff --git a/webapp/packages/plugin-connection-search/src/manifest.ts b/webapp/packages/plugin-connection-search/src/manifest.ts index acaf3985b4..481cb74b90 100644 --- a/webapp/packages/plugin-connection-search/src/manifest.ts +++ b/webapp/packages/plugin-connection-search/src/manifest.ts @@ -9,10 +9,5 @@ export const connectionSearchPlugin: PluginManifest = { info: { name: 'Search connection plugin', }, - providers: [ - SearchConnectionPluginBootstrap, - ConnectionSearchService, - LocaleService, - ConnectionSearchSettingsService, - ], -}; \ No newline at end of file + providers: [SearchConnectionPluginBootstrap, ConnectionSearchService, LocaleService, ConnectionSearchSettingsService], +}; diff --git a/webapp/packages/plugin-connection-template/src/Actions/ACTION_CONNECTION_TEMPLATE.ts b/webapp/packages/plugin-connection-template/src/Actions/ACTION_CONNECTION_TEMPLATE.ts index 5a2e4ca1e3..bd2c259e79 100644 --- a/webapp/packages/plugin-connection-template/src/Actions/ACTION_CONNECTION_TEMPLATE.ts +++ b/webapp/packages/plugin-connection-template/src/Actions/ACTION_CONNECTION_TEMPLATE.ts @@ -5,12 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; -export const ACTION_CONNECTION_TEMPLATE = createAction( - 'connection-template', - { - label: 'plugin_connection_template_action_connection_template_label', - } -); +export const ACTION_CONNECTION_TEMPLATE = createAction('connection-template', { + label: 'plugin_connection_template_action_connection_template_label', +}); diff --git a/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionController.ts b/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionController.ts index 2ab3e487d2..1490601d66 100644 --- a/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionController.ts +++ b/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionController.ts @@ -5,11 +5,20 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ +import { computed, makeObservable, observable } from 'mobx'; -import { observable, makeObservable, computed } from 'mobx'; - -import { DBDriverResource, Connection, DatabaseAuthModelsResource, ConnectionInfoResource, DBDriver, ConnectionInitConfig, USER_NAME_PROPERTY_ID, createConnectionParam, ConnectionInfoProjectKey } from '@cloudbeaver/core-connections'; -import { injectable, IInitializableController, IDestructibleController } from '@cloudbeaver/core-di'; +import { + Connection, + ConnectionInfoProjectKey, + ConnectionInfoResource, + ConnectionInitConfig, + createConnectionParam, + DatabaseAuthModelsResource, + DBDriver, + DBDriverResource, + USER_NAME_PROPERTY_ID, +} from '@cloudbeaver/core-connections'; +import { IDestructibleController, IInitializableController, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; import { ErrorDetailsDialog } from '@cloudbeaver/core-notifications'; @@ -23,7 +32,7 @@ import { TemplateConnectionsService } from '../TemplateConnectionsService'; export enum ConnectionStep { ConnectionTemplateSelect, - Connection + Connection, } export interface IConnectionController { @@ -34,8 +43,7 @@ export interface IConnectionController { } @injectable() -export class ConnectionController -implements IInitializableController, IDestructibleController, IConnectionController { +export class ConnectionController implements IInitializableController, IDestructibleController, IConnectionController { step = ConnectionStep.ConnectionTemplateSelect; isLoading = true; isConnecting = false; @@ -74,9 +82,7 @@ implements IInitializableController, IDestructibleController, IConnectionControl return []; } - return this.template.networkHandlersConfig - .filter(handler => handler.enabled && !handler.savePassword) - .map(handler => handler.id); + return this.template.networkHandlersConfig.filter(handler => handler.enabled && !handler.savePassword).map(handler => handler.id); } constructor( @@ -128,17 +134,11 @@ implements IInitializableController, IDestructibleController, IConnectionControl this.isConnecting = true; this.clearError(); try { - const connections = await this.connectionInfoResource.load( - ConnectionInfoProjectKey(this.projectsService.userProject.id) - ); + const connections = await this.connectionInfoResource.load(ConnectionInfoProjectKey(this.projectsService.userProject.id)); const connectionNames = connections.map(connection => connection.name); const uniqueConnectionName = getUniqueName(this.template.name || 'Template connection', connectionNames); - const connection = await this.connectionInfoResource.createFromTemplate( - this.template.projectId, - this.template.id, - uniqueConnectionName - ); + const connection = await this.connectionInfoResource.createFromTemplate(this.template.projectId, this.template.id, uniqueConnectionName); try { await this.connectionInfoResource.init(this.getConfig(connection.projectId, connection.id)); @@ -241,7 +241,7 @@ implements IInitializableController, IDestructibleController, IConnectionControl await this.templateConnectionsResource.load(); await this.dbDriverResource.load(CachedMapAllKey); } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t load database sources'); + this.notificationService.logException(exception, "Can't load database sources"); } finally { this.isLoading = false; } @@ -256,7 +256,7 @@ implements IInitializableController, IDestructibleController, IConnectionControl this.isLoading = true; this.authModel = await this.dbAuthModelsResource.load(this.dbDriver.defaultAuthModel); } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t load driver auth model'); + this.notificationService.logException(exception, "Can't load driver auth model"); } finally { this.isLoading = false; } diff --git a/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialog.tsx b/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialog.tsx index 458908c31e..f3a6c9a4d6 100644 --- a/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialog.tsx +++ b/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialog.tsx @@ -5,18 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { - ErrorMessage, - SubmittingForm, - Loader, - useFocus, - useTranslate, - useAdministrationSettings, -} from '@cloudbeaver/core-blocks'; +import { ErrorMessage, Loader, SubmittingForm, useAdministrationSettings, useFocus, useTranslate } from '@cloudbeaver/core-blocks'; import { useController } from '@cloudbeaver/core-di'; import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs'; import { ConnectionAuthenticationFormLoader } from '@cloudbeaver/plugin-connections'; @@ -26,28 +18,27 @@ import { ConnectionDialogFooter } from './ConnectionDialogFooter'; import { TemplateConnectionSelector } from './TemplateConnectionSelector/TemplateConnectionSelector'; const styles = css` - SubmittingForm, center { - display: flex; - flex: 1; - margin: auto; - } - center { - box-sizing: border-box; - flex-direction: column; - align-items: center; - justify-content: center; - } - ConnectionAuthenticationFormLoader { - align-content: center; - } - ErrorMessage { - composes: theme-background-secondary theme-text-on-secondary from global; - } + SubmittingForm, + center { + display: flex; + flex: 1; + margin: auto; + } + center { + box-sizing: border-box; + flex-direction: column; + align-items: center; + justify-content: center; + } + ConnectionAuthenticationFormLoader { + align-content: center; + } + ErrorMessage { + composes: theme-background-secondary theme-text-on-secondary from global; + } `; -export const ConnectionDialog: DialogComponent = observer(function ConnectionDialog({ - rejectDialog, -}) { +export const ConnectionDialog: DialogComponent = observer(function ConnectionDialog({ rejectDialog }) { const [focusedRef] = useFocus({ focusFirstChild: true }); const controller = useController(ConnectionController, rejectDialog); const translate = useTranslate(); @@ -60,7 +51,7 @@ export const ConnectionDialog: DialogComponent = observer(function C } return styled(styles)( - + = observer(function C onSelect={controller.onTemplateSelect} /> )} - {controller.step === ConnectionStep.Connection && (!controller.authModel ? ( -
- {controller.isConnecting && translate('basicConnection_connectionDialog_connecting_message')} -
- ) : ( - - - - ))} + {controller.step === ConnectionStep.Connection && + (!controller.authModel ? ( +
{controller.isConnecting && translate('basicConnection_connectionDialog_connecting_message')}
+ ) : ( + + + + ))} {controller.responseMessage && ( - + )} {controller.step === ConnectionStep.Connection && ( @@ -109,6 +95,6 @@ export const ConnectionDialog: DialogComponent = observer(function C /> )} -
+
, ); }); diff --git a/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialogFooter.tsx b/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialogFooter.tsx index c40d40e8ae..bb8582c617 100644 --- a/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialogFooter.tsx +++ b/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialogFooter.tsx @@ -5,29 +5,27 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; import { Button, useTranslate } from '@cloudbeaver/core-blocks'; - const styles = css` -controls { - display: flex; - flex: 1; - height: 100%; - align-items: center; - margin: auto; -} + controls { + display: flex; + flex: 1; + height: 100%; + align-items: center; + margin: auto; + } -fill { - flex: 1; -} + fill { + flex: 1; + } -Button:not(:first-child) { - margin-left: 24px; -} + Button:not(:first-child) { + margin-left: 24px; + } `; interface Props { @@ -36,34 +34,17 @@ interface Props { onBack: () => void; } -export const ConnectionDialogFooter = observer(function ConnectionDialogFooter({ - isConnecting, - onConnect, - onBack, -}) { +export const ConnectionDialogFooter = observer(function ConnectionDialogFooter({ isConnecting, onConnect, onBack }) { const translate = useTranslate(); return styled(styles)( - - - + , ); -} -); +}); diff --git a/webapp/packages/plugin-connection-template/src/ConnectionDialog/TemplateConnectionSelector/TemplateConnectionItem.tsx b/webapp/packages/plugin-connection-template/src/ConnectionDialog/TemplateConnectionSelector/TemplateConnectionItem.tsx index 4ed75c227a..9462d1bf5c 100644 --- a/webapp/packages/plugin-connection-template/src/ConnectionDialog/TemplateConnectionSelector/TemplateConnectionItem.tsx +++ b/webapp/packages/plugin-connection-template/src/ConnectionDialog/TemplateConnectionSelector/TemplateConnectionItem.tsx @@ -5,15 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback } from 'react'; import styled, { css } from 'reshadow'; -import { - ListItem, ListItemDescription, ListItemName, ListItemIcon, StaticImage -} from '@cloudbeaver/core-blocks'; -import type { DBDriver, Connection } from '@cloudbeaver/core-connections'; +import { ListItem, ListItemDescription, ListItemIcon, ListItemName, StaticImage } from '@cloudbeaver/core-blocks'; +import type { Connection, DBDriver } from '@cloudbeaver/core-connections'; interface Props { template: Connection; @@ -29,18 +26,16 @@ const styles = css` } `; -export const TemplateConnectionItem = observer(function TemplateConnectionItem({ - template, - dbDriver, - onSelect, -}) { +export const TemplateConnectionItem = observer(function TemplateConnectionItem({ template, dbDriver, onSelect }) { const select = useCallback(() => onSelect(template.id), [template]); return styled(styles)( - + + + {template.name} {template.description} - + , ); }); diff --git a/webapp/packages/plugin-connection-template/src/ConnectionDialog/TemplateConnectionSelector/TemplateConnectionSelector.tsx b/webapp/packages/plugin-connection-template/src/ConnectionDialog/TemplateConnectionSelector/TemplateConnectionSelector.tsx index c3834c9558..39fd6c20db 100644 --- a/webapp/packages/plugin-connection-template/src/ConnectionDialog/TemplateConnectionSelector/TemplateConnectionSelector.tsx +++ b/webapp/packages/plugin-connection-template/src/ConnectionDialog/TemplateConnectionSelector/TemplateConnectionSelector.tsx @@ -5,12 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { useState, useMemo } from 'react'; +import { useMemo, useState } from 'react'; import { ItemList, ItemListSearch } from '@cloudbeaver/core-blocks'; -import type { DBDriver, Connection } from '@cloudbeaver/core-connections'; +import type { Connection, DBDriver } from '@cloudbeaver/core-connections'; import { TemplateConnectionItem } from './TemplateConnectionItem'; @@ -40,12 +39,7 @@ export const TemplateConnectionSelector = observer(function TemplateConne {filteredTemplateConnections.map(template => ( - + ))} diff --git a/webapp/packages/plugin-connection-template/src/LocaleService.ts b/webapp/packages/plugin-connection-template/src/LocaleService.ts index 144237a086..e3649a06b4 100644 --- a/webapp/packages/plugin-connection-template/src/LocaleService.ts +++ b/webapp/packages/plugin-connection-template/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-connection-template/src/TemplateConnectionPluginBootstrap.ts b/webapp/packages/plugin-connection-template/src/TemplateConnectionPluginBootstrap.ts index cc943a7395..27c12cf578 100644 --- a/webapp/packages/plugin-connection-template/src/TemplateConnectionPluginBootstrap.ts +++ b/webapp/packages/plugin-connection-template/src/TemplateConnectionPluginBootstrap.ts @@ -5,14 +5,13 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { AppAuthService } from '@cloudbeaver/core-authentication'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects'; import { PermissionsService } from '@cloudbeaver/core-root'; import { CachedMapAllKey, getCachedDataResourceLoaderState, getCachedMapResourceLoaderState } from '@cloudbeaver/core-sdk'; -import { MenuService, ActionService, DATA_CONTEXT_MENU, DATA_CONTEXT_LOADABLE_STATE } from '@cloudbeaver/core-view'; +import { ActionService, DATA_CONTEXT_LOADABLE_STATE, DATA_CONTEXT_MENU, MenuService } from '@cloudbeaver/core-view'; import { MENU_CONNECTIONS } from '@cloudbeaver/plugin-connections'; import { ACTION_CONNECTION_TEMPLATE } from './Actions/ACTION_CONNECTION_TEMPLATE'; @@ -39,33 +38,24 @@ export class TemplateConnectionPluginBootstrap extends Bootstrap { register(): void | Promise { this.menuService.addCreator({ isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === MENU_CONNECTIONS, - getItems: (context, items) => [ - ...items, - ACTION_CONNECTION_TEMPLATE, - ], + getItems: (context, items) => [...items, ACTION_CONNECTION_TEMPLATE], }); this.actionService.addHandler({ id: 'connection-template', - isActionApplicable: (context, action) => [ - ACTION_CONNECTION_TEMPLATE, - ].includes(action), - isHidden: () => ( - !this.appAuthService.authenticated - || !this.projectsService.userProject?.canEditDataSources - || !this.templateConnectionsService.projectTemplates.length - ), + isActionApplicable: (context, action) => [ACTION_CONNECTION_TEMPLATE].includes(action), + isHidden: () => + !this.appAuthService.authenticated || + !this.projectsService.userProject?.canEditDataSources || + !this.templateConnectionsService.projectTemplates.length, getLoader: (context, action) => { const state = context.get(DATA_CONTEXT_LOADABLE_STATE); - return state.getState( - action.id, - () => [ - ...this.appAuthService.loaders, - getCachedMapResourceLoaderState(this.projectInfoResource, CachedMapAllKey), - getCachedDataResourceLoaderState(this.templateConnectionsResource, undefined, undefined), - ] - ); + return state.getState(action.id, () => [ + ...this.appAuthService.loaders, + getCachedMapResourceLoaderState(this.projectInfoResource, CachedMapAllKey), + getCachedDataResourceLoaderState(this.templateConnectionsResource, undefined, undefined), + ]); }, handler: async (context, action) => { switch (action) { @@ -78,7 +68,7 @@ export class TemplateConnectionPluginBootstrap extends Bootstrap { }); } - load(): void | Promise { } + load(): void | Promise {} private async openConnectionsDialog() { await this.commonDialogService.open(ConnectionDialog, null); diff --git a/webapp/packages/plugin-connection-template/src/TemplateConnectionsResource.ts b/webapp/packages/plugin-connection-template/src/TemplateConnectionsResource.ts index 66c433bf56..d944e8ba70 100644 --- a/webapp/packages/plugin-connection-template/src/TemplateConnectionsResource.ts +++ b/webapp/packages/plugin-connection-template/src/TemplateConnectionsResource.ts @@ -5,19 +5,18 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { AppAuthService } from '@cloudbeaver/core-authentication'; import { Connection, ConnectionInfoResource } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; -import { SessionDataResource } from '@cloudbeaver/core-root'; -import { GraphQLService, CachedDataResource, ResourceKeyUtils } from '@cloudbeaver/core-sdk'; +import { SessionDataResource } from '@cloudbeaver/core-root'; +import { CachedDataResource, GraphQLService, ResourceKeyUtils } from '@cloudbeaver/core-sdk'; @injectable() export class TemplateConnectionsResource extends CachedDataResource { constructor( private readonly graphQLService: GraphQLService, connectionInfoResource: ConnectionInfoResource, - sessionDataResource:SessionDataResource, + sessionDataResource: SessionDataResource, appAuthService: AppAuthService, ) { super(() => []); @@ -32,9 +31,7 @@ export class TemplateConnectionsResource extends CachedDataResource { - const isAnyTemplate = connectionInfoResource - .get(ResourceKeyUtils.toList(list)) - .some(connection => connection?.template); + const isAnyTemplate = connectionInfoResource.get(ResourceKeyUtils.toList(list)).some(connection => connection?.template); if (isAnyTemplate) { this.markOutdated(); diff --git a/webapp/packages/plugin-connection-template/src/TemplateConnectionsService.ts b/webapp/packages/plugin-connection-template/src/TemplateConnectionsService.ts index 391856c0d5..3ff2e52b51 100644 --- a/webapp/packages/plugin-connection-template/src/TemplateConnectionsService.ts +++ b/webapp/packages/plugin-connection-template/src/TemplateConnectionsService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { Connection } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { ProjectsService } from '@cloudbeaver/core-projects'; @@ -15,10 +14,7 @@ import { TemplateConnectionsResource } from './TemplateConnectionsResource'; @injectable() export class TemplateConnectionsService { get projectTemplates(): Connection[] { - if ( - this.projectsService.userProject - && this.projectsService.activeProjects.includes(this.projectsService.userProject) - ) { + if (this.projectsService.userProject && this.projectsService.activeProjects.includes(this.projectsService.userProject)) { return this.templateConnectionsResource.data; } @@ -28,9 +24,5 @@ export class TemplateConnectionsService { // ); return []; } - constructor( - private readonly templateConnectionsResource: TemplateConnectionsResource, - private readonly projectsService: ProjectsService, - ) { - } + constructor(private readonly templateConnectionsResource: TemplateConnectionsResource, private readonly projectsService: ProjectsService) {} } diff --git a/webapp/packages/plugin-connection-template/src/locales/zh.ts b/webapp/packages/plugin-connection-template/src/locales/zh.ts index d554184ac7..52ea3d122e 100644 --- a/webapp/packages/plugin-connection-template/src/locales/zh.ts +++ b/webapp/packages/plugin-connection-template/src/locales/zh.ts @@ -1,12 +1,12 @@ export default [ - ['basicConnection_connectionDialog_newConnection', '新连接'], - ['basicConnection_connectionDialog_title', '连接数据库'], - ['basicConnection_connectionDialog_listTitle', '数据库:'], - ['basicConnection_connectionDialog_username', '用户库用户名:'], - ['basicConnection_connectionDialog_usernamePlaceholder', '用户'], - ['basicConnection_connectionDialog_password', '数据库用户密码:'], - ['basicConnection_connectionDialog_passwordPlaceholder', '密码'], - ['basicConnection_connectionDialog_connecting', '连接中...'], - ['basicConnection_connectionDialog_connecting_message', '连接数据库...'], - ['basicConnection_main_menu_item', '从模板创建'], - ]; + ['basicConnection_connectionDialog_newConnection', '新连接'], + ['basicConnection_connectionDialog_title', '连接数据库'], + ['basicConnection_connectionDialog_listTitle', '数据库:'], + ['basicConnection_connectionDialog_username', '用户库用户名:'], + ['basicConnection_connectionDialog_usernamePlaceholder', '用户'], + ['basicConnection_connectionDialog_password', '数据库用户密码:'], + ['basicConnection_connectionDialog_passwordPlaceholder', '密码'], + ['basicConnection_connectionDialog_connecting', '连接中...'], + ['basicConnection_connectionDialog_connecting_message', '连接数据库...'], + ['basicConnection_main_menu_item', '从模板创建'], +]; diff --git a/webapp/packages/plugin-connection-template/src/manifest.ts b/webapp/packages/plugin-connection-template/src/manifest.ts index e490e37ca5..7accde3222 100644 --- a/webapp/packages/plugin-connection-template/src/manifest.ts +++ b/webapp/packages/plugin-connection-template/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { LocaleService } from './LocaleService'; @@ -18,10 +17,5 @@ export const connectionTemplate: PluginManifest = { name: 'Template Connections plugin', }, - providers: [ - TemplateConnectionsResource, - LocaleService, - TemplateConnectionPluginBootstrap, - TemplateConnectionsService, - ], + providers: [TemplateConnectionsResource, LocaleService, TemplateConnectionPluginBootstrap, TemplateConnectionsService], }; 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 227da76394..731cf009e2 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministration.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministration.tsx @@ -5,12 +5,25 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { AdministrationItemContentProps, ADMINISTRATION_TOOLS_PANEL_STYLES } from '@cloudbeaver/core-administration'; -import { Loader, useResource, ToolsAction, ToolsPanel, useTranslate, useStyles, Translate, Group, ColoredContainer, BASE_CONTAINERS_STYLES, Container, GroupTitle, GroupItem } from '@cloudbeaver/core-blocks'; +import { ADMINISTRATION_TOOLS_PANEL_STYLES, AdministrationItemContentProps } from '@cloudbeaver/core-administration'; +import { + BASE_CONTAINERS_STYLES, + ColoredContainer, + Container, + Group, + GroupItem, + GroupTitle, + Loader, + ToolsAction, + ToolsPanel, + Translate, + useResource, + useStyles, + useTranslate, +} from '@cloudbeaver/core-blocks'; import { ConnectionInfoActiveProjectKey, ConnectionInfoResource, DBDriverResource } from '@cloudbeaver/core-connections'; import { useController, useService } from '@cloudbeaver/core-di'; import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; @@ -58,7 +71,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 2229772d76..47f2c18d1c 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationController.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationController.ts @@ -5,15 +5,23 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ +import { computed, makeObservable, observable } from 'mobx'; -import { observable, computed, makeObservable } from 'mobx'; - -import { compareConnectionsInfo, compareNewConnectionsInfo, Connection, ConnectionInfoActiveProjectKey, ConnectionInfoResource, createConnectionParam, DatabaseConnection, IConnectionInfoParams } from '@cloudbeaver/core-connections'; +import { + compareConnectionsInfo, + compareNewConnectionsInfo, + Connection, + ConnectionInfoActiveProjectKey, + ConnectionInfoResource, + createConnectionParam, + DatabaseConnection, + IConnectionInfoParams, +} from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { CommonDialogService, ConfirmationDialogDelete, DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; import { LocalizationService } from '@cloudbeaver/core-localization'; -import { isSharedProject, isGlobalProject, ProjectInfoResource, projectInfoSortByName } from '@cloudbeaver/core-projects'; +import { isGlobalProject, isSharedProject, ProjectInfoResource, projectInfoSortByName } from '@cloudbeaver/core-projects'; import { resourceKeyList } from '@cloudbeaver/core-sdk'; import { isArraysEqual, isDefined, isObjectsEqual } from '@cloudbeaver/core-utils'; @@ -66,7 +74,7 @@ export class ConnectionsAdministrationController { private readonly connectionInfoResource: ConnectionInfoResource, private readonly commonDialogService: CommonDialogService, private readonly localizationService: LocalizationService, - private readonly projectInfoResource: ProjectInfoResource + private readonly projectInfoResource: ProjectInfoResource, ) { makeObservable(this, { isProcessing: observable, @@ -97,8 +105,7 @@ export class ConnectionsAdministrationController { return; } - const deletionList = Array - .from(this.selectedItems) + const deletionList = Array.from(this.selectedItems) .filter(([_, value]) => value) .map(([connectionId]) => connectionId); @@ -108,7 +115,9 @@ export class ConnectionsAdministrationController { const connectionNames = deletionList.map(id => this.connectionInfoResource.get(id)?.name).filter(Boolean); const nameList = connectionNames.map(name => `"${name}"`).join(', '); - const message = `${this.localizationService.translate('connections_administration_delete_confirmation')}${nameList}. ${this.localizationService.translate('ui_are_you_sure')}`; + const message = `${this.localizationService.translate( + 'connections_administration_delete_confirmation', + )}${nameList}. ${this.localizationService.translate('ui_are_you_sure')}`; const result = await this.commonDialogService.open(ConfirmationDialogDelete, { title: 'ui_data_delete_confirmation', diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationNavService.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationNavService.ts index d966c336c3..7704f4a23c 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationNavService.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationNavService.ts @@ -5,15 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { AdministrationScreenService } from '@cloudbeaver/core-administration'; import { injectable } from '@cloudbeaver/core-di'; @injectable() export class ConnectionsAdministrationNavService { - constructor( - private readonly administrationScreenService: AdministrationScreenService - ) { } + constructor(private readonly administrationScreenService: AdministrationScreenService) {} navToRoot() { this.administrationScreenService.navigateToItem('connections'); 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 a33506d8f2..a772049291 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministrationService.ts @@ -5,13 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; import { AdministrationItemService, AdministrationItemType } from '@cloudbeaver/core-administration'; import { PlaceholderContainer } from '@cloudbeaver/core-blocks'; import { ConnectionInfoActiveProjectKey, ConnectionInfoResource, DatabaseConnection, DBDriverResource } from '@cloudbeaver/core-connections'; -import { injectable, Bootstrap } from '@cloudbeaver/core-di'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService, ConfirmationDialog, DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; import { ServerConfigResource } from '@cloudbeaver/core-root'; @@ -55,7 +54,7 @@ export class ConnectionsAdministrationService extends Bootstrap { private readonly dbDriverResource: DBDriverResource, private readonly createConnectionService: CreateConnectionService, private readonly commonDialogService: CommonDialogService, - private readonly serverConfigResource: ServerConfigResource + private readonly serverConfigResource: ServerConfigResource, ) { super(); } @@ -88,13 +87,9 @@ export class ConnectionsAdministrationService extends Bootstrap { this.connectionDetailsPlaceholder.add(SSH, 2); } - load(): void | Promise { } + load(): void | Promise {} - private async refreshUserConnections( - configuration: boolean, - outside: boolean, - outsideAdminPage: boolean - ): Promise { + private async refreshUserConnections(configuration: boolean, outside: boolean, outsideAdminPage: boolean): Promise { // TODO: we have to track users' leaving the page if (outside) { this.connectionInfoResource.cleanNewFlags(); diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsDrawerItem.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsDrawerItem.tsx index bd27449806..7396f283c5 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsDrawerItem.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsDrawerItem.tsx @@ -5,20 +5,25 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled from 'reshadow'; import type { AdministrationItemDrawerProps } from '@cloudbeaver/core-administration'; -import { useStyles, Translate } from '@cloudbeaver/core-blocks'; -import { Tab, TabTitle, TabIcon } from '@cloudbeaver/core-ui'; +import { Translate, useStyles } from '@cloudbeaver/core-blocks'; +import { Tab, TabIcon, TabTitle } from '@cloudbeaver/core-ui'; export const ConnectionsDrawerItem: React.FC = function ConnectionsDrawerItem({ - item, onSelect, style, disabled, configurationWizard, + item, + onSelect, + style, + disabled, + configurationWizard, }) { return styled(useStyles(style))( onSelect(item.name)}> - - - + + + + + , ); }; 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 6d6d87fa5f..f54530b163 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 @@ -5,17 +5,13 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { - TableItem, TableColumnValue, TableItemSelect, TableItemExpand, StaticImage, Placeholder, Loader -} from '@cloudbeaver/core-blocks'; +import { Loader, Placeholder, StaticImage, TableColumnValue, TableItem, TableItemExpand, TableItemSelect } from '@cloudbeaver/core-blocks'; import { DatabaseConnection, DBDriverResource, IConnectionInfoParams } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; - import { ConnectionsAdministrationService } from '../ConnectionsAdministrationService'; import { ConnectionEdit } from './ConnectionEdit'; @@ -59,19 +55,24 @@ export const Connection = observer(function Connection({ connectionKey, c - {connection.name} - {connection.host}{connection.host && connection.port && `:${connection.port}`} + + {connection.name} + + + {connection.host} + {connection.host && connection.port && `:${connection.port}`} + {connection.folder && connection.folder} {projectName !== undefined && ( - {projectName})} + + {projectName} + + )} - + - + , ); }); diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/ConnectionDetailsStyles.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/ConnectionDetailsStyles.ts index 5403502278..4163986891 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/ConnectionDetailsStyles.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/ConnectionDetailsStyles.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { css } from 'reshadow'; export const CONNECTION_DETAILS_STYLES = css` 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 6fed134352..3af2422328 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 @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; @@ -15,9 +14,7 @@ import { PlaceholderComponent, StaticImage } from '@cloudbeaver/core-blocks'; import type { IConnectionDetailsPlaceholderProps } from '../../ConnectionsAdministrationService'; import { CONNECTION_DETAILS_STYLES } from './ConnectionDetailsStyles'; -export const Origin: PlaceholderComponent = observer(function Origin({ - connection, -}) { +export const Origin: PlaceholderComponent = observer(function Origin({ connection }) { const isLocal = connection.origin?.type === AUTH_PROVIDER_LOCAL_ID; if (!connection.origin || isLocal) { @@ -27,7 +24,5 @@ export const Origin: PlaceholderComponent = const icon = connection.origin.icon; const title = connection.origin.displayName; - return styled(CONNECTION_DETAILS_STYLES)( - - ); + return styled(CONNECTION_DETAILS_STYLES)(); }); diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/SSH.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/SSH.tsx index 128b4bafff..26cf7d7fcb 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/SSH.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/SSH.tsx @@ -5,14 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; import { PlaceholderComponent, StaticImage, useResource, useTranslate } from '@cloudbeaver/core-blocks'; import { NetworkHandlerResource, SSH_TUNNEL_ID } from '@cloudbeaver/core-connections'; - import type { IConnectionDetailsPlaceholderProps } from '../../ConnectionsAdministrationService'; import { CONNECTION_DETAILS_STYLES } from './ConnectionDetailsStyles'; @@ -27,6 +25,6 @@ export const SSH: PlaceholderComponent = obs } return styled(CONNECTION_DETAILS_STYLES)( - + , ); }); diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/Template.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/Template.tsx index a51406b3ec..6493619398 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/Template.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionDetailsInfo/Template.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; @@ -19,7 +18,5 @@ export const Template: PlaceholderComponent return null; } - return styled(CONNECTION_DETAILS_STYLES)( - - ); + return styled(CONNECTION_DETAILS_STYLES)(); }); 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 17e5087327..87fe8e34b1 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 @@ -5,9 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { useRef, useEffect } from 'react'; +import { useEffect, useRef } from 'react'; import styled, { css } from 'reshadow'; import { Loader } from '@cloudbeaver/core-blocks'; @@ -16,26 +15,24 @@ import { useService } from '@cloudbeaver/core-di'; import { ConnectionFormLoader, useConnectionFormState } from '@cloudbeaver/plugin-connections'; const styles = css` - box { - composes: theme-background-secondary theme-text-on-secondary from global; - box-sizing: border-box; - padding-bottom: 24px; - display: flex; - flex-direction: column; - height: 740px; - } - Loader { - height: 100%; - } - `; + box { + composes: theme-background-secondary theme-text-on-secondary from global; + box-sizing: border-box; + padding-bottom: 24px; + display: flex; + flex-direction: column; + height: 740px; + } + Loader { + height: 100%; + } +`; interface Props { item: IConnectionInfoParams; } -export const ConnectionEdit = observer(function ConnectionEditNew({ - item, -}) { +export const ConnectionEdit = observer(function ConnectionEditNew({ item }) { const connectionInfoResource = useService(ConnectionInfoResource); const boxRef = useRef(null); // const tableContext = useContext(TableContext); @@ -48,10 +45,7 @@ export const ConnectionEdit = observer(function ConnectionEditNew({ }); }, []); - const data = useConnectionFormState( - connectionInfoResource, - state => state.setOptions('edit', 'admin') - ); + const data = useConnectionFormState(connectionInfoResource, state => state.setOptions('edit', 'admin')); data.config.connectionId = item.connectionId; data.projectId = item.projectId; @@ -65,6 +59,6 @@ export const ConnectionEdit = observer(function ConnectionEditNew({ // onSave={collapse} /> - + , ); }); 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 f410b39fb9..eb84affb52 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 @@ -5,14 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { - Table, TableHeader, TableColumnHeader, - TableBody, TableSelect, useTranslate, - getComputed, useResource -} from '@cloudbeaver/core-blocks'; +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'; @@ -27,25 +22,20 @@ interface Props { expandedItems: Map; } -export const ConnectionsTable = observer(function ConnectionsTable({ - keys, - connections, - selectedItems, - expandedItems, -}) { +export const ConnectionsTable = observer(function ConnectionsTable({ keys, 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 displayProjects = getComputed( + () => projectService.activeProjects.filter(project => isGlobalProject(project) || isSharedProject(project)).length > 1, + ); function getProjectName(projectId: string) { - return displayProjects ? (projectsLoader.resource.get(projectId)?.name ?? null) : undefined; + return displayProjects ? projectsLoader.resource.get(projectId)?.name ?? null : undefined; } return ( -
+
diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/CreateConnection.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/CreateConnection.tsx index e61d510c3f..3cec7ef372 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/CreateConnection.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/CreateConnection.tsx @@ -5,108 +5,109 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { IconButton, Loader, StaticImage, Icon, useResource, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { Icon, IconButton, Loader, StaticImage, useResource, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; import { DBDriverResource } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; -import { TabsState, TabList, UNDERLINE_TAB_STYLES, TabPanelList, BASE_TAB_STYLES } from '@cloudbeaver/core-ui'; +import { BASE_TAB_STYLES, TabList, TabPanelList, TabsState, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui'; import { ConnectionFormLoader } from '@cloudbeaver/plugin-connections'; import { CreateConnectionService } from '../CreateConnectionService'; const styles = css` - title-bar { - composes: theme-border-color-background from global; + title-bar { + composes: theme-border-color-background from global; + } + + connection-create { + display: flex; + flex-direction: column; + height: 800px; + overflow: hidden; + } + + connection-create-content { + composes: theme-background-secondary theme-text-on-secondary from global; + position: relative; + display: flex; + flex-direction: column; + flex: 1; + overflow: auto; + } + + Tab { + composes: theme-ripple theme-background-secondary theme-text-on-secondary from global; + height: 46px !important; + text-transform: uppercase; + font-weight: 500 !important; + } + + TabList { + composes: theme-border-color-background theme-background-secondary theme-text-on-secondary from global; + border-top: solid 1px; + position: relative; + flex-shrink: 0; + align-items: center; + + &:before { + content: ''; + position: absolute; + bottom: 0; + width: 100%; + border-bottom: solid 2px; + border-color: inherit; } + } - connection-create { - display: flex; - flex-direction: column; - height: 800px; - overflow: hidden; - } + TabPanel, + CustomConnection, + SearchDatabase { + flex-direction: column; + height: 100%; + overflow: auto; + } - connection-create-content { - composes: theme-background-secondary theme-text-on-secondary from global; - position: relative; - display: flex; - flex-direction: column; - flex: 1; - overflow: auto; - } + Loader { + z-index: 1; + height: 100%; + } - Tab { - composes: theme-ripple theme-background-secondary theme-text-on-secondary from global; - height: 46px!important; - text-transform: uppercase; - font-weight: 500 !important; - } + title-bar { + composes: theme-typography--headline6 from global; + padding: 16px 24px; + align-items: center; + display: flex; + font-weight: 400; + flex: auto 0 0; + } - TabList { - composes: theme-border-color-background theme-background-secondary theme-text-on-secondary from global; - border-top: solid 1px; - position: relative; - flex-shrink: 0; - align-items: center; + StaticImage { + width: 32px; + max-height: 32px; + margin-right: 16px; + } - &:before { - content: ''; - position: absolute; - bottom: 0; - width: 100%; - border-bottom: solid 2px; - border-color: inherit; - } - } + fill { + flex: 1; + } - TabPanel, CustomConnection, SearchDatabase { - flex-direction: column; - height: 100%; - overflow: auto; - } + back-button { + position: relative; + box-sizing: border-box; + margin-right: 16px; + display: flex; - Loader { - z-index: 1; - height: 100%; - } - - title-bar { - composes: theme-typography--headline6 from global; - padding: 16px 24px; - align-items: center; - display: flex; - font-weight: 400; - flex: auto 0 0; - } - - StaticImage { - width: 32px; - max-height: 32px; - margin-right: 16px; - } - - fill { - flex: 1; - } - - back-button { - position: relative; + & Icon { box-sizing: border-box; - margin-right: 16px; - display: flex; - - & Icon { - box-sizing: border-box; - transform: rotate(90deg); - cursor: pointer; - height: 16px; - width: 16px; - } + transform: rotate(90deg); + cursor: pointer; + height: 16px; + width: 16px; } - `; + } +`; const componentStyle = [BASE_TAB_STYLES, styles, UNDERLINE_TAB_STYLES]; @@ -115,23 +116,19 @@ interface Props { configurationWizard: boolean; } -export const CreateConnection = observer(function CreateConnection({ - method, -}) { +export const CreateConnection = observer(function CreateConnection({ method }) { const style = useStyles(componentStyle); const createConnectionService = useService(CreateConnectionService); const translate = useTranslate(); - const driver = useResource( - CreateConnection, - DBDriverResource, - createConnectionService.data?.config.driverId || null - ); + const driver = useResource(CreateConnection, DBDriverResource, createConnectionService.data?.config.driverId || null); if (createConnectionService.data) { return styled(style)( - + + + {driver.data?.icon && } {driver.data?.name ?? translate('connections_administration_connection_create')} @@ -146,7 +143,7 @@ export const CreateConnection = observer(function CreateConnection({ /> - + , ); } @@ -170,6 +167,6 @@ export const CreateConnection = observer(function CreateConnection({ {createConnectionService.disabled && } - + , ); }); diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/CreateConnectionBaseBootstrap.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/CreateConnectionBaseBootstrap.ts index 702acaf91c..0c552a45c8 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/CreateConnectionBaseBootstrap.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/CreateConnectionBaseBootstrap.ts @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; -import { injectable, Bootstrap } from '@cloudbeaver/core-di'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { CreateConnectionService } from '../CreateConnectionService'; @@ -19,9 +18,7 @@ const CustomConnection = React.lazy(async () => { @injectable() export class CreateConnectionBaseBootstrap extends Bootstrap { - constructor( - private readonly createConnectionService: CreateConnectionService, - ) { + constructor(private readonly createConnectionService: CreateConnectionService) { super(); } @@ -34,5 +31,5 @@ export class CreateConnectionBaseBootstrap extends Bootstrap { }); } - load(): void | Promise { } + load(): void | Promise {} } diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/ConnectionManualService.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/ConnectionManualService.ts index 4f9aa57c90..a02d981ba0 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/ConnectionManualService.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/ConnectionManualService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { ConnectionInfoResource } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; @@ -21,10 +20,7 @@ export class ConnectionManualService { this.createConnectionService.disabled = value; } - constructor( - private readonly connectionInfoResource: ConnectionInfoResource, - private readonly createConnectionService: CreateConnectionService - ) { + constructor(private readonly connectionInfoResource: ConnectionInfoResource, private readonly createConnectionService: CreateConnectionService) { this.select = this.select.bind(this); } @@ -35,7 +31,7 @@ export class ConnectionManualService { ...this.connectionInfoResource.getEmptyConfig(), driverId, }, - [driverId] + [driverId], ); } } diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/CustomConnection.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/CustomConnection.tsx index ccd3c8b103..675051f499 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/CustomConnection.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/CustomConnection.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useMemo } from 'react'; @@ -26,9 +25,10 @@ export const CustomConnection = observer(function CustomConnection() { const connectionManualService = useService(ConnectionManualService); const dbDriverResource = useResource(CustomConnection, DBDriverResource, CachedMapAllKey); - const drivers = useMemo(() => computed(() => ( - dbDriverResource.resource.enabledDrivers.slice().sort(dbDriverResource.resource.compare) - )), [dbDriverResource]); + const drivers = useMemo( + () => computed(() => dbDriverResource.resource.enabledDrivers.slice().sort(dbDriverResource.resource.compare)), + [dbDriverResource], + ); useResource(CustomConnection, ProjectInfoResource, CachedMapAllKey); diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/Driver.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/Driver.tsx index 41be21c5d6..7fc2dd452b 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/Driver.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/Driver.tsx @@ -5,14 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback } from 'react'; import styled, { css } from 'reshadow'; -import { - ListItem, ListItemIcon, StaticImage, ListItemName, ListItemDescription -} from '@cloudbeaver/core-blocks'; +import { ListItem, ListItemDescription, ListItemIcon, ListItemName, StaticImage } from '@cloudbeaver/core-blocks'; import type { DBDriver } from '@cloudbeaver/core-connections'; const styles = css` @@ -33,9 +30,11 @@ export const Driver = observer(function Driver({ driver, onSelect }) { return styled(styles)( - + + + {driver.name} {driver.description} - + , ); }); diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/DriverList.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/DriverList.tsx index 12ee09ced0..18d24ccfd6 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/DriverList.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/DriverList.tsx @@ -5,15 +5,13 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { useState, useMemo } from 'react'; +import { useMemo, useState } from 'react'; import styled, { css } from 'reshadow'; -import { ItemListSearch, ItemList, useFocus, useTranslate } from '@cloudbeaver/core-blocks'; +import { ItemList, ItemListSearch, useFocus, useTranslate } from '@cloudbeaver/core-blocks'; import type { DBDriver } from '@cloudbeaver/core-connections'; - import { Driver } from './Driver'; interface Props { @@ -45,8 +43,10 @@ export const DriverList = observer(function DriverList({ drivers, classNa
- {filteredDrivers.map(driver => )} + {filteredDrivers.map(driver => ( + + ))} -
+ , ); }); 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 f7ec8818ab..ff6a4d846a 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts @@ -5,8 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { observable, makeObservable, action } from 'mobx'; +import { action, makeObservable, observable } from 'mobx'; import { AdministrationScreenService } from '@cloudbeaver/core-administration'; import { ConnectionInfoResource } from '@cloudbeaver/core-connections'; @@ -38,7 +37,7 @@ export class CreateConnectionService { private readonly connectionFormService: ConnectionFormService, private readonly connectionInfoResource: ConnectionInfoResource, private readonly projectsService: ProjectsService, - private readonly projectInfoResource: ProjectInfoResource + private readonly projectInfoResource: ProjectInfoResource, ) { this.data = null; this.tabsContainer = new TabsContainer('Connection Creation mode'); @@ -110,12 +109,7 @@ 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.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 1a400ea6d1..f379525af5 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useMemo } from 'react'; @@ -13,15 +12,15 @@ import styled, { css } from 'reshadow'; import { TeamsResource, UsersResource } from '@cloudbeaver/core-authentication'; import { - TextPlaceholder, - Loader, - useResource, BASE_CONTAINERS_STYLES, ColoredContainer, - Group, Container, + Group, InfoItem, + Loader, + TextPlaceholder, useAutoLoad, + useResource, useTranslate, } from '@cloudbeaver/core-blocks'; import { isCloudConnection } from '@cloudbeaver/core-connections'; @@ -34,7 +33,6 @@ import { ConnectionAccessGrantedList } from './ConnectionAccessGrantedList'; import { ConnectionAccessList } from './ConnectionAccessList'; import { useConnectionAccessState } from './useConnectionAccessState'; - const styles = css` ColoredContainer { flex: 1; @@ -51,10 +49,7 @@ const styles = css` } `; -export const ConnectionAccess: TabContainerPanelComponent = observer(function ConnectionAccess({ - tabId, - state: formState, -}) { +export const ConnectionAccess: TabContainerPanelComponent = observer(function ConnectionAccess({ tabId, state: formState }) { const state = useConnectionAccessState(formState.info); const translate = useTranslate(); @@ -65,13 +60,15 @@ export const ConnectionAccess: TabContainerPanelComponent const users = useResource(ConnectionAccess, UsersResource, CachedMapAllKey, { active: selected }); const teams = useResource(ConnectionAccess, TeamsResource, CachedMapAllKey, { active: selected }); - const grantedUsers = useMemo(() => computed(() => users.resource.values - .filter(user => state.state.grantedSubjects.includes(user.userId)) - ), [state.state.grantedSubjects, users.resource]); + const grantedUsers = useMemo( + () => computed(() => users.resource.values.filter(user => state.state.grantedSubjects.includes(user.userId))), + [state.state.grantedSubjects, users.resource], + ); - const grantedTeams = useMemo(() => computed(() => teams.resource.values - .filter(team => state.state.grantedSubjects.includes(team.teamId)) - ), [state.state.grantedSubjects, teams.resource]); + const grantedTeams = useMemo( + () => computed(() => teams.resource.values.filter(team => state.state.grantedSubjects.includes(team.teamId))), + [state.state.grantedSubjects, teams.resource], + ); if (!selected) { return null; @@ -88,39 +85,47 @@ export const ConnectionAccess: TabContainerPanelComponent info = 'cloud_connections_access_placeholder'; } - return styled(styles, BASE_CONTAINERS_STYLES)( + return styled( + styles, + BASE_CONTAINERS_STYLES, + )( - {() => styled(styles, BASE_CONTAINERS_STYLES)( - - {!users.resource.values.length && !teams.resource.values.length ? ( - - {translate('connections_administration_connection_access_empty')} - - ) : ( - <> - {info && } - - - {state.state.editing && ( - + styled( + styles, + BASE_CONTAINERS_STYLES, + )( + + {!users.resource.values.length && !teams.resource.values.length ? ( + + {translate('connections_administration_connection_access_empty')} + + ) : ( + <> + {info && } + + - )} - - - )} - - )} - + {state.state.editing && ( + + )} + + + )} + , + ) + } +
, ); }); diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessGrantedList.tsx b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessGrantedList.tsx index 15e8a4c988..45ff8b0a09 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessGrantedList.tsx +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessGrantedList.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useCallback, useState } from 'react'; @@ -13,49 +12,50 @@ import styled, { css } from 'reshadow'; import type { TeamInfo } from '@cloudbeaver/core-authentication'; import { - Table, - TableBody, - TableItem, - TableColumnValue, BASE_CONTAINERS_STYLES, - Group, Button, - useObjectRef, getComputed, getSelectedItems, - useTranslate + Group, + Table, + TableBody, + TableColumnValue, + TableItem, + useObjectRef, + useTranslate, } from '@cloudbeaver/core-blocks'; import type { TLocalizationToken } from '@cloudbeaver/core-localization'; import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; - import { ConnectionAccessTableHeader, IFilterState } from './ConnectionAccessTableHeader/ConnectionAccessTableHeader'; import { ConnectionAccessTableInnerHeader } from './ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader'; import { ConnectionAccessTableItem } from './ConnectionAccessTableItem'; import { getFilteredTeams, getFilteredUsers } from './getFilteredSubjects'; const styles = css` - Table { - composes: theme-background-surface theme-text-on-surface from global; - } - Group { - position: relative; - } - Group, container, table-container { - height: 100%; - } - container { - display: flex; - flex-direction: column; - width: 100%; - } - ConnectionAccessTableHeader { - flex: 0 0 auto; - } - table-container { - overflow: auto; - } - `; + Table { + composes: theme-background-surface theme-text-on-surface from global; + } + Group { + position: relative; + } + Group, + container, + table-container { + height: 100%; + } + container { + display: flex; + flex-direction: column; + width: 100%; + } + ConnectionAccessTableHeader { + flex: 0 0 auto; + } + table-container { + overflow: auto; + } +`; interface Props { grantedUsers: AdminUserInfoFragment[]; @@ -97,21 +97,26 @@ export const ConnectionAccessGrantedList = observer(function ConnectionAc } } - return styled(styles, BASE_CONTAINERS_STYLES)( + return styled( + styles, + BASE_CONTAINERS_STYLES, + )( - - + +
- - - {translate(tableInfoText)} - + + {translate(tableInfoText)} {teams.map(team => ( (function ConnectionAc name={team.teamName || team.teamId} tooltip={team.teamId} description={team.description} - icon='/icons/team.svg' + icon="/icons/team.svg" iconTooltip={translate('authentication_team_icon_tooltip')} disabled={disabled} /> @@ -131,7 +136,7 @@ export const ConnectionAccessGrantedList = observer(function ConnectionAc id={user.userId} name={user.userId} tooltip={user.userId} - icon='/icons/user.svg' + icon="/icons/user.svg" iconTooltip={translate('authentication_user_icon_tooltip')} disabled={disabled} /> @@ -140,6 +145,6 @@ export const ConnectionAccessGrantedList = observer(function ConnectionAc
-
+ , ); }); diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessList.tsx b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessList.tsx index 2cc56f8234..ab811e555d 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessList.tsx +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessList.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useCallback, useState } from 'react'; @@ -13,48 +12,49 @@ import styled, { css } from 'reshadow'; import type { TeamInfo } from '@cloudbeaver/core-authentication'; import { - Table, - TableBody, - TableItem, - TableColumnValue, BASE_CONTAINERS_STYLES, - Group, Button, - useObjectRef, getComputed, getSelectedItems, + Group, + Table, + TableBody, + TableColumnValue, + TableItem, + useObjectRef, useTranslate, } from '@cloudbeaver/core-blocks'; import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; - import { ConnectionAccessTableHeader, IFilterState } from './ConnectionAccessTableHeader/ConnectionAccessTableHeader'; import { ConnectionAccessTableInnerHeader } from './ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader'; import { ConnectionAccessTableItem } from './ConnectionAccessTableItem'; import { getFilteredTeams, getFilteredUsers } from './getFilteredSubjects'; const styles = css` - Table { - composes: theme-background-surface theme-text-on-surface from global; - } - Group { - position: relative; - } - Group, container, table-container { - height: 100%; - } - container { - display: flex; - flex-direction: column; - width: 100%; - } - table-container { - overflow: auto; - } - ConnectionAccessTableHeader { - flex: 0 0 auto; - } - `; + Table { + composes: theme-background-surface theme-text-on-surface from global; + } + Group { + position: relative; + } + Group, + container, + table-container { + height: 100%; + } + container { + display: flex; + flex-direction: column; + width: 100%; + } + table-container { + overflow: auto; + } + ConnectionAccessTableHeader { + flex: 0 0 auto; + } +`; interface Props { userList: AdminUserInfoFragment[]; @@ -64,13 +64,7 @@ interface Props { disabled: boolean; } -export const ConnectionAccessList = observer(function ConnectionAccessList({ - userList, - teamList, - grantedSubjects, - onGrant, - disabled, -}) { +export const ConnectionAccessList = observer(function ConnectionAccessList({ userList, teamList, grantedSubjects, onGrant, disabled }) { const props = useObjectRef({ onGrant }); const translate = useTranslate(); const [selectedSubjects] = useState>(() => observable(new Map())); @@ -87,25 +81,24 @@ export const ConnectionAccessList = observer(function ConnectionAccessLis selectedSubjects.clear(); }, []); - return styled(styles, BASE_CONTAINERS_STYLES)( + return styled( + styles, + BASE_CONTAINERS_STYLES, + )( - + - !grantedSubjects.includes(item)} - > +
!grantedSubjects.includes(item)}> {!keys.length && filterState.filterValue && ( - - - {translate('ui_search_no_result_placeholder')} - + + {translate('ui_search_no_result_placeholder')} )} {teams.map(team => ( @@ -115,7 +108,7 @@ export const ConnectionAccessList = observer(function ConnectionAccessLis name={team.teamName || team.teamId} tooltip={team.teamId} description={team.description} - icon='/icons/team.svg' + icon="/icons/team.svg" iconTooltip={translate('authentication_team_icon_tooltip')} disabled={disabled} /> @@ -126,7 +119,7 @@ export const ConnectionAccessList = observer(function ConnectionAccessLis id={user.userId} name={user.userId} tooltip={user.userId} - icon='/icons/user.svg' + icon="/icons/user.svg" iconTooltip={translate('authentication_user_icon_tooltip')} disabled={disabled} /> @@ -135,6 +128,6 @@ export const ConnectionAccessList = observer(function ConnectionAccessLis
-
+ , ); }); diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTabService.ts b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTabService.ts index 9973fe4176..b5b6891281 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTabService.ts +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTabService.ts @@ -15,7 +15,14 @@ import { executorHandlerFilter, IExecutionContextProvider } from '@cloudbeaver/c import { isGlobalProject, ProjectInfoResource } from '@cloudbeaver/core-projects'; import { PermissionsService } from '@cloudbeaver/core-root'; import type { MetadataValueGetter } from '@cloudbeaver/core-utils'; -import { connectionConfigContext, ConnectionFormService, connectionFormStateContext, IConnectionFormProps, IConnectionFormState, IConnectionFormSubmitData } from '@cloudbeaver/plugin-connections'; +import { + connectionConfigContext, + ConnectionFormService, + connectionFormStateContext, + IConnectionFormProps, + IConnectionFormState, + IConnectionFormSubmitData, +} from '@cloudbeaver/plugin-connections'; import type { IConnectionAccessTabState } from './IConnectionAccessTabState'; @@ -46,35 +53,23 @@ export class ConnectionAccessTabService extends Bootstrap { title: 'connections_connection_edit_access', order: 4, stateGetter: context => this.stateGetter(context), - isHidden: (_, context) => ( - !context - || !this.isAccessTabActive(context.state) - ), - isDisabled: (tabId, props) => !props?.state.config.driverId - || this.administrationScreenService.isConfigurationMode, + isHidden: (_, context) => !context || !this.isAccessTabActive(context.state), + isDisabled: (tabId, props) => !props?.state.config.driverId || this.administrationScreenService.isConfigurationMode, panel: () => ConnectionAccess, }); - this.connectionFormService.formSubmittingTask - .addHandler(executorHandlerFilter( - data => this.isAccessTabActive(data.state), - this.save.bind(this) - )); + this.connectionFormService.formSubmittingTask.addHandler(executorHandlerFilter(data => this.isAccessTabActive(data.state), this.save.bind(this))); - this.connectionFormService.formStateTask - .addHandler(executorHandlerFilter( - this.isAccessTabActive.bind(this), - this.formState.bind(this) - )); + this.connectionFormService.formStateTask.addHandler(executorHandlerFilter(this.isAccessTabActive.bind(this), this.formState.bind(this))); } - load(): void { } + load(): void {} private isAccessTabActive(state: IConnectionFormState): boolean { return ( - state.projectId !== null - && isGlobalProject(this.projectInfoResource.get(state.projectId)) - && this.permissionsResource.has(EAdminPermission.admin) + state.projectId !== null && + isGlobalProject(this.projectInfoResource.get(state.projectId)) && + this.permissionsResource.has(EAdminPermission.admin) ); } @@ -88,14 +83,8 @@ export class ConnectionAccessTabService extends Bootstrap { }); } - private async save( - data: IConnectionFormSubmitData, - contexts: IExecutionContextProvider - ) { - if ( - data.submitType === 'test' - || !data.state.projectId - ) { + private async save(data: IConnectionFormSubmitData, contexts: IExecutionContextProvider) { + if (data.submitType === 'test' || !data.state.projectId) { return; } const status = contexts.getContext(this.connectionFormService.connectionStatusContext); @@ -105,11 +94,9 @@ export class ConnectionAccessTabService extends Bootstrap { } const config = contexts.getContext(connectionConfigContext); - const state = this.connectionFormService.tabsContainer.getTabState( - data.state.partsState, - this.key, - { state: data.state } - ); + const state = this.connectionFormService.tabsContainer.getTabState(data.state.partsState, this.key, { + state: data.state, + }); if (!config.connectionId || !state.loaded) { return; @@ -120,24 +107,14 @@ export class ConnectionAccessTabService extends Bootstrap { const changed = await this.isChanged(key, state.grantedSubjects); if (changed) { - await this.connectionInfoResource.setAccessSubjects( - key, - state.grantedSubjects - ); + await this.connectionInfoResource.setAccessSubjects(key, state.grantedSubjects); state.initialGrantedSubjects = state.grantedSubjects.slice(); } } - private async formState( - data: IConnectionFormState, - contexts: IExecutionContextProvider - ) { + private async formState(data: IConnectionFormState, contexts: IExecutionContextProvider) { const config = contexts.getContext(connectionConfigContext); - const state = this.connectionFormService.tabsContainer.getTabState( - data.partsState, - this.key, - { state: data } - ); + const state = this.connectionFormService.tabsContainer.getTabState(data.partsState, this.key, { state: data }); if (!config.connectionId || !data.projectId || !state.loaded) { return; diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableHeader/ConnectionAccessTableHeader.tsx b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableHeader/ConnectionAccessTableHeader.tsx index a6eafb27ed..2e0590a279 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableHeader/ConnectionAccessTableHeader.tsx +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableHeader/ConnectionAccessTableHeader.tsx @@ -5,13 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { Filter, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; - - +import { Filter, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; export interface IFilterState { filterValue: string; @@ -24,38 +21,41 @@ interface Props { } const styles = css` - buttons { - display: flex; - gap: 16px; - } - header { - composes: theme-border-color-background theme-background-surface theme-text-on-surface from global; - overflow: hidden; - position: sticky; - top: 0; - z-index: 1; - display: flex; - align-items: center; - justify-content: space-between; - padding: 16px; - gap: 16px; - border-bottom: 1px solid; - } - `; + buttons { + display: flex; + gap: 16px; + } + header { + composes: theme-border-color-background theme-background-surface theme-text-on-surface from global; + overflow: hidden; + position: sticky; + top: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px; + gap: 16px; + border-bottom: 1px solid; + } +`; -export const ConnectionAccessTableHeader = observer>(function ConnectionAccessTableHeader({ filterState, disabled, className, children }) { +export const ConnectionAccessTableHeader = observer>(function ConnectionAccessTableHeader({ + filterState, + disabled, + className, + children, +}) { const translate = useTranslate(); return styled(useStyles(styles))(
- - {children} - -
+ {children} + , ); }); diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader.tsx b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader.tsx index f34595d8d8..687681ceeb 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader.tsx +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { TableColumnHeader, TableHeader, TableSelect, useTranslate } from '@cloudbeaver/core-blocks'; @@ -20,7 +19,7 @@ export const ConnectionAccessTableInnerHeader = observer(function Connect return ( - + {translate('connections_connection_access_user_or_team_name')} diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableItem.tsx b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableItem.tsx index bb6bc5171e..1c48ef168f 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableItem.tsx +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableItem.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -30,22 +29,25 @@ const style = css` `; export const ConnectionAccessTableItem = observer(function ConnectionAccessTableItem({ - id, name, description, icon, iconTooltip, tooltip, disabled, className, + id, + name, + description, + icon, + iconTooltip, + tooltip, + disabled, + className, }) { return styled(style)( - + - + + + {name} {description} - + , ); }); diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/getFilteredSubjects.ts b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/getFilteredSubjects.ts index fd9dc67158..6232fd4120 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/getFilteredSubjects.ts +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/getFilteredSubjects.ts @@ -5,7 +5,6 @@ * 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 type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; @@ -16,7 +15,7 @@ import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; export function getFilteredUsers(users: AdminUserInfoFragment[], filter: string): AdminUserInfoFragment[] { return users .filter(user => user.enabled && user.userId.toLowerCase().includes(filter.toLowerCase())) - .sort((a, b) => (a.userId).localeCompare(b.userId)); + .sort((a, b) => a.userId.localeCompare(b.userId)); } /** diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/useConnectionAccessState.ts b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/useConnectionAccessState.ts index 6896968741..e99b6bc394 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/useConnectionAccessState.ts +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/useConnectionAccessState.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, computed, observable } from 'mobx'; import { IAutoLoadable, useObservableRef } from '@cloudbeaver/core-blocks'; @@ -32,74 +31,76 @@ export function useConnectionAccessState(connection: DatabaseConnectionFragment const notificationService = useService(NotificationService); const state = useTabState(); - return useObservableRef(() => ({ - exception: null as Error | null, - get changed() { - return !isArraysEqual(this.state.initialGrantedSubjects, this.state.grantedSubjects); - }, - isLoading() { - return this.state.loading; - }, - isError() { - return isContainsException(this.exception); - }, - isLoaded() { - return this.state.loaded; - }, - edit() { - this.state.editing = !this.state.editing; - }, - revoke(subjectIds: string[]) { - this.state.grantedSubjects = this.state.grantedSubjects.filter(subject => !subjectIds.includes(subject)); - }, - grant(subjectIds: string[]) { - this.state.grantedSubjects.push(...subjectIds); - }, - async load(reload = false) { - let loaded = this.exception || this.state.loaded; + return useObservableRef( + () => ({ + exception: null as Error | null, + get changed() { + return !isArraysEqual(this.state.initialGrantedSubjects, this.state.grantedSubjects); + }, + isLoading() { + return this.state.loading; + }, + isError() { + return isContainsException(this.exception); + }, + isLoaded() { + return this.state.loaded; + }, + edit() { + this.state.editing = !this.state.editing; + }, + revoke(subjectIds: string[]) { + this.state.grantedSubjects = this.state.grantedSubjects.filter(subject => !subjectIds.includes(subject)); + }, + grant(subjectIds: string[]) { + this.state.grantedSubjects.push(...subjectIds); + }, + async load(reload = false) { + let loaded = this.exception || this.state.loaded; - if (reload) { - loaded = false; - } - - if (loaded || this.state.loading) { - return; - } - - try { - this.state.loading = true; - - if (this.connection) { - const key = createConnectionParam(this.connection); - const grantedSubjects = await this.resource.loadAccessSubjects(key); - this.state.grantedSubjects = grantedSubjects.map(subject => subject.subjectId); - this.state.initialGrantedSubjects = this.state.grantedSubjects.slice(); + if (reload) { + loaded = false; } - this.state.loaded = true; - this.exception = null; - } catch (exception: any) { - this.notificationService.logException(exception, 'connections_connection_edit_access_load_failed'); - this.exception = exception; - } finally { - this.state.loading = false; - } + if (loaded || this.state.loading) { + return; + } + + try { + this.state.loading = true; + + if (this.connection) { + const key = createConnectionParam(this.connection); + const grantedSubjects = await this.resource.loadAccessSubjects(key); + this.state.grantedSubjects = grantedSubjects.map(subject => subject.subjectId); + this.state.initialGrantedSubjects = this.state.grantedSubjects.slice(); + } + + this.state.loaded = true; + this.exception = null; + } catch (exception: any) { + this.notificationService.logException(exception, 'connections_connection_edit_access_load_failed'); + this.exception = exception; + } finally { + this.state.loading = false; + } + }, + async reload() { + this.load(true); + }, + }), + { + exception: observable.ref, + state: observable.ref, + changed: computed, + edit: action.bound, + isLoading: action.bound, + isLoaded: action.bound, + reload: action.bound, + revoke: action.bound, + grant: action.bound, }, - async reload() { - this.load(true); - }, - }), - { - exception: observable.ref, - state: observable.ref, - changed: computed, - edit: action.bound, - isLoading: action.bound, - isLoaded: action.bound, - reload: action.bound, - revoke: action.bound, - grant: action.bound, - }, - { state, connection, resource, notificationService }, - ['load']); + { state, connection, resource, notificationService }, + ['load'], + ); } diff --git a/webapp/packages/plugin-connections-administration/src/LocaleService.ts b/webapp/packages/plugin-connections-administration/src/LocaleService.ts index 144237a086..e3649a06b4 100644 --- a/webapp/packages/plugin-connections-administration/src/LocaleService.ts +++ b/webapp/packages/plugin-connections-administration/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-connections-administration/src/index.ts b/webapp/packages/plugin-connections-administration/src/index.ts index 515700d344..939e1ee7f7 100644 --- a/webapp/packages/plugin-connections-administration/src/index.ts +++ b/webapp/packages/plugin-connections-administration/src/index.ts @@ -1,4 +1,5 @@ import { connectionPlugin } from './manifest'; + export * from './Administration/Connections/ConnectionsAdministration'; export * from './Administration/Connections/CreateConnection/Manual/ConnectionManualService'; export * from './Administration/Connections/ConnectionsAdministrationNavService'; diff --git a/webapp/packages/plugin-connections-administration/src/locales/it.ts b/webapp/packages/plugin-connections-administration/src/locales/it.ts index 73d0dd1037..3be43aa970 100644 --- a/webapp/packages/plugin-connections-administration/src/locales/it.ts +++ b/webapp/packages/plugin-connections-administration/src/locales/it.ts @@ -1,4 +1,4 @@ export default [ ['connections_public_connection_edit_menu_item_title', 'Modifica Connessione'], - ['connections_public_connection_edit_cancel_title', 'Conferma l\'annullamento'], + ['connections_public_connection_edit_cancel_title', "Conferma l'annullamento"], ]; diff --git a/webapp/packages/plugin-connections-administration/src/manifest.ts b/webapp/packages/plugin-connections-administration/src/manifest.ts index 9c70e33a83..a1564cd91a 100644 --- a/webapp/packages/plugin-connections-administration/src/manifest.ts +++ b/webapp/packages/plugin-connections-administration/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { ConnectionsAdministrationNavService } from './Administration/Connections/ConnectionsAdministrationNavService'; diff --git a/webapp/packages/plugin-connections/src/ConnectionAuthService.ts b/webapp/packages/plugin-connections/src/ConnectionAuthService.ts index faf7ae24cb..5405991776 100644 --- a/webapp/packages/plugin-connections/src/ConnectionAuthService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionAuthService.ts @@ -5,9 +5,14 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { AuthProviderService } from '@cloudbeaver/core-authentication'; -import { Connection, ConnectionInfoResource, ConnectionsManagerService, createConnectionParam, IConnectionInfoParams } from '@cloudbeaver/core-connections'; +import { + Connection, + ConnectionInfoResource, + ConnectionsManagerService, + createConnectionParam, + IConnectionInfoParams, +} from '@cloudbeaver/core-connections'; import { Dependency, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService, DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; @@ -30,17 +35,12 @@ export class ConnectionAuthService extends Dependency { connectionsManagerService.connectionExecutor.addHandler(this.connectionDialog.bind(this)); this.authenticationService.onLogout.before(connectionsManagerService.onDisconnect, state => ({ - connections: connectionInfoResource.values - .filter(connection => connection.connected) - .map(createConnectionParam), + connections: connectionInfoResource.values.filter(connection => connection.connected).map(createConnectionParam), state, })); } - private async connectionDialog( - connectionKey: IConnectionInfoParams, - context: IExecutionContextProvider - ) { + private async connectionDialog(connectionKey: IConnectionInfoParams, context: IExecutionContextProvider) { const connection = context.getContext(this.connectionsManagerService.connectionContext); try { @@ -84,8 +84,8 @@ export class ConnectionAuthService extends Dependency { connection = await this.connectionInfoResource.load(key, ['includeAuthNeeded', 'includeNetworkHandlersConfig', 'includeCredentialsSaved']); - const networkHandlers = connection.networkHandlersConfig! - .filter(handler => handler.enabled && (!handler.savePassword || resetCredentials)) + const networkHandlers = connection + .networkHandlersConfig!.filter(handler => handler.enabled && (!handler.savePassword || resetCredentials)) .map(handler => handler.id); if (connection.authNeeded || (connection.credentialsSaved && resetCredentials) || networkHandlers.length > 0) { diff --git a/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationDialog.tsx b/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationDialog.tsx index 77a697cc01..047fb8d9c3 100644 --- a/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationDialog.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationDialog.tsx @@ -5,16 +5,14 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { SubmittingForm, useFocus, Button, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { Button, SubmittingForm, useFocus, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; import { useDBDriver } from '@cloudbeaver/core-connections'; import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; - import { ConnectionAuthenticationFormLoader } from './ConnectionAuthenticationFormLoader'; const styles = css` @@ -50,7 +48,7 @@ export const ConnectionAuthenticationDialog: DialogComponent = observer const { driver } = useDBDriver(payload.driverId || ''); return styled(useStyles(styles))( - + = observer {translate('ui_apply')} - + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationDialogLoader.tsx b/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationDialogLoader.tsx index 596310934c..d84191c6d6 100644 --- a/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationDialogLoader.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationDialogLoader.tsx @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; export const ConnectionAuthenticationDialogLoader = React.lazy(async () => { const { ConnectionAuthenticationDialog } = await import('./ConnectionAuthenticationDialog'); return { default: ConnectionAuthenticationDialog }; -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationForm.tsx b/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationForm.tsx index 5da00066d2..bda8ad1104 100644 --- a/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationForm.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationForm.tsx @@ -5,15 +5,24 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; -import { BASE_CONTAINERS_STYLES, Container, FieldCheckbox, Group, GroupTitle, ObjectPropertyInfoForm, TextPlaceholder, useResource, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { + BASE_CONTAINERS_STYLES, + Container, + FieldCheckbox, + Group, + GroupTitle, + ObjectPropertyInfoForm, + TextPlaceholder, + useResource, + useStyles, + useTranslate, +} from '@cloudbeaver/core-blocks'; import { DatabaseAuthModelsResource } from '@cloudbeaver/core-connections'; import type { ObjectPropertyInfo } from '@cloudbeaver/core-sdk'; - import type { IConnectionAuthenticationConfig } from './IConnectionAuthenticationConfig'; import { NetworkHandlers } from './NetworkHandlers'; @@ -89,6 +98,6 @@ export const ConnectionAuthenticationForm = observer(function ConnectionA disabled={disabled} /> )} - + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationFormLoader.tsx b/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationFormLoader.tsx index c5ef42b8ec..f2eb496816 100644 --- a/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationFormLoader.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionAuthentication/ConnectionAuthenticationFormLoader.tsx @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; export const ConnectionAuthenticationFormLoader = React.lazy(async () => { const { ConnectionAuthenticationForm } = await import('./ConnectionAuthenticationForm'); return { default: ConnectionAuthenticationForm }; -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-connections/src/ConnectionAuthentication/IConnectionAuthenticationConfig.ts b/webapp/packages/plugin-connections/src/ConnectionAuthentication/IConnectionAuthenticationConfig.ts index f8cf9ef6e4..f38bb9f1ac 100644 --- a/webapp/packages/plugin-connections/src/ConnectionAuthentication/IConnectionAuthenticationConfig.ts +++ b/webapp/packages/plugin-connections/src/ConnectionAuthentication/IConnectionAuthenticationConfig.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { NetworkHandlerConfigInput } from '@cloudbeaver/core-sdk'; export interface IConnectionAuthenticationConfig { diff --git a/webapp/packages/plugin-connections/src/ConnectionAuthentication/NetworkHandlerAuthForm.tsx b/webapp/packages/plugin-connections/src/ConnectionAuthentication/NetworkHandlerAuthForm.tsx index 7ce4ea8c8e..d809c3bff7 100644 --- a/webapp/packages/plugin-connections/src/ConnectionAuthentication/NetworkHandlerAuthForm.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionAuthentication/NetworkHandlerAuthForm.tsx @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; -import { BASE_CONTAINERS_STYLES, FieldCheckbox, GroupTitle, InputField, useResource, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { BASE_CONTAINERS_STYLES, FieldCheckbox, GroupTitle, InputField, useResource, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; import { NetworkHandlerResource } from '@cloudbeaver/core-connections'; import { NetworkHandlerAuthType, NetworkHandlerConfigInput } from '@cloudbeaver/core-sdk'; @@ -39,27 +38,19 @@ export const NetworkHandlerAuthForm = observer(function NetworkHandlerAut const state = networkHandlersConfig.find(state => state.id === id)!; const keyAuth = state.authType === NetworkHandlerAuthType.PublicKey; - const passwordLabel = keyAuth ? 'Passphrase' : translate(`connections_network_handler_${id}_password`, 'connections_network_handler_default_password'); + const passwordLabel = keyAuth + ? 'Passphrase' + : translate(`connections_network_handler_${id}_password`, 'connections_network_handler_default_password'); return styled(useStyles(BASE_CONTAINERS_STYLES))( <> - {handler.data?.label || translate(`connections_network_handler_${id}_title`, 'connections_network_handler_default_title')} - + + {handler.data?.label || translate(`connections_network_handler_${id}_title`, 'connections_network_handler_default_title')} + + {translate(`connections_network_handler_${id}_user`, 'connections_network_handler_default_user')} - + {passwordLabel} {keyAuth && } @@ -72,6 +63,6 @@ export const NetworkHandlerAuthForm = observer(function NetworkHandlerAut disabled={disabled} /> )} - + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionAuthentication/NetworkHandlers.tsx b/webapp/packages/plugin-connections/src/ConnectionAuthentication/NetworkHandlers.tsx index 80535692f9..767543019f 100644 --- a/webapp/packages/plugin-connections/src/ConnectionAuthentication/NetworkHandlers.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionAuthentication/NetworkHandlers.tsx @@ -1,4 +1,3 @@ - /* * CloudBeaver - Cloud Database Manager * Copyright (C) 2020-2023 DBeaver Corp and others @@ -6,14 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; import { BASE_CONTAINERS_STYLES, Group, useStyles } from '@cloudbeaver/core-blocks'; import type { NetworkHandlerConfigInput } from '@cloudbeaver/core-sdk'; - import { NetworkHandlerAuthForm } from './NetworkHandlerAuthForm'; interface Props { @@ -41,6 +38,6 @@ export const NetworkHandlers = observer(function NetworkHandlers({ networ disabled={disabled} /> ))} - + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionForm.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionForm.tsx index 6f79f54fbf..018f61c75b 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionForm.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionForm.tsx @@ -5,15 +5,25 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useEffect } from 'react'; import styled, { css } from 'reshadow'; -import { Placeholder, useObjectRef, useExecutor, BASE_CONTAINERS_STYLES, IconOrImage, Loader, ErrorMessage, useErrorDetails, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { + BASE_CONTAINERS_STYLES, + ErrorMessage, + IconOrImage, + Loader, + Placeholder, + useErrorDetails, + useExecutor, + useObjectRef, + useStyles, + useTranslate, +} from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; -import { TabsState, TabList, UNDERLINE_TAB_STYLES, TabPanelList, BASE_TAB_STYLES } from '@cloudbeaver/core-ui'; +import { BASE_TAB_STYLES, TabList, TabPanelList, TabsState, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui'; import { ConnectionFormService } from './ConnectionFormService'; import { connectionConfigContext } from './Contexts/connectionConfigContext'; @@ -26,78 +36,78 @@ const tabsStyles = css` align-items: center; } Tab { - height: 46px!important; + height: 46px !important; text-transform: uppercase; font-weight: 500 !important; } `; const topBarStyles = css` - connection-top-bar { - composes: theme-border-color-background theme-background-secondary theme-text-on-secondary from global; - } - connection-top-bar { - position: relative; - display: flex; - padding-top: 16px; + connection-top-bar { + composes: theme-border-color-background theme-background-secondary theme-text-on-secondary from global; + } + connection-top-bar { + position: relative; + display: flex; + padding-top: 16px; - &:before { - content: ''; - position: absolute; - bottom: 0; - width: 100%; - border-bottom: solid 2px; - border-color: inherit; - } - } - connection-top-bar-tabs { - flex: 1; + &:before { + content: ''; + position: absolute; + bottom: 0; + width: 100%; + border-bottom: solid 2px; + border-color: inherit; } + } + connection-top-bar-tabs { + flex: 1; + } - connection-top-bar-actions { - display: flex; - align-items: center; - padding: 0 24px; - gap: 16px; - } + connection-top-bar-actions { + display: flex; + align-items: center; + padding: 0 24px; + gap: 16px; + } - /*Button:not(:first-child) { + /*Button:not(:first-child) { margin-right: 24px; }*/ - connection-status-message { - composes: theme-typography--caption from global; - height: 24px; - padding: 0 16px; - display: flex; - align-items: center; - gap: 8px; + connection-status-message { + composes: theme-typography--caption from global; + height: 24px; + padding: 0 16px; + display: flex; + align-items: center; + gap: 8px; - & IconOrImage { - height: 24px; - width: 24px; - } + & IconOrImage { + height: 24px; + width: 24px; } - `; + } +`; const formStyles = css` - box { - composes: theme-background-secondary theme-text-on-secondary from global; - display: flex; - flex-direction: column; - flex: 1; - height: 100%; - overflow: auto; - } - content-box { - composes: theme-background-secondary theme-border-color-background from global; - position: relative; - display: flex; - flex: 1; - flex-direction: column; - overflow: auto; - } - `; + box { + composes: theme-background-secondary theme-text-on-secondary from global; + display: flex; + flex-direction: column; + flex: 1; + height: 100%; + overflow: auto; + } + content-box { + composes: theme-background-secondary theme-border-color-background from global; + position: relative; + display: flex; + flex: 1; + flex-direction: column; + overflow: auto; + } +`; interface Props { state: IConnectionFormState; @@ -106,12 +116,7 @@ interface Props { className?: string; } -export const ConnectionForm = observer(function ConnectionForm({ - state, - onCancel, - onSave = () => { }, - className, -}) { +export const ConnectionForm = observer(function ConnectionForm({ state, onCancel, onSave = () => {}, className }) { const translate = useTranslate(); const props = useObjectRef({ onSave }); const style = [BASE_TAB_STYLES, tabsStyles, UNDERLINE_TAB_STYLES]; @@ -121,15 +126,17 @@ export const ConnectionForm = observer(function ConnectionForm({ useExecutor({ executor: state.submittingTask, - postHandlers: [function save(data, contexts) { - const validation = contexts.getContext(service.connectionValidationContext); - const state = contexts.getContext(service.connectionStatusContext); - const config = contexts.getContext(connectionConfigContext); + postHandlers: [ + function save(data, contexts) { + const validation = contexts.getContext(service.connectionValidationContext); + const state = contexts.getContext(service.connectionStatusContext); + const config = contexts.getContext(connectionConfigContext); - if (validation.valid && state.saved && data.submitType === 'submit') { - props.onSave(config); - } - }], + if (validation.valid && state.saved && data.submitType === 'submit') { + props.onSave(config); + } + }, + ], }); useEffect(() => { @@ -137,37 +144,26 @@ export const ConnectionForm = observer(function ConnectionForm({ }, [state]); if (error.name) { - return styled(styles)( - - ); + return styled(styles)(); } if (!state.configured) { return styled(styles)( - + , ); } return styled(styles)( - + {state.statusMessage && ( <> - + {translate(state.statusMessage)} )} @@ -184,6 +180,6 @@ export const ConnectionForm = observer(function ConnectionForm({ - + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormBaseActions.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormBaseActions.tsx index 2d06d6b891..c0c0c47a79 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormBaseActions.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormBaseActions.tsx @@ -5,12 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { AUTH_PROVIDER_LOCAL_ID } from '@cloudbeaver/core-authentication'; import { Button, getComputed, PlaceholderComponent, useResource, useTranslate } from '@cloudbeaver/core-blocks'; -import { DBDriverResource, DatabaseAuthModelsResource } from '@cloudbeaver/core-connections'; +import { DatabaseAuthModelsResource, DBDriverResource } from '@cloudbeaver/core-connections'; import { useAuthenticationAction } from '@cloudbeaver/core-ui'; import type { IConnectionFormProps } from './IConnectionFormProps'; @@ -20,17 +19,13 @@ export const ConnectionFormBaseActions: PlaceholderComponent state.config.authModelId || state.info?.authModel || driver?.defaultAuthModel || null) + getComputed(() => state.config.authModelId || state.info?.authModel || driver?.defaultAuthModel || null), ); const authentication = useAuthenticationAction({ providerId: authModel?.requiredAuth ?? state.info?.requiredAuth ?? AUTH_PROVIDER_LOCAL_ID, @@ -41,31 +36,14 @@ export const ConnectionFormBaseActions: PlaceholderComponent {onCancel && ( - )} - - diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormBaseActionsLoader.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormBaseActionsLoader.tsx index 08e94a3df2..4904f1e01c 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormBaseActionsLoader.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormBaseActionsLoader.tsx @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; export const ConnectionFormBaseActionsLoader = React.lazy(async () => { const { ConnectionFormBaseActions } = await import('./ConnectionFormBaseActions'); return { default: ConnectionFormBaseActions }; -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormLoader.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormLoader.tsx index 83cf88863d..77b70de265 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormLoader.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormLoader.tsx @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; export const ConnectionFormLoader = React.lazy(async () => { const { ConnectionForm } = await import('./ConnectionForm'); return { default: ConnectionForm }; -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormService.ts index 79f07d371e..076313f2bd 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable, runInAction, toJS } from 'mobx'; import { PlaceholderContainer } from '@cloudbeaver/core-blocks'; @@ -20,7 +19,7 @@ import { ConnectionAuthenticationDialogLoader } from '../ConnectionAuthenticatio import { ConnectionFormBaseActionsLoader } from './ConnectionFormBaseActionsLoader'; import { connectionConfigContext } from './Contexts/connectionConfigContext'; import { connectionCredentialsStateContext } from './Contexts/connectionCredentialsStateContext'; -import type { IConnectionFormProps, IConnectionFormState, IConnectionFormFillConfigData, IConnectionFormSubmitData } from './IConnectionFormProps'; +import type { IConnectionFormFillConfigData, IConnectionFormProps, IConnectionFormState, IConnectionFormSubmitData } from './IConnectionFormProps'; export interface IConnectionFormValidation { valid: boolean; @@ -63,12 +62,9 @@ export class ConnectionFormService { this.formValidationTask = new ExecutorHandlersCollection(); this.formStateTask = new ExecutorHandlersCollection(); - this.formSubmittingTask - .before(this.formValidationTask) - .before(this.prepareConfigTask); + this.formSubmittingTask.before(this.formValidationTask).before(this.prepareConfigTask); - this.formStateTask - .before(this.prepareConfigTask, state => ({ state, submitType: 'submit' })); + this.formStateTask.before(this.prepareConfigTask, state => ({ state, submitType: 'submit' })); this.prepareConfigTask.addPostHandler(this.askCredentials); this.formSubmittingTask.addPostHandler(this.showSubmittingStatusMessage); @@ -112,16 +108,15 @@ export class ConnectionFormService { if (status.messages.length > 0) { if (status.exception) { - this.notificationService.logException( - status.exception, - status.messages[0], - status.messages.slice(1).join('\n') - ); + this.notificationService.logException(status.exception, status.messages[0], status.messages.slice(1).join('\n')); } else { - this.notificationService.notify({ - title: status.messages[0], - message: status.messages.slice(1).join('\n'), - }, status.saved ? ENotificationType.Success : ENotificationType.Error); + this.notificationService.notify( + { + title: status.messages[0], + message: status.messages.slice(1).join('\n'), + }, + status.saved ? ENotificationType.Success : ENotificationType.Error, + ); } } }; @@ -174,12 +169,14 @@ export class ConnectionFormService { if (validation.messages.length > 0) { const messages = validation.messages.map(message => this.localizationService.translate(message)); - this.notificationService.notify({ - title: data.state.mode === 'edit' - ? 'connections_administration_connection_save_error' - : 'connections_administration_connection_create_error', - message: messages.join('\n'), - }, validation.valid ? ENotificationType.Info : ENotificationType.Error); + this.notificationService.notify( + { + title: + data.state.mode === 'edit' ? 'connections_administration_connection_save_error' : 'connections_administration_connection_create_error', + message: messages.join('\n'), + }, + validation.valid ? ENotificationType.Info : ENotificationType.Error, + ); } }; } diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts index aa31ce3d5d..26aa6a9398 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, computed, makeObservable, observable } from 'mobx'; import type { IFormStateInfo } from '@cloudbeaver/core-blocks'; @@ -18,7 +17,7 @@ import { MetadataMap, uuid } from '@cloudbeaver/core-utils'; import { connectionFormConfigureContext } from './connectionFormConfigureContext'; import type { ConnectionFormService } from './ConnectionFormService'; import { connectionFormStateContext } from './Contexts/connectionFormStateContext'; -import type { IConnectionFormState, ConnectionFormMode, ConnectionFormType, IConnectionFormSubmitData } from './IConnectionFormProps'; +import type { ConnectionFormMode, ConnectionFormType, IConnectionFormState, IConnectionFormSubmitData } from './IConnectionFormProps'; export class ConnectionFormState implements IConnectionFormState { mode: ConnectionFormMode; @@ -96,7 +95,7 @@ export class ConnectionFormState implements IConnectionFormState { private readonly projectsService: ProjectsService, private readonly projectInfoResource: ProjectInfoResource, service: ConnectionFormService, - resource: ConnectionInfoResource + resource: ConnectionInfoResource, ) { this._id = uuid(); this.initError = null; @@ -117,7 +116,6 @@ export class ConnectionFormState implements IConnectionFormState { this.mode = 'create'; this.type = 'public'; - this.syncProject = this.syncProject.bind(this); this.syncInfo = this.syncInfo.bind(this); this.test = this.test.bind(this); @@ -126,18 +124,13 @@ export class ConnectionFormState implements IConnectionFormState { this.loadInfo = this.loadInfo.bind(this); this.updateFormState = this.updateFormState.bind(this); - this.formStateTask - .addCollection(service.formStateTask) - .addPostHandler(this.updateFormState); + this.formStateTask.addCollection(service.formStateTask).addPostHandler(this.updateFormState); - this.resource.onItemUpdate - .addHandler(this.syncInfo); + this.resource.onItemUpdate.addHandler(this.syncInfo); - this.projectInfoResource.onDataUpdate - .addHandler(this.syncProject); + this.projectInfoResource.onDataUpdate.addHandler(this.syncProject); - this.projectsService.onActiveProjectChange - .addHandler(this.syncProject); + this.projectsService.onActiveProjectChange.addHandler(this.syncProject); this.submittingTask.addPostHandler(async (data, contexts) => { const status = contexts.getContext(service.connectionStatusContext); @@ -159,9 +152,7 @@ export class ConnectionFormState implements IConnectionFormState { return { state, - updated: state.info !== configuration.info - || state.config.driverId !== configuration.driverId - || !this.configured, + updated: state.info !== configuration.info || state.config.driverId !== configuration.driverId || !this.configured, }; }) .next(this.formStateTask); @@ -214,10 +205,7 @@ export class ConnectionFormState implements IConnectionFormState { return this; } - setOptions( - mode: ConnectionFormMode, - type: ConnectionFormType - ): this { + setOptions(mode: ConnectionFormMode, type: ConnectionFormType): this { this.mode = mode; this.type = type; return this; @@ -247,7 +235,7 @@ export class ConnectionFormState implements IConnectionFormState { state: this, submitType: 'submit', }, - this.service.formSubmittingTask + this.service.formSubmittingTask, ); } @@ -257,7 +245,7 @@ export class ConnectionFormState implements IConnectionFormState { state: this, submitType: 'test', }, - this.service.formSubmittingTask + this.service.formSubmittingTask, ); } @@ -267,12 +255,9 @@ export class ConnectionFormState implements IConnectionFormState { } dispose(): void { - this.resource.onItemUpdate - .removeHandler(this.syncInfo); - this.projectInfoResource.onDataUpdate - .removeHandler(this.syncProject); - this.projectsService.onActiveProjectChange - .removeHandler(this.syncProject); + this.resource.onItemUpdate.removeHandler(this.syncInfo); + this.projectInfoResource.onDataUpdate.removeHandler(this.syncProject); + this.projectsService.onActiveProjectChange.removeHandler(this.syncProject); } async close(): Promise { @@ -300,9 +285,9 @@ export class ConnectionFormState implements IConnectionFormState { private syncInfo(key: ResourceKeySimple) { if ( - !this.config.connectionId - || this.projectId === null - || !this.resource.isIntersect(key, createConnectionParam(this.projectId, this.config.connectionId)) + !this.config.connectionId || + this.projectId === null || + !this.resource.isIntersect(key, createConnectionParam(this.projectId, this.config.connectionId)) ) { return; } diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Contexts/connectionConfigContext.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Contexts/connectionConfigContext.ts index 102332e1b7..4e22566ca3 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Contexts/connectionConfigContext.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Contexts/connectionConfigContext.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; export function connectionConfigContext(): ConnectionConfig { diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Contexts/connectionFormStateContext.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Contexts/connectionFormStateContext.ts index 45f8e6199e..3c7fb83edd 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Contexts/connectionFormStateContext.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Contexts/connectionFormStateContext.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IFormStateInfo } from '@cloudbeaver/core-blocks'; export interface IConnectionFormStateContext extends IFormStateInfo { diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts index 1d41ee5597..07fcbcd570 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, makeObservable } from 'mobx'; import { DBDriverResource } from '@cloudbeaver/core-connections'; @@ -17,15 +16,12 @@ import { connectionFormConfigureContext } from '../connectionFormConfigureContex import { ConnectionFormService } from '../ConnectionFormService'; import { connectionConfigContext } from '../Contexts/connectionConfigContext'; import { connectionFormStateContext } from '../Contexts/connectionFormStateContext'; -import type { IConnectionFormFillConfigData, IConnectionFormSubmitData, IConnectionFormState } from '../IConnectionFormProps'; +import type { IConnectionFormFillConfigData, IConnectionFormState, IConnectionFormSubmitData } from '../IConnectionFormProps'; import { DriverPropertiesLoader } from './DriverPropertiesLoader'; @injectable() export class ConnectionDriverPropertiesTabService extends Bootstrap { - constructor( - private readonly connectionFormService: ConnectionFormService, - private readonly dbDriverResource: DBDriverResource, - ) { + constructor(private readonly connectionFormService: ConnectionFormService, private readonly dbDriverResource: DBDriverResource) { super(); makeObservable(this, { @@ -48,20 +44,16 @@ export class ConnectionDriverPropertiesTabService extends Bootstrap { }, }); - this.connectionFormService.prepareConfigTask - .addHandler(this.prepareConfig.bind(this)); + this.connectionFormService.prepareConfigTask.addHandler(this.prepareConfig.bind(this)); - this.connectionFormService.formStateTask - .addHandler(this.formState.bind(this)); + this.connectionFormService.formStateTask.addHandler(this.formState.bind(this)); - this.connectionFormService.fillConfigTask - .addHandler(this.fillConfig.bind(this)); + this.connectionFormService.fillConfigTask.addHandler(this.fillConfig.bind(this)); - this.connectionFormService.configureTask - .addHandler(this.configure.bind(this)); + this.connectionFormService.configureTask.addHandler(this.configure.bind(this)); } - load(): void { } + load(): void {} private configure(data: IConnectionFormState, contexts: IExecutionContextProvider) { const configuration = contexts.getContext(connectionFormConfigureContext); @@ -69,10 +61,7 @@ export class ConnectionDriverPropertiesTabService extends Bootstrap { configuration.include('includeProperties', 'includeProviderProperties'); } - private fillConfig( - { state, updated }: IConnectionFormFillConfigData, - contexts: IExecutionContextProvider - ) { + private fillConfig({ state, updated }: IConnectionFormFillConfigData, contexts: IExecutionContextProvider) { if (!updated) { return; } @@ -87,21 +76,13 @@ export class ConnectionDriverPropertiesTabService extends Bootstrap { state.config.properties = { ...state.info.properties }; } - private prepareConfig( - { - state, - }: IConnectionFormSubmitData, - contexts: IExecutionContextProvider - ) { + private prepareConfig({ state }: IConnectionFormSubmitData, contexts: IExecutionContextProvider) { const config = contexts.getContext(connectionConfigContext); config.properties = { ...state.config.properties }; } - private formState( - data: IConnectionFormState, - contexts: IExecutionContextProvider - ) { + private formState(data: IConnectionFormState, contexts: IExecutionContextProvider) { if (!data.info || !data.config.driverId) { return; } diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/DriverProperties.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/DriverProperties.tsx index 753da4d0f3..1131c5c909 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/DriverProperties.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/DriverProperties.tsx @@ -5,13 +5,21 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useMemo, useState } from 'react'; import styled, { css } from 'reshadow'; -import { BASE_CONTAINERS_STYLES, ColoredContainer, Group, IProperty, Loader, PropertiesTable, useResource, useStyles } from '@cloudbeaver/core-blocks'; +import { + BASE_CONTAINERS_STYLES, + ColoredContainer, + Group, + IProperty, + Loader, + PropertiesTable, + useResource, + useStyles, +} from '@cloudbeaver/core-blocks'; import { DBDriverResource } from '@cloudbeaver/core-connections'; import { TabContainerPanelComponent, useTab } from '@cloudbeaver/core-ui'; import { uuid } from '@cloudbeaver/core-utils'; @@ -33,10 +41,7 @@ const styles = css` } `; -export const DriverProperties: TabContainerPanelComponent = observer(function DriverProperties({ - tabId, - state: formState, -}) { +export const DriverProperties: TabContainerPanelComponent = observer(function DriverProperties({ tabId, state: formState }) { const style = useStyles(styles, BASE_CONTAINERS_STYLES); const { selected } = useTab(tabId); @@ -60,19 +65,15 @@ export const DriverProperties: TabContainerPanelComponent return { propertiesList, add, remove }; }); - const driver = useResource( - DriverProperties, - DBDriverResource, - { key: (selected && formState.config.driverId) || null, includes: ['includeDriverProperties'] as const }, - ); + const driver = useResource(DriverProperties, DBDriverResource, { + key: (selected && formState.config.driverId) || null, + includes: ['includeDriverProperties'] as const, + }); runInAction(() => { if (driver.data) { for (const key of Object.keys(formState.config.properties)) { - if ( - driver.data.driverProperties.some(property => property.id === key) - || state.propertiesList.some(property => property.key === key) - ) { + if (driver.data.driverProperties.some(property => property.id === key) || state.propertiesList.some(property => property.key === key)) { continue; } @@ -81,21 +82,25 @@ export const DriverProperties: TabContainerPanelComponent } }); - const joinedProperties = useMemo(() => computed(() => ([ - ...state.propertiesList, - ...(driver.data?.driverProperties - ? driver.data.driverProperties.map(property => ({ - id: property.id!, - key: property.id!, - keyPlaceholder: property.id, - displayName: property.displayName, - valuePlaceholder: property.defaultValue, - defaultValue: property.defaultValue, - description: property.description, - validValues: property.validValues, - })) - : []), - ])), [driver.data]); + const joinedProperties = useMemo( + () => + computed(() => [ + ...state.propertiesList, + ...(driver.data?.driverProperties + ? driver.data.driverProperties.map(property => ({ + id: property.id!, + key: property.id!, + keyPlaceholder: property.id, + displayName: property.displayName, + valuePlaceholder: property.defaultValue, + defaultValue: property.defaultValue, + description: property.description, + validValues: property.validValues, + })) + : []), + ]), + [driver.data], + ); return styled(style)( @@ -109,6 +114,6 @@ export const DriverProperties: TabContainerPanelComponent onRemove={state.remove} /> - + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/DriverPropertiesLoader.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/DriverPropertiesLoader.tsx index a4e5b47594..0b0b4e632a 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/DriverPropertiesLoader.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/DriverPropertiesLoader.tsx @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; export const DriverPropertiesLoader = React.lazy(async () => { const { DriverProperties } = await import('./DriverProperties'); return { default: DriverProperties }; -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts index 9a21873c32..1bd1681957 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormProps.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IFormStateInfo } from '@cloudbeaver/core-blocks'; import type { ConnectionInfoResource, DatabaseConnection } from '@cloudbeaver/core-connections'; import type { IExecutor, IExecutorHandlersCollection } from '@cloudbeaver/core-executor'; @@ -42,10 +41,7 @@ export interface IConnectionFormState { readonly loadConnectionInfo: () => Promise; readonly reset: () => void; readonly setPartsState: (state: MetadataMap) => this; - readonly setOptions: ( - mode: ConnectionFormMode, - type: ConnectionFormType - ) => this; + readonly setOptions: (mode: ConnectionFormMode, type: ConnectionFormType) => this; readonly setConfig: (projectId: string, config: ConnectionConfig) => this; readonly setProject: (projectId: string) => this; readonly setAvailableDrivers: (drivers: string[]) => this; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts index 420ec6f017..39692a21d8 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts @@ -5,12 +5,18 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, makeObservable, runInAction, toJS } from 'mobx'; import React from 'react'; -import { AuthProvidersResource, AUTH_PROVIDER_LOCAL_ID, EAdminPermission, UserInfoResource } from '@cloudbeaver/core-authentication'; -import { ConnectionInfoProjectKey, createConnectionParam, DatabaseAuthModelsResource, DatabaseConnection, DBDriverResource, isLocalConnection } from '@cloudbeaver/core-connections'; +import { AUTH_PROVIDER_LOCAL_ID, AuthProvidersResource, EAdminPermission, UserInfoResource } from '@cloudbeaver/core-authentication'; +import { + ConnectionInfoProjectKey, + createConnectionParam, + DatabaseAuthModelsResource, + DatabaseConnection, + DBDriverResource, + isLocalConnection, +} from '@cloudbeaver/core-connections'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -24,7 +30,7 @@ import { ConnectionFormService } from '../ConnectionFormService'; import { connectionConfigContext } from '../Contexts/connectionConfigContext'; import { connectionCredentialsStateContext } from '../Contexts/connectionCredentialsStateContext'; import { connectionFormStateContext } from '../Contexts/connectionFormStateContext'; -import type { IConnectionFormSubmitData, IConnectionFormFillConfigData, IConnectionFormState } from '../IConnectionFormProps'; +import type { IConnectionFormFillConfigData, IConnectionFormState, IConnectionFormSubmitData } from '../IConnectionFormProps'; export const Options = React.lazy(async () => { const { Options } = await import('./Options'); @@ -42,7 +48,7 @@ export class ConnectionOptionsTabService extends Bootstrap { private readonly localizationService: LocalizationService, private readonly authProvidersResource: AuthProvidersResource, private readonly databaseAuthModelsResource: DatabaseAuthModelsResource, - private readonly permissionsService: PermissionsService + private readonly permissionsService: PermissionsService, ) { super(); @@ -59,27 +65,20 @@ export class ConnectionOptionsTabService extends Bootstrap { panel: () => Options, }); - this.connectionFormService.prepareConfigTask - .addHandler(this.prepareConfig.bind(this)); + this.connectionFormService.prepareConfigTask.addHandler(this.prepareConfig.bind(this)); - this.connectionFormService.formValidationTask - .addHandler(this.validate.bind(this)); + this.connectionFormService.formValidationTask.addHandler(this.validate.bind(this)); - this.connectionFormService.formSubmittingTask - .addHandler(this.save.bind(this)); + this.connectionFormService.formSubmittingTask.addHandler(this.save.bind(this)); - this.connectionFormService.formStateTask - .addHandler(this.formState.bind(this)) - .addHandler(this.formAuthState.bind(this)); + this.connectionFormService.formStateTask.addHandler(this.formState.bind(this)).addHandler(this.formAuthState.bind(this)); - this.connectionFormService.configureTask - .addHandler(this.configure.bind(this)); + this.connectionFormService.configureTask.addHandler(this.configure.bind(this)); - this.connectionFormService.fillConfigTask - .addHandler(this.fillConfig.bind(this)); + this.connectionFormService.fillConfigTask.addHandler(this.fillConfig.bind(this)); } - load(): void { } + load(): void {} isProjectShared(state: IConnectionFormState): boolean { if (state.projectId === null) { @@ -103,13 +102,7 @@ export class ConnectionOptionsTabService extends Bootstrap { return adminPermission && originLocal && isProjectShared && !this.serverConfigResource.distributed; } - private async save( - { - state, - submitType, - }: IConnectionFormSubmitData, - contexts: IExecutionContextProvider - ) { + private async save({ state, submitType }: IConnectionFormSubmitData, contexts: IExecutionContextProvider) { const status = contexts.getContext(this.connectionFormService.connectionStatusContext); const config = contexts.getContext(connectionConfigContext); @@ -121,10 +114,7 @@ export class ConnectionOptionsTabService extends Bootstrap { try { if (submitType === 'submit') { if (state.mode === 'edit') { - const connection = await state.resource.update( - createConnectionParam(state.projectId, config.connectionId!), - config - ); + const connection = await state.resource.update(createConnectionParam(state.projectId, config.connectionId!), config); status.info('Connection was updated'); status.info(connection.name); } else { @@ -149,19 +139,10 @@ export class ConnectionOptionsTabService extends Bootstrap { } } - private async validate( - { - state, - }: IConnectionFormSubmitData, - contexts: IExecutionContextProvider - ) { + private async validate({ state }: IConnectionFormSubmitData, contexts: IExecutionContextProvider) { const validation = contexts.getContext(this.connectionFormService.connectionValidationContext); - if ( - state.config.configurationType === DriverConfigurationType.Manual - && state.config.host?.length === 0 - && state.config.driverId - ) { + if (state.config.configurationType === DriverConfigurationType.Manual && state.config.host?.length === 0 && state.config.driverId) { const driver = await this.dbDriverResource.load(state.config.driverId); if (!driver.embedded) { validation.error('plugin_connections_connection_form_host_invalid'); @@ -193,10 +174,7 @@ export class ConnectionOptionsTabService extends Bootstrap { // } } - private fillConfig( - { state, updated }: IConnectionFormFillConfigData, - contexts: IExecutionContextProvider - ) { + private fillConfig({ state, updated }: IConnectionFormFillConfigData, contexts: IExecutionContextProvider) { if (!updated) { return; } @@ -229,7 +207,6 @@ export class ConnectionOptionsTabService extends Bootstrap { state.config.url = state.info.url; state.config.folder = state.info.folder; - state.config.authModelId = state.info.authModel; state.config.saveCredentials = state.info.credentialsSaved; state.config.sharedCredentials = state.info.sharedCredentials; @@ -253,10 +230,7 @@ export class ConnectionOptionsTabService extends Bootstrap { configuration.include('includeOrigin', 'includeAuthProperties', 'includeCredentialsSaved', 'customIncludeOptions'); } - private async prepareConfig( - { state }: IConnectionFormSubmitData, - contexts: IExecutionContextProvider - ) { + private async prepareConfig({ state }: IConnectionFormSubmitData, contexts: IExecutionContextProvider) { const config = contexts.getContext(connectionConfigContext); const credentialsState = contexts.getContext(connectionCredentialsStateContext); @@ -276,9 +250,7 @@ export class ConnectionOptionsTabService extends Bootstrap { tempConfig.name = state.config.name?.trim(); if (tempConfig.name && state.mode === 'create') { - const connections = await state.resource.load( - ConnectionInfoProjectKey(state.projectId) - ); + const connections = await state.resource.load(ConnectionInfoProjectKey(state.projectId)); const connectionNames = connections.map(connection => connection.name); tempConfig.name = getUniqueName(tempConfig.name, connectionNames); @@ -351,17 +323,12 @@ export class ConnectionOptionsTabService extends Bootstrap { }); } - private async formAuthState( - data: IConnectionFormState, - contexts: IExecutionContextProvider - ) { + private async formAuthState(data: IConnectionFormState, contexts: IExecutionContextProvider) { const config = contexts.getContext(connectionConfigContext); const stateContext = contexts.getContext(connectionFormStateContext); const driver = await this.dbDriverResource.load(config.driverId!, ['includeProviderProperties']); - const authModel = await this.databaseAuthModelsResource.load( - config.authModelId ?? data.info?.authModel ?? driver.defaultAuthModel - ); + const authModel = await this.databaseAuthModelsResource.load(config.authModelId ?? data.info?.authModel ?? driver.defaultAuthModel); const providerId = authModel.requiredAuth ?? data.info?.requiredAuth ?? AUTH_PROVIDER_LOCAL_ID; @@ -369,16 +336,15 @@ export class ConnectionOptionsTabService extends Bootstrap { if (!this.userInfoResource.hasToken(providerId)) { const provider = await this.authProvidersResource.load(providerId); - const message = this.localizationService.translate('connections_public_connection_cloud_auth_required', undefined, { providerLabel: provider.label }); + const message = this.localizationService.translate('connections_public_connection_cloud_auth_required', undefined, { + providerLabel: provider.label, + }); stateContext.setStatusMessage(message); stateContext.readonly = data.mode === 'edit'; } } - private async formState( - data: IConnectionFormState, - contexts: IExecutionContextProvider - ) { + private async formState(data: IConnectionFormState, contexts: IExecutionContextProvider) { if (!data.info) { return; } @@ -388,38 +354,29 @@ export class ConnectionOptionsTabService extends Bootstrap { const driver = await this.dbDriverResource.load(data.config.driverId!, ['includeProviderProperties']); if ( - !isValuesEqual(config.name, data.info.name, '') - || !isValuesEqual(config.configurationType, data.info.configurationType, DriverConfigurationType.Manual) - || !isValuesEqual(config.description, data.info.description, '') - || !isValuesEqual(config.template, data.info.template, true) - || !isValuesEqual(config.folder, data.info.folder, undefined) - || !isValuesEqual(config.driverId, data.info.driverId, '') - || (config.url !== undefined && !isValuesEqual(config.url, data.info.url, '')) - || (config.host !== undefined && !isValuesEqual(config.host, data.info.host, '')) - || (config.port !== undefined && !isValuesEqual(config.port, data.info.port, '')) - || (config.serverName !== undefined && !isValuesEqual(config.serverName, data.info.serverName, '')) - || (config.databaseName !== undefined && !isValuesEqual(config.databaseName, data.info.databaseName, '')) - || config.credentials !== undefined - || (config.authModelId !== undefined && !isValuesEqual(config.authModelId, data.info.authModel, '')) - || (config.saveCredentials !== undefined && config.saveCredentials !== data.info.credentialsSaved) - || (config.sharedCredentials !== undefined && config.sharedCredentials !== data.info.sharedCredentials) - || ( - config.providerProperties !== undefined - && !isObjectPropertyInfoStateEqual( - driver.providerProperties, - config.providerProperties, - data.info.providerProperties - ) - ) + !isValuesEqual(config.name, data.info.name, '') || + !isValuesEqual(config.configurationType, data.info.configurationType, DriverConfigurationType.Manual) || + !isValuesEqual(config.description, data.info.description, '') || + !isValuesEqual(config.template, data.info.template, true) || + !isValuesEqual(config.folder, data.info.folder, undefined) || + !isValuesEqual(config.driverId, data.info.driverId, '') || + (config.url !== undefined && !isValuesEqual(config.url, data.info.url, '')) || + (config.host !== undefined && !isValuesEqual(config.host, data.info.host, '')) || + (config.port !== undefined && !isValuesEqual(config.port, data.info.port, '')) || + (config.serverName !== undefined && !isValuesEqual(config.serverName, data.info.serverName, '')) || + (config.databaseName !== undefined && !isValuesEqual(config.databaseName, data.info.databaseName, '')) || + config.credentials !== undefined || + (config.authModelId !== undefined && !isValuesEqual(config.authModelId, data.info.authModel, '')) || + (config.saveCredentials !== undefined && config.saveCredentials !== data.info.credentialsSaved) || + (config.sharedCredentials !== undefined && config.sharedCredentials !== data.info.sharedCredentials) || + (config.providerProperties !== undefined && + !isObjectPropertyInfoStateEqual(driver.providerProperties, config.providerProperties, data.info.providerProperties)) ) { stateContext.markEdited(); } } - private isCredentialsChanged( - authProperties: ObjectPropertyInfo[], - credentials: Record - ) { + private isCredentialsChanged(authProperties: ObjectPropertyInfo[], credentials: Record) { for (const property of authProperties) { const value = credentials[property.id!]; @@ -434,10 +391,7 @@ export class ConnectionOptionsTabService extends Bootstrap { return false; } - private async getConnectionAuthModelProperties( - authModelId: string, - connectionInfo?: DatabaseConnection - ): Promise { + private async getConnectionAuthModelProperties(authModelId: string, connectionInfo?: DatabaseConnection): Promise { const authModel = await this.databaseAuthModelsResource.load(authModelId); let properties = authModel.properties; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx index ebc2775ca5..ac7c8067e7 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx @@ -5,33 +5,32 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback, useRef } from 'react'; import styled, { css } from 'reshadow'; import { AUTH_PROVIDER_LOCAL_ID, EAdminPermission } from '@cloudbeaver/core-authentication'; import { - InputField, - SubmittingForm, - useResource, - ColoredContainer, BASE_CONTAINERS_STYLES, - Group, - GroupTitle, - FieldCheckbox, - ObjectPropertyInfoForm, - Textarea, + ColoredContainer, Combobox, Container, - useFormValidator, + FieldCheckbox, + FormFieldDescription, getComputed, + Group, + GroupTitle, + InputField, + ObjectPropertyInfoForm, Radio, RadioGroup, - FormFieldDescription, - useTranslate, - usePermission, + SubmittingForm, + Textarea, useAdministrationSettings, + useFormValidator, + usePermission, + useResource, + useTranslate, } from '@cloudbeaver/core-blocks'; import { DatabaseAuthModelsResource, DBDriverResource, isLocalConnection } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; @@ -75,21 +74,13 @@ const driverConfiguration: IDriverConfiguration[] = [ }, ]; -export const Options: TabContainerPanelComponent = observer(function Options({ - state, -}) { +export const Options: TabContainerPanelComponent = observer(function Options({ state }) { const serverConfigResource = useResource(Options, ServerConfigResource, undefined as void); const connectionOptionsTabService = useService(ConnectionOptionsTabService); const service = useService(ConnectionFormService); const formRef = useRef(null); const translate = useTranslate(); - const { - info, - config, - availableDrivers, - submittingTask: submittingHandlers, - disabled, - } = state; + const { info, config, availableDrivers, submittingTask: submittingHandlers, disabled } = state; //@TODO it's here until the profile implementation in the CloudBeaver const readonly = state.readonly || info?.authModel === PROFILE_AUTH_MODEL_ID; @@ -118,12 +109,11 @@ export const Options: TabContainerPanelComponent = observe onData: (data, resource, prevDriver) => { optionsHook.setDefaults(data, prevDriver); }, - } + }, ); const driver = driverMap.data; - const configurationTypes = driverConfiguration - .filter(conf => driver?.configurationTypes.includes(conf.value)); + const configurationTypes = driverConfiguration.filter(conf => driver?.configurationTypes.includes(conf.value)); function handleFormChange(value?: unknown, name?: string) { if (name !== 'name') { @@ -148,7 +138,7 @@ export const Options: TabContainerPanelComponent = observe const { data: applicableAuthModels } = useResource( Options, DatabaseAuthModelsResource, - getComputed(() => driver?.applicableAuthModels ? resourceKeyList(driver.applicableAuthModels) : CachedMapEmptyKey) + getComputed(() => (driver?.applicableAuthModels ? resourceKeyList(driver.applicableAuthModels) : CachedMapEmptyKey)), ); const { data: authModel } = useResource( @@ -157,7 +147,7 @@ export const Options: TabContainerPanelComponent = observe getComputed(() => config.authModelId || info?.authModel || driver?.defaultAuthModel || null), { onData: data => optionsHook.setAuthModel(data), - } + }, ); const authentication = useAuthenticationAction({ @@ -169,31 +159,26 @@ export const Options: TabContainerPanelComponent = observe const originLocal = !info || isLocalConnection(info); const templateAvailable = connectionOptionsTabService.isTemplateAvailable(state); - const availableAuthModels = applicableAuthModels.filter(model => !!model && ( - adminPermission - || !model.requiresLocalConfiguration - )); - const drivers = driverMap.resource.enabledDrivers - .filter(({ id }) => availableDrivers.includes(id)); + const availableAuthModels = applicableAuthModels.filter(model => !!model && (adminPermission || !model.requiresLocalConfiguration)); + const drivers = driverMap.resource.enabledDrivers.filter(({ id }) => availableDrivers.includes(id)); let properties = authModel?.properties; - if ( - info?.authProperties - && info.authProperties.length > 0 - && config.authModelId === info.authModel - ) { + if (info?.authProperties && info.authProperties.length > 0 && config.authModelId === info.authModel) { properties = info.authProperties; } - return styled(styles, BASE_CONTAINERS_STYLES)( + return styled( + styles, + BASE_CONTAINERS_STYLES, + )( driver.id} @@ -225,16 +210,9 @@ export const Options: TabContainerPanelComponent = observe > {translate('connections_connection_configuration')} */} - + - + {driverConfiguration.map(conf => ( = observe disabled={disabled} readOnly={readonly} autoComplete={`section-${config.driverId || 'driver'} section-jdbc`} - mod='surface' + mod="surface" > {translate('customConnection_url_JDBC')} @@ -286,7 +264,7 @@ export const Options: TabContainerPanelComponent = observe state={config} disabled={disabled} readOnly={readonly} - mod='surface' + mod="surface" required tiny fill @@ -307,7 +285,7 @@ export const Options: TabContainerPanelComponent = observe state={config} disabled={disabled} autoComplete={`section-${config.driverId || 'driver'} section-folder`} - mod='surface' + mod="surface" autoHide readOnly tiny @@ -324,29 +302,23 @@ export const Options: TabContainerPanelComponent = observe state={config} disabled={edit || disabled} readOnly={readonly} - // autoHide // maybe better to use autoHide + // autoHide // maybe better to use autoHide > {translate('connections_connection_template')} )} - - {(!driver?.anonymousAccess && (authentication.authorized || !edit)) && ( + {!driver?.anonymousAccess && (authentication.authorized || !edit) && ( {translate('connections_connection_edit_authentication')} {availableAuthModels.length > 1 && ( model!.id} @@ -364,7 +336,7 @@ export const Options: TabContainerPanelComponent = observe <> = observe > {translate('connections_connection_edit_save_credentials')} - {( - serverConfigResource.resource.distributed - && connectionOptionsTabService.isProjectShared(state) - ) && ( + {serverConfigResource.resource.distributed && connectionOptionsTabService.isProjectShared(state) && ( = observe )} {driver?.providerProperties && ( - + )} - + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ParametersForm.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ParametersForm.tsx index d92412e0b9..c94fcfaff6 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ParametersForm.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ParametersForm.tsx @@ -5,14 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; -import { BASE_CONTAINERS_STYLES, Container, InputField, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { BASE_CONTAINERS_STYLES, Container, InputField, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; - interface Props { config: ConnectionConfig; disabled?: boolean; @@ -22,64 +20,29 @@ interface Props { originLocal?: boolean; } -export const ParametersForm = observer(function ParametersForm({ - config, - embedded, - requiresServerName, - disabled, - readOnly, - originLocal, -}) { +export const ParametersForm = observer(function ParametersForm({ config, embedded, requiresServerName, disabled, readOnly, originLocal }) { const translate = useTranslate(); return styled(useStyles(BASE_CONTAINERS_STYLES))( {!embedded && ( - + {translate('customConnection_custom_host')} - + {translate('customConnection_custom_port')} )} - + {translate('customConnection_custom_database')} {requiresServerName && ( - + {translate('customConnection_custom_server_name')} )} - + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ProviderPropertiesForm.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ProviderPropertiesForm.tsx index 5012c9693f..69658ee791 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ProviderPropertiesForm.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ProviderPropertiesForm.tsx @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; -import { BASE_CONTAINERS_STYLES, Container, useTranslate, Group, GroupTitle, ObjectPropertyInfoForm } from '@cloudbeaver/core-blocks'; +import { BASE_CONTAINERS_STYLES, Container, Group, GroupTitle, ObjectPropertyInfoForm, useTranslate } from '@cloudbeaver/core-blocks'; import type { ConnectionConfig, DriverProviderPropertyInfoFragment } from '@cloudbeaver/core-sdk'; type DriverProviderPropertyInfo = DriverProviderPropertyInfoFragment; @@ -21,17 +20,10 @@ interface Props { readonly?: boolean; } -export const ProviderPropertiesForm = observer(function ProviderPropertiesForm({ - config, - properties, - disabled, - readonly, -}) { +export const ProviderPropertiesForm = observer(function ProviderPropertiesForm({ config, properties, disabled, readonly }) { const translate = useTranslate(); - const supportedProperties = properties.filter( - property => property.supportedConfigurationTypes?.some(type => type === config.configurationType) - ); + const supportedProperties = properties.filter(property => property.supportedConfigurationTypes?.some(type => type === config.configurationType)); if (!supportedProperties.length) { return null; @@ -67,6 +59,6 @@ export const ProviderPropertiesForm = observer(function ProviderPropertie /> )} - + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/useOptions.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Options/useOptions.ts index e14ca3e182..d9b519c04b 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/useOptions.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/useOptions.ts @@ -5,7 +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 { useObjectRef } from '@cloudbeaver/core-blocks'; @@ -17,22 +16,21 @@ import type { IConnectionFormState } from '../IConnectionFormProps'; const MAX_HOST_LENGTH = 20; export function useOptions(state: IConnectionFormState) { - const refObject = useObjectRef(() => ({ - prevName: null as string | null, - }), { - state, - }); + const refObject = useObjectRef( + () => ({ + prevName: null as string | null, + }), + { + state, + }, + ); return useObjectRef({ updateNameTemplate(driver: DBDriver | undefined) { runInAction(() => { const { prevName, - state: { - config, - info, - mode, - }, + state: { config, info, mode }, } = refObject; const isAutoFill = config.name === prevName || prevName === null; @@ -66,10 +64,7 @@ export function useOptions(state: IConnectionFormState) { setDefaults(driver: DBDriver | undefined, prevDriver?: DBDriver) { runInAction(() => { const { - state: { - config, - info, - }, + state: { config, info }, } = refObject; if (info || driver?.id !== config.driverId) { @@ -77,11 +72,9 @@ export function useOptions(state: IConnectionFormState) { } if (!config.configurationType || !driver?.configurationTypes.includes(config.configurationType)) { - config.configurationType = ( - driver?.configurationTypes.includes(DriverConfigurationType.Manual) - ? DriverConfigurationType.Manual - : DriverConfigurationType.Url - ); + config.configurationType = driver?.configurationTypes.includes(DriverConfigurationType.Manual) + ? DriverConfigurationType.Manual + : DriverConfigurationType.Url; } if ((!prevDriver && config.host === undefined) || config.host === prevDriver?.defaultServer) { @@ -111,10 +104,7 @@ export function useOptions(state: IConnectionFormState) { }, setAuthModel(model: DatabaseAuthModel) { const { - state: { - config, - info, - }, + state: { config, info }, } = refObject; config.credentials = {}; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionFormAuthenticationAction.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionFormAuthenticationAction.tsx index d5d6301f5a..be88f5d3df 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionFormAuthenticationAction.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionFormAuthenticationAction.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { AUTH_PROVIDER_LOCAL_ID } from '@cloudbeaver/core-authentication'; @@ -15,21 +14,15 @@ import { useAuthenticationAction } from '@cloudbeaver/core-ui'; import type { IConnectionFormProps } from '../IConnectionFormProps'; -export const AuthenticationButton: PlaceholderComponent = observer(function ConnectionFormAuthenticationAction({ - state, -}) { +export const AuthenticationButton: PlaceholderComponent = observer(function ConnectionFormAuthenticationAction({ state }) { const translate = useTranslate(); - const driverMap = useResource( - ConnectionFormAuthenticationAction, - DBDriverResource, - state.config.driverId || null - ); + const driverMap = useResource(ConnectionFormAuthenticationAction, DBDriverResource, state.config.driverId || null); const driver = driverMap.data; const { data: authModel } = useResource( ConnectionFormAuthenticationAction, DatabaseAuthModelsResource, - getComputed(() => state.config.authModelId || state.info?.authModel || driver?.defaultAuthModel || null) + getComputed(() => state.config.authModelId || state.info?.authModel || driver?.defaultAuthModel || null), ); const authentication = useAuthenticationAction({ @@ -42,12 +35,7 @@ export const AuthenticationButton: PlaceholderComponent = } return ( - ); @@ -56,17 +44,13 @@ export const AuthenticationButton: PlaceholderComponent = export const ConnectionFormAuthenticationAction: PlaceholderComponent = observer(function ConnectionFormAuthenticationAction({ state, }) { - const driverMap = useResource( - ConnectionFormAuthenticationAction, - DBDriverResource, - state.config.driverId || null - ); + const driverMap = useResource(ConnectionFormAuthenticationAction, DBDriverResource, state.config.driverId || null); const driver = driverMap.data; const { data: authModel } = useResource( ConnectionFormAuthenticationAction, DatabaseAuthModelsResource, - getComputed(() => state.config.authModelId || state.info?.authModel || driver?.defaultAuthModel || null) + getComputed(() => state.config.authModelId || state.info?.authModel || driver?.defaultAuthModel || null), ); if (!authModel?.requiredAuth && !state.info?.requiredAuth) { diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionOriginInfoTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionOriginInfoTabService.ts index 2725f75ccd..113812c3d2 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionOriginInfoTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionOriginInfoTabService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; import { isLocalConnection } from '@cloudbeaver/core-connections'; @@ -31,9 +30,7 @@ export const OriginInfoTab = React.lazy(async () => { @injectable() export class ConnectionOriginInfoTabService extends Bootstrap { - constructor( - private readonly connectionFormService: ConnectionFormService, - ) { + constructor(private readonly connectionFormService: ConnectionFormService) { super(); } @@ -44,17 +41,15 @@ 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.info ? isLocalConnection(props.state.info) : true), }); - this.connectionFormService.configureTask - .addHandler(this.configure.bind(this)); + this.connectionFormService.configureTask.addHandler(this.configure.bind(this)); - this.connectionFormService.actionsContainer - .add(ConnectionFormAuthenticationAction, 0); + this.connectionFormService.actionsContainer.add(ConnectionFormAuthenticationAction, 0); } - load(): void { } + load(): void {} private configure(data: IConnectionFormState, contexts: IExecutionContextProvider) { const configuration = contexts.getContext(connectionFormConfigureContext); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx index a17bc86356..1bf2c2d4ad 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx @@ -5,11 +5,21 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { TextPlaceholder, Loader, ExceptionMessage, useResource, ColoredContainer, Group, ObjectPropertyInfoForm, BASE_CONTAINERS_STYLES, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { + BASE_CONTAINERS_STYLES, + ColoredContainer, + ExceptionMessage, + Group, + Loader, + ObjectPropertyInfoForm, + TextPlaceholder, + useResource, + useStyles, + useTranslate, +} from '@cloudbeaver/core-blocks'; import { createConnectionParam } from '@cloudbeaver/core-connections'; import { TabContainerPanelComponent, useTab, useTabState } from '@cloudbeaver/core-ui'; @@ -28,48 +38,46 @@ const style = css` } `; -export const OriginInfo: TabContainerPanelComponent = observer(function OriginInfo({ - tabId, - state: { - info, - resource, - }, -}) { +export const OriginInfo: TabContainerPanelComponent = observer(function OriginInfo({ tabId, state: { info, resource } }) { const tab = useTab(tabId); const translate = useTranslate(); // const userInfoService = useService(UserInfoResource); const state = useTabState>(); const styles = useStyles(style, BASE_CONTAINERS_STYLES); - const connection = useResource(OriginInfo, resource, { - key: (tab.selected && info) ? createConnectionParam(info.projectId, info.id) : null, - includes: ['includeOrigin', 'customIncludeOriginDetails'] as const, - }, { - // isActive: () => !info?.origin || userInfoService.hasOrigin(info.origin), - onData: (connection, res, prev) => { - if (!connection.origin.details) { - return; - } + const connection = useResource( + OriginInfo, + resource, + { + key: tab.selected && info ? createConnectionParam(info.projectId, info.id) : null, + includes: ['includeOrigin', 'customIncludeOriginDetails'] as const, + }, + { + // isActive: () => !info?.origin || userInfoService.hasOrigin(info.origin), + onData: (connection, res, prev) => { + if (!connection.origin.details) { + return; + } - if (prev?.origin.details) { - for (const property of prev.origin.details) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete state[property.id!]; + if (prev?.origin.details) { + for (const property of prev.origin.details) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete state[property.id!]; + } } - } - for (const property of connection.origin.details) { - state[property.id!] = property.value; - } + for (const property of connection.origin.details) { + state[property.id!] = property.value; + } + }, }, - } ); if (connection.isLoading()) { return styled(styles)( - + , ); } @@ -77,7 +85,7 @@ export const OriginInfo: TabContainerPanelComponent = obse return styled(styles)( - + , ); } @@ -95,22 +103,16 @@ export const OriginInfo: TabContainerPanelComponent = obse return styled(styles)( {translate('connections_administration_connection_no_information')} - + , ); } return styled(styles)( - + - + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfoTab.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfoTab.tsx index f2b343f69b..39b665866a 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfoTab.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfoTab.tsx @@ -5,23 +5,20 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; -import { useStyles, Translate } from '@cloudbeaver/core-blocks'; -import { TabTitle, Tab, TabContainerTabComponent } from '@cloudbeaver/core-ui'; +import { Translate, useStyles } from '@cloudbeaver/core-blocks'; +import { Tab, TabContainerTabComponent, TabTitle } from '@cloudbeaver/core-ui'; import type { IConnectionFormProps } from '../IConnectionFormProps'; -export const OriginInfoTab: TabContainerTabComponent = observer(function OriginInfoTab({ - state: { info }, - style, - ...rest -}) { +export const OriginInfoTab: TabContainerTabComponent = observer(function OriginInfoTab({ state: { info }, style, ...rest }) { return styled(useStyles(style))( - - + + + + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionSSHTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionSSHTabService.ts index c7c9c7f35d..78fb6368ba 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionSSHTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionSSHTabService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, makeObservable } from 'mobx'; import React from 'react'; @@ -32,10 +31,7 @@ export const SSHPanel = React.lazy(async () => { @injectable() export class ConnectionSSHTabService extends Bootstrap { - constructor( - private readonly connectionFormService: ConnectionFormService, - private readonly dbDriverResource: DBDriverResource - ) { + constructor(private readonly connectionFormService: ConnectionFormService, private readonly dbDriverResource: DBDriverResource) { super(); makeObservable(this, { @@ -63,28 +59,20 @@ export class ConnectionSSHTabService extends Bootstrap { }, }); - this.connectionFormService.prepareConfigTask - .addHandler(this.prepareConfig.bind(this)); + this.connectionFormService.prepareConfigTask.addHandler(this.prepareConfig.bind(this)); - this.connectionFormService.formValidationTask - .addHandler(this.validate.bind(this)); + this.connectionFormService.formValidationTask.addHandler(this.validate.bind(this)); - this.connectionFormService.formStateTask - .addHandler(this.formState.bind(this)); + this.connectionFormService.formStateTask.addHandler(this.formState.bind(this)); - this.connectionFormService.configureTask - .addHandler(this.configure.bind(this)); + this.connectionFormService.configureTask.addHandler(this.configure.bind(this)); - this.connectionFormService.fillConfigTask - .addHandler(this.fillConfig.bind(this)); + this.connectionFormService.fillConfigTask.addHandler(this.fillConfig.bind(this)); } - load(): void { } + load(): void {} - private fillConfig( - { state, updated }: IConnectionFormFillConfigData, - contexts: IExecutionContextProvider - ) { + private fillConfig({ state, updated }: IConnectionFormFillConfigData, contexts: IExecutionContextProvider) { if (!updated) { return; } @@ -121,15 +109,7 @@ export class ConnectionSSHTabService extends Bootstrap { configuration.include('includeNetworkHandlersConfig'); } - private validate( - { - state: { - config, - info, - }, - }: IConnectionFormSubmitData, - contexts: IExecutionContextProvider - ) { + private validate({ state: { config, info } }: IConnectionFormSubmitData, contexts: IExecutionContextProvider) { const validation = contexts.getContext(this.connectionFormService.connectionValidationContext); if (!config.networkHandlersConfig) { @@ -168,12 +148,7 @@ export class ConnectionSSHTabService extends Bootstrap { } } - private prepareConfig( - { - state, - }: IConnectionFormSubmitData, - contexts: IExecutionContextProvider - ) { + private prepareConfig({ state }: IConnectionFormSubmitData, contexts: IExecutionContextProvider) { const config = contexts.getContext(connectionConfigContext); const credentialsState = contexts.getContext(connectionCredentialsStateContext); const urlType = state.config.configurationType === DriverConfigurationType.Url; @@ -206,10 +181,7 @@ export class ConnectionSSHTabService extends Bootstrap { } } - private formState( - data: IConnectionFormState, - contexts: IExecutionContextProvider - ) { + private formState(data: IConnectionFormState, contexts: IExecutionContextProvider) { const config = contexts.getContext(connectionConfigContext); if (config.networkHandlersConfig !== undefined) { const stateContext = contexts.getContext(connectionFormStateContext); @@ -226,14 +198,16 @@ export class ConnectionSSHTabService extends Bootstrap { const port = Number(initial?.properties?.port); const formPort = Number(handler.properties?.port); - if (handler.enabled !== initial?.enabled - || handler.authType !== initial?.authType - || handler.savePassword !== initial?.savePassword - || handler.userName !== initial?.userName - || handler.properties?.host !== initial?.properties?.host - || port !== formPort - || handler.properties?.aliveInterval !== initial?.properties?.aliveInterval - || handler.properties?.sshConnectTimeout !== initial?.properties?.sshConnectTimeout) { + if ( + handler.enabled !== initial?.enabled || + handler.authType !== initial?.authType || + handler.savePassword !== initial?.savePassword || + handler.userName !== initial?.userName || + handler.properties?.host !== initial?.properties?.host || + port !== formPort || + handler.properties?.aliveInterval !== initial?.properties?.aliveInterval || + handler.properties?.sshConnectTimeout !== initial?.properties?.sshConnectTimeout + ) { return true; } @@ -246,8 +220,8 @@ export class ConnectionSSHTabService extends Bootstrap { } return ( - (((initial?.password === null && handler.password !== null) || initial?.password === '') && handler.password !== '') - || !!handler.password?.length + (((initial?.password === null && handler.password !== null) || initial?.password === '') && handler.password !== '') || + !!handler.password?.length ); } @@ -256,9 +230,6 @@ export class ConnectionSSHTabService extends Bootstrap { return false; } - return ( - (((initial?.key === null && handler.key !== null) || initial?.key === '') && handler.key !== '') - || !!handler.key?.length - ); + return (((initial?.key === null && handler.key !== null) || initial?.key === '') && handler.key !== '') || !!handler.key?.length; } -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSH.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSH.tsx index 634aa8dce3..12d4b20e38 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSH.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSH.tsx @@ -5,15 +5,28 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback, useState } from 'react'; import styled, { css } from 'reshadow'; import { - Group, SubmittingForm, useResource, Button, ColoredContainer, InputField, - FieldCheckbox, BASE_CONTAINERS_STYLES, Switch, GroupItem, Container, - Combobox, Expandable, EXPANDABLE_FORM_STYLES, useTranslate, useStyles, useAdministrationSettings + BASE_CONTAINERS_STYLES, + Button, + ColoredContainer, + Combobox, + Container, + Expandable, + EXPANDABLE_FORM_STYLES, + FieldCheckbox, + Group, + GroupItem, + InputField, + SubmittingForm, + Switch, + useAdministrationSettings, + useResource, + useStyles, + useTranslate, } from '@cloudbeaver/core-blocks'; import { NetworkHandlerResource, SSH_TUNNEL_ID } from '@cloudbeaver/core-connections'; import { NetworkHandlerAuthType, NetworkHandlerConfigInput } from '@cloudbeaver/core-sdk'; @@ -36,15 +49,8 @@ interface Props extends IConnectionFormProps { handlerState: NetworkHandlerConfigInput; } -export const SSH: TabContainerPanelComponent = observer(function SSH({ - state: formState, - handlerState, -}) { - const { - info, - readonly, - disabled: formDisabled, - } = formState; +export const SSH: TabContainerPanelComponent = observer(function SSH({ state: formState, handlerState }) { + const { info, readonly, disabled: formDisabled } = formState; const [loading, setLoading] = useState(false); const { credentialsSavingEnabled } = useAdministrationSettings(); @@ -90,12 +96,7 @@ export const SSH: TabContainerPanelComponent = observer(function SSH({ - + {translate('connections_network_handler_ssh_tunnel_enable')} = observer(function SSH({ state={handlerState.properties} disabled={disabled || !enabled} readOnly={readonly} - mod='surface' + mod="surface" required small > @@ -129,7 +130,7 @@ export const SSH: TabContainerPanelComponent = observer(function SSH({ state={handlerState.properties} disabled={disabled || !enabled} readOnly={readonly} - mod='surface' + mod="surface" required tiny > @@ -143,7 +144,7 @@ export const SSH: TabContainerPanelComponent = observer(function SSH({ state={handlerState} disabled={disabled || !enabled} readOnly={readonly} - mod='surface' + mod="surface" required={handlerState.savePassword} tiny > @@ -152,25 +153,18 @@ export const SSH: TabContainerPanelComponent = observer(function SSH({ {passwordLabel} - {keyAuth && ( - - )} + {keyAuth && } {credentialsSavingEnabled && ( = observer(function SSH({ )} - + {aliveIntervalLabel} {connectTimeoutLabel} @@ -216,18 +207,12 @@ export const SSH: TabContainerPanelComponent = observer(function SSH({ - - + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHKeyUploader.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHKeyUploader.tsx index c1b7524983..4ff3e99ed6 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHKeyUploader.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHKeyUploader.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { Button, GroupItem, Textarea, UploadArea, useTranslate } from '@cloudbeaver/core-blocks'; @@ -41,7 +40,7 @@ export const SSHKeyUploader = observer(function SSHKeyUploader({ state, s return ( <> - - ); -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHPanel.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHPanel.tsx index 2a98894157..28de5386a6 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHPanel.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHPanel.tsx @@ -5,16 +5,14 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { SSH_TUNNEL_ID } from '@cloudbeaver/core-connections'; +import { SSH_TUNNEL_ID } from '@cloudbeaver/core-connections'; import { TabContainerPanelComponent, useTab } from '@cloudbeaver/core-ui'; import type { IConnectionFormProps } from '../IConnectionFormProps'; import { SSH } from './SSH'; - export const SSHPanel: TabContainerPanelComponent = observer(function SSHPanel(props) { const state = props.state.config.networkHandlersConfig?.find(state => state.id === SSH_TUNNEL_ID); const tab = useTab(props.tabId); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHTab.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHTab.tsx index ecb59836f6..15c1ff5638 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHTab.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHTab.tsx @@ -5,26 +5,24 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; import { Translate, useResource, useStyles } from '@cloudbeaver/core-blocks'; import { NetworkHandlerResource, SSH_TUNNEL_ID } from '@cloudbeaver/core-connections'; -import { TabTitle, Tab, TabContainerTabComponent } from '@cloudbeaver/core-ui'; +import { Tab, TabContainerTabComponent, TabTitle } from '@cloudbeaver/core-ui'; import type { IConnectionFormProps } from '../IConnectionFormProps'; -export const SSHTab: TabContainerTabComponent = observer(function SSHTab({ - style, - ...rest -}) { +export const SSHTab: TabContainerTabComponent = observer(function SSHTab({ style, ...rest }) { const styles = useStyles(style); const handler = useResource(SSHTab, NetworkHandlerResource, SSH_TUNNEL_ID); return styled(styles)( - - + + + + , ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/authTypes.ts b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/authTypes.ts index 603f376403..e469d4a713 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/authTypes.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/authTypes.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { TLocalizationToken } from '@cloudbeaver/core-localization'; import { NetworkHandlerAuthType } from '@cloudbeaver/core-sdk'; @@ -23,4 +22,4 @@ export const authTypes: IAuthType[] = [ key: NetworkHandlerAuthType.PublicKey, label: 'Public Key', }, -]; \ No newline at end of file +]; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/connectionFormConfigureContext.ts b/webapp/packages/plugin-connections/src/ConnectionForm/connectionFormConfigureContext.ts index 82861db825..2480dbc0ec 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/connectionFormConfigureContext.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/connectionFormConfigureContext.ts @@ -5,17 +5,13 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { DatabaseConnection } from '@cloudbeaver/core-connections'; import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; import type { CachedResourceIncludeArgs, GetUserConnectionsQueryVariables } from '@cloudbeaver/core-sdk'; import type { IConnectionFormState } from './IConnectionFormProps'; -export type ConnectionFormInfoIncludes = CachedResourceIncludeArgs< -DatabaseConnection, -GetUserConnectionsQueryVariables ->; +export type ConnectionFormInfoIncludes = CachedResourceIncludeArgs; export interface IConnectionFormConfigureContext { readonly driverId: string | undefined; @@ -27,7 +23,7 @@ export interface IConnectionFormConfigureContext { export function connectionFormConfigureContext( contexts: IExecutionContextProvider, - state: IConnectionFormState + state: IConnectionFormState, ): IConnectionFormConfigureContext { return { info: state.info, diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts b/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts index 45f07b73c0..68751a78f6 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { useEffect, useState } from 'react'; import type { ConnectionInfoResource } from '@cloudbeaver/core-connections'; @@ -16,21 +15,13 @@ 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, 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); configure?.(state); state.load(); diff --git a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_CHANGE_CREDENTIALS.ts b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_CHANGE_CREDENTIALS.ts index 355dbbb7b3..2d186dcbb0 100644 --- a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_CHANGE_CREDENTIALS.ts +++ b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_CHANGE_CREDENTIALS.ts @@ -5,12 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; -export const ACTION_CONNECTION_CHANGE_CREDENTIALS = createAction( - 'connection-change-credentials', - { - label: 'app_navigationTree_context_change_credentials', - } -); +export const ACTION_CONNECTION_CHANGE_CREDENTIALS = createAction('connection-change-credentials', { + label: 'app_navigationTree_context_change_credentials', +}); diff --git a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_DISCONNECT.ts b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_DISCONNECT.ts index a63f008520..dbc0f0ca9c 100644 --- a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_DISCONNECT.ts +++ b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_DISCONNECT.ts @@ -5,12 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; -export const ACTION_CONNECTION_DISCONNECT = createAction( - 'connection-disconnect', - { - label: 'app_navigationTree_context_disconnect', - } -); +export const ACTION_CONNECTION_DISCONNECT = createAction('connection-disconnect', { + label: 'app_navigationTree_context_disconnect', +}); diff --git a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_DISCONNECT_ALL.ts b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_DISCONNECT_ALL.ts index 80ca613fa9..228b206828 100644 --- a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_DISCONNECT_ALL.ts +++ b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_DISCONNECT_ALL.ts @@ -5,12 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; -export const ACTION_CONNECTION_DISCONNECT_ALL = createAction( - 'connection-disconnect-all', - { - label: 'plugin_connections_action_disconnect_all_label', - } -); +export const ACTION_CONNECTION_DISCONNECT_ALL = createAction('connection-disconnect-all', { + label: 'plugin_connections_action_disconnect_all_label', +}); diff --git a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_EDIT.ts b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_EDIT.ts index df25ebe5d1..aab5957a4d 100644 --- a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_EDIT.ts +++ b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_EDIT.ts @@ -5,12 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; -export const ACTION_CONNECTION_EDIT = createAction( - 'connection-edit', - { - label: 'connections_public_connection_edit_menu_item_title', - } -); +export const ACTION_CONNECTION_EDIT = createAction('connection-edit', { + label: 'connections_public_connection_edit_menu_item_title', +}); diff --git a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_VIEW_ADVANCED.ts b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_VIEW_ADVANCED.ts index 8da08fd0e2..fe8ff3f5b6 100644 --- a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_VIEW_ADVANCED.ts +++ b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_VIEW_ADVANCED.ts @@ -5,13 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; -export const ACTION_CONNECTION_VIEW_ADVANCED = createAction( - 'connection-view-advanced', - { - label: 'app_navigationTree_connection_view_option_advanced', - type: 'select', - } -); +export const ACTION_CONNECTION_VIEW_ADVANCED = createAction('connection-view-advanced', { + label: 'app_navigationTree_connection_view_option_advanced', + type: 'select', +}); diff --git a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_VIEW_SIMPLE.ts b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_VIEW_SIMPLE.ts index 222c157ba1..dda3624e25 100644 --- a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_VIEW_SIMPLE.ts +++ b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_VIEW_SIMPLE.ts @@ -5,13 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; -export const ACTION_CONNECTION_VIEW_SIMPLE = createAction( - 'connection-view-simple', - { - label: 'app_navigationTree_connection_view_option_simple', - type: 'select', - } -); +export const ACTION_CONNECTION_VIEW_SIMPLE = createAction('connection-view-simple', { + label: 'app_navigationTree_connection_view_option_simple', + type: 'select', +}); diff --git a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_VIEW_SYSTEM_OBJECTS.ts b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_VIEW_SYSTEM_OBJECTS.ts index 802f1c1f7c..818fa53fad 100644 --- a/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_VIEW_SYSTEM_OBJECTS.ts +++ b/webapp/packages/plugin-connections/src/ContextMenu/Actions/ACTION_CONNECTION_VIEW_SYSTEM_OBJECTS.ts @@ -5,13 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; -export const ACTION_CONNECTION_VIEW_SYSTEM_OBJECTS = createAction( - 'connection-view-system-objects', - { - label: 'app_navigationTree_connection_view_option_showSystemObjects', - type: 'checkbox', - } -); +export const ACTION_CONNECTION_VIEW_SYSTEM_OBJECTS = createAction('connection-view-system-objects', { + label: 'app_navigationTree_connection_view_option_showSystemObjects', + type: 'checkbox', +}); diff --git a/webapp/packages/plugin-connections/src/ContextMenu/ConnectionMenuBootstrap.ts b/webapp/packages/plugin-connections/src/ContextMenu/ConnectionMenuBootstrap.ts index 1ff7ac0f82..e6b3a007f1 100644 --- a/webapp/packages/plugin-connections/src/ContextMenu/ConnectionMenuBootstrap.ts +++ b/webapp/packages/plugin-connections/src/ContextMenu/ConnectionMenuBootstrap.ts @@ -5,15 +5,34 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { EAdminPermission } from '@cloudbeaver/core-authentication'; -import { Connection, ConnectionInfoResource, ConnectionsManagerService, ConnectionsSettingsService, createConnectionParam } from '@cloudbeaver/core-connections'; +import { + Connection, + ConnectionInfoResource, + ConnectionsManagerService, + ConnectionsSettingsService, + createConnectionParam, +} from '@cloudbeaver/core-connections'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; import { DATA_CONTEXT_NAV_NODE, EObjectFeature, NavNodeManagerService } from '@cloudbeaver/core-navigation-tree'; -import { CONNECTION_NAVIGATOR_VIEW_SETTINGS, isNavigatorViewSettingsEqual, NavigatorViewSettings, PermissionsService, ServerConfigResource } from '@cloudbeaver/core-root'; +import { + CONNECTION_NAVIGATOR_VIEW_SETTINGS, + isNavigatorViewSettingsEqual, + NavigatorViewSettings, + PermissionsService, + ServerConfigResource, +} from '@cloudbeaver/core-root'; import { getCachedMapResourceLoaderState } from '@cloudbeaver/core-sdk'; -import { ActionService, ACTION_DELETE, DATA_CONTEXT_LOADABLE_STATE, DATA_CONTEXT_MENU, DATA_CONTEXT_MENU_NESTED, MenuSeparatorItem, MenuService } from '@cloudbeaver/core-view'; +import { + ACTION_DELETE, + ActionService, + DATA_CONTEXT_LOADABLE_STATE, + DATA_CONTEXT_MENU, + DATA_CONTEXT_MENU_NESTED, + MenuSeparatorItem, + MenuService, +} from '@cloudbeaver/core-view'; import { MENU_APP_ACTIONS } from '@cloudbeaver/plugin-top-app-bar'; import { ConnectionAuthService } from '../ConnectionAuthService'; @@ -55,8 +74,8 @@ export class ConnectionMenuBootstrap extends Bootstrap { this.menuService.addCreator({ isApplicable: context => { if ( - this.pluginConnectionsSettingsService.settings.getValue('hideConnectionViewForUsers') - && !this.permissionsService.has(EAdminPermission.admin) + this.pluginConnectionsSettingsService.settings.getValue('hideConnectionViewForUsers') && + !this.permissionsService.has(EAdminPermission.admin) ) { return false; } @@ -73,15 +92,9 @@ export class ConnectionMenuBootstrap extends Bootstrap { return false; } - return ( - context.has(DATA_CONTEXT_CONNECTION) - && !context.has(DATA_CONTEXT_MENU_NESTED) - ); + return context.has(DATA_CONTEXT_CONNECTION) && !context.has(DATA_CONTEXT_MENU_NESTED); }, - getItems: (context, items) => [ - ...items, - MENU_CONNECTION_VIEW, - ], + getItems: (context, items) => [...items, MENU_CONNECTION_VIEW], }); this.menuService.addCreator({ @@ -101,26 +114,17 @@ export class ConnectionMenuBootstrap extends Bootstrap { this.actionService.addHandler({ id: 'connection-view', - isActionApplicable: (context, action) => [ - ACTION_CONNECTION_VIEW_SIMPLE, - ACTION_CONNECTION_VIEW_ADVANCED, - ACTION_CONNECTION_VIEW_SYSTEM_OBJECTS, - ].includes(action), + isActionApplicable: (context, action) => + [ACTION_CONNECTION_VIEW_SIMPLE, ACTION_CONNECTION_VIEW_ADVANCED, ACTION_CONNECTION_VIEW_SYSTEM_OBJECTS].includes(action), isChecked: (context, action) => { const connection = context.get(DATA_CONTEXT_CONNECTION); switch (action) { case ACTION_CONNECTION_VIEW_SIMPLE: { - return isNavigatorViewSettingsEqual( - connection.navigatorSettings, - CONNECTION_NAVIGATOR_VIEW_SETTINGS.simple - ); + return isNavigatorViewSettingsEqual(connection.navigatorSettings, CONNECTION_NAVIGATOR_VIEW_SETTINGS.simple); } case ACTION_CONNECTION_VIEW_ADVANCED: { - return isNavigatorViewSettingsEqual( - connection.navigatorSettings, - CONNECTION_NAVIGATOR_VIEW_SETTINGS.advanced - ); + return isNavigatorViewSettingsEqual(connection.navigatorSettings, CONNECTION_NAVIGATOR_VIEW_SETTINGS.advanced); } case ACTION_CONNECTION_VIEW_SYSTEM_OBJECTS: { return connection.navigatorSettings.showSystemObjects; @@ -215,9 +219,8 @@ export class ConnectionMenuBootstrap extends Bootstrap { const connection = context.get(DATA_CONTEXT_CONNECTION); if (action === ACTION_CONNECTION_CHANGE_CREDENTIALS) { - return state.getState( - action.id, - () => getCachedMapResourceLoaderState(this.connectionInfoResource, createConnectionParam(connection), ['includeCredentialsSaved'], true) + return state.getState(action.id, () => + getCachedMapResourceLoaderState(this.connectionInfoResource, createConnectionParam(connection), ['includeCredentialsSaved'], true), ); } @@ -228,9 +231,7 @@ export class ConnectionMenuBootstrap extends Bootstrap { switch (action) { case ACTION_CONNECTION_DISCONNECT: { - await this.connectionsManagerService.closeConnectionAsync( - createConnectionParam(connection) - ); + await this.connectionsManagerService.closeConnectionAsync(createConnectionParam(connection)); break; } case ACTION_CONNECTION_DISCONNECT_ALL: { @@ -239,9 +240,7 @@ export class ConnectionMenuBootstrap extends Bootstrap { } case ACTION_DELETE: { try { - await this.connectionsManagerService.deleteConnection( - createConnectionParam(connection) - ); + await this.connectionsManagerService.deleteConnection(createConnectionParam(connection)); } catch (exception: any) { this.notificationService.logException(exception, 'Failed to delete connection'); } @@ -252,10 +251,7 @@ export class ConnectionMenuBootstrap extends Bootstrap { break; } case ACTION_CONNECTION_CHANGE_CREDENTIALS: { - await this.connectionAuthService.auth( - { connectionId: connection.id, projectId: connection.projectId }, - true - ); + await this.connectionAuthService.auth({ connectionId: connection.id, projectId: connection.projectId }, true); break; } } @@ -263,14 +259,11 @@ export class ConnectionMenuBootstrap extends Bootstrap { }); } - load(): void { } + load(): void {} private async changeConnectionView(connection: Connection, settings: NavigatorViewSettings) { try { - connection = await this.connectionInfoResource.changeConnectionView( - createConnectionParam(connection), - settings - ); + connection = await this.connectionInfoResource.changeConnectionView(createConnectionParam(connection), settings); if (connection.nodePath) { await this.navNodeManagerService.refreshTree(connection.nodePath); @@ -283,15 +276,13 @@ export class ConnectionMenuBootstrap extends Bootstrap { private addConnectionsMenuToTopAppBar() { this.menuService.addCreator({ menus: [MENU_APP_ACTIONS], - getItems: (context, items) => [ - ...items, - MENU_CONNECTIONS, - ], + getItems: (context, items) => [...items, MENU_CONNECTIONS], }); this.menuService.setHandler({ id: 'connections-menu-base', isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === MENU_CONNECTIONS, - isHidden: () => this.connectionsManagerService.createConnectionProjects.length === 0 || this.connectionsSettingsService.settings.getValue('disabled'), + isHidden: () => + this.connectionsManagerService.createConnectionProjects.length === 0 || this.connectionsSettingsService.settings.getValue('disabled'), isLabelVisible: () => false, }); } diff --git a/webapp/packages/plugin-connections/src/ContextMenu/DATA_CONTEXT_CONNECTION.ts b/webapp/packages/plugin-connections/src/ContextMenu/DATA_CONTEXT_CONNECTION.ts index 0e02cd81db..b81ecc19bf 100644 --- a/webapp/packages/plugin-connections/src/ContextMenu/DATA_CONTEXT_CONNECTION.ts +++ b/webapp/packages/plugin-connections/src/ContextMenu/DATA_CONTEXT_CONNECTION.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { Connection } from '@cloudbeaver/core-connections'; import { createDataContext } from '@cloudbeaver/core-view'; diff --git a/webapp/packages/plugin-connections/src/ContextMenu/MENU_CONNECTIONS.ts b/webapp/packages/plugin-connections/src/ContextMenu/MENU_CONNECTIONS.ts index 3a516a39a4..c88d42439e 100644 --- a/webapp/packages/plugin-connections/src/ContextMenu/MENU_CONNECTIONS.ts +++ b/webapp/packages/plugin-connections/src/ContextMenu/MENU_CONNECTIONS.ts @@ -5,12 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; export const MENU_CONNECTIONS = createMenu( 'connections', 'plugin_connections_menu_connections_label', '/icons/plugin_connections_menu_m.svg', - 'plugin_connections_menu_connections_label' + 'plugin_connections_menu_connections_label', ); diff --git a/webapp/packages/plugin-connections/src/ContextMenu/MENU_CONNECTION_VIEW.ts b/webapp/packages/plugin-connections/src/ContextMenu/MENU_CONNECTION_VIEW.ts index 2cc0589684..45f785c3f0 100644 --- a/webapp/packages/plugin-connections/src/ContextMenu/MENU_CONNECTION_VIEW.ts +++ b/webapp/packages/plugin-connections/src/ContextMenu/MENU_CONNECTION_VIEW.ts @@ -5,10 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; -export const MENU_CONNECTION_VIEW = createMenu( - 'connection-view', - 'app_navigationTree_connection_view' -); +export const MENU_CONNECTION_VIEW = createMenu('connection-view', 'app_navigationTree_connection_view'); diff --git a/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DBAuthDialogController.ts b/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DBAuthDialogController.ts index 58fa7f3ce6..563a475ba7 100644 --- a/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DBAuthDialogController.ts +++ b/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DBAuthDialogController.ts @@ -5,11 +5,16 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ +import { makeObservable, observable } from 'mobx'; -import { observable, makeObservable } from 'mobx'; - -import { ConnectionInfoResource, ConnectionInitConfig, DBDriverResource, IConnectionInfoParams, USER_NAME_PROPERTY_ID } from '@cloudbeaver/core-connections'; -import { injectable, IInitializableController, IDestructibleController } from '@cloudbeaver/core-di'; +import { + ConnectionInfoResource, + ConnectionInitConfig, + DBDriverResource, + IConnectionInfoParams, + USER_NAME_PROPERTY_ID, +} from '@cloudbeaver/core-connections'; +import { IDestructibleController, IInitializableController, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; import { ErrorDetailsDialog } from '@cloudbeaver/core-notifications'; @@ -38,7 +43,7 @@ export class DBAuthDialogController implements IInitializableController, IDestru private readonly notificationService: NotificationService, private readonly connectionInfoResource: ConnectionInfoResource, private readonly commonDialogService: CommonDialogService, - private readonly dbDriverResource: DBDriverResource + private readonly dbDriverResource: DBDriverResource, ) { makeObservable(this, { isAuthenticating: observable.ref, @@ -108,7 +113,9 @@ export class DBAuthDialogController implements IInitializableController, IDestru private async loadAuthModel() { try { const connection = await this.connectionInfoResource.load(this.connectionKey, [ - 'includeAuthProperties', 'includeNetworkHandlersConfig', 'includeAuthNeeded', + 'includeAuthProperties', + 'includeNetworkHandlersConfig', + 'includeAuthNeeded', ]); if (connection.authNeeded) { @@ -133,7 +140,7 @@ export class DBAuthDialogController implements IInitializableController, IDestru } } } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t load auth model'); + this.notificationService.logException(exception, "Can't load auth model"); } } @@ -141,7 +148,7 @@ export class DBAuthDialogController implements IInitializableController, IDestru try { await this.dbDriverResource.load(CachedMapAllKey); } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t load database drivers', '', true); + this.notificationService.logException(exception, "Can't load database drivers", '', true); } } } diff --git a/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DBAuthDialogFooter.tsx b/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DBAuthDialogFooter.tsx index 753df144e1..f37aec66cf 100644 --- a/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DBAuthDialogFooter.tsx +++ b/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DBAuthDialogFooter.tsx @@ -5,13 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; import { Button, useTranslate } from '@cloudbeaver/core-blocks'; - const styles = css` footer-container { display: flex; @@ -45,14 +43,9 @@ export const DBAuthDialogFooter = observer>(funct return styled(styles)( {children} - - + , ); }); diff --git a/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DatabaseAuthDialog.tsx b/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DatabaseAuthDialog.tsx index d78d579530..acfa945348 100644 --- a/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DatabaseAuthDialog.tsx +++ b/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DatabaseAuthDialog.tsx @@ -5,18 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { - SubmittingForm, - useFocus, - ErrorMessage, - useStyles, - Loader, - useAdministrationSettings, -} from '@cloudbeaver/core-blocks'; +import { ErrorMessage, Loader, SubmittingForm, useAdministrationSettings, useFocus, useStyles } from '@cloudbeaver/core-blocks'; import { IConnectionInfoParams, useConnectionInfo, useDBDriver } from '@cloudbeaver/core-connections'; import { useController } from '@cloudbeaver/core-di'; import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs'; @@ -26,20 +18,20 @@ import { DBAuthDialogController } from './DBAuthDialogController'; import { DBAuthDialogFooter } from './DBAuthDialogFooter'; const styles = css` - SubmittingForm { - overflow: auto; - margin: auto; - flex: 1; - display: flex; - flex-direction: column; - } - ConnectionAuthenticationFormLoader { - align-content: center; - } - ErrorMessage { - composes: theme-background-secondary theme-text-on-secondary from global; - flex: 1; - } + SubmittingForm { + overflow: auto; + margin: auto; + flex: 1; + display: flex; + flex-direction: column; + } + ConnectionAuthenticationFormLoader { + align-content: center; + } + ErrorMessage { + composes: theme-background-secondary theme-text-on-secondary from global; + flex: 1; + } `; interface Payload { @@ -48,12 +40,7 @@ interface Payload { resetCredentials?: boolean; } -export const DatabaseAuthDialog: DialogComponent = observer(function DatabaseAuthDialog({ - payload, - options, - rejectDialog, - resolveDialog, -}) { +export const DatabaseAuthDialog: DialogComponent = observer(function DatabaseAuthDialog({ payload, options, rejectDialog, resolveDialog }) { const connection = useConnectionInfo(payload.connection); const controller = useController(DBAuthDialogController, payload.connection, payload.networkHandlers, resolveDialog); @@ -68,7 +55,7 @@ export const DatabaseAuthDialog: DialogComponent = observer(function Da } return styled(useStyles(styles))( - + = observer(function Da /> - {!connection.isLoaded() || connection.isLoading() || !controller.configured - ? - : ( - - )} + {!connection.isLoaded() || connection.isLoading() || !controller.configured ? ( + + ) : ( + + )} - + {controller.error.responseMessage && ( - + )} - + , ); }); diff --git a/webapp/packages/plugin-connections/src/LocaleService.ts b/webapp/packages/plugin-connections/src/LocaleService.ts index 144237a086..e3649a06b4 100644 --- a/webapp/packages/plugin-connections/src/LocaleService.ts +++ b/webapp/packages/plugin-connections/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-connections/src/NavNodes/ConnectionFoldersBootstrap.ts b/webapp/packages/plugin-connections/src/NavNodes/ConnectionFoldersBootstrap.ts index 11f453b543..9e6bd72176 100644 --- a/webapp/packages/plugin-connections/src/NavNodes/ConnectionFoldersBootstrap.ts +++ b/webapp/packages/plugin-connections/src/NavNodes/ConnectionFoldersBootstrap.ts @@ -5,23 +5,46 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - - import { untracked } from 'mobx'; import { UserInfoResource } from '@cloudbeaver/core-authentication'; -import { ConnectionFolderProjectKey, ConnectionFolderResource, ConnectionInfoResource, ConnectionsManagerService, CONNECTION_FOLDER_NAME_VALIDATION, createConnectionFolderParam, createConnectionParam, getConnectionFolderIdFromNodeId, IConnectionFolderParam, IConnectionInfoParams, getConnectionFolderId } from '@cloudbeaver/core-connections'; +import { + CONNECTION_FOLDER_NAME_VALIDATION, + ConnectionFolderProjectKey, + ConnectionFolderResource, + ConnectionInfoResource, + ConnectionsManagerService, + createConnectionFolderParam, + createConnectionParam, + getConnectionFolderId, + getConnectionFolderIdFromNodeId, + IConnectionFolderParam, + IConnectionInfoParams, +} from '@cloudbeaver/core-connections'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService, ConfirmationDialogDelete, DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; import { ExecutorInterrupter, IExecutionContextProvider } from '@cloudbeaver/core-executor'; import { LocalizationService } from '@cloudbeaver/core-localization'; -import { ENodeMoveType, getNodesFromContext, INodeMoveData, NavNode, NavNodeInfoResource, NavNodeManagerService, navNodeMoveContext, NavTreeResource, NAV_NODE_TYPE_FOLDER, nodeDeleteContext, ProjectsNavNodeService, ROOT_NODE_PATH } from '@cloudbeaver/core-navigation-tree'; +import { + ENodeMoveType, + getNodesFromContext, + INodeMoveData, + NAV_NODE_TYPE_FOLDER, + NavNode, + NavNodeInfoResource, + NavNodeManagerService, + navNodeMoveContext, + NavTreeResource, + nodeDeleteContext, + ProjectsNavNodeService, + ROOT_NODE_PATH, +} from '@cloudbeaver/core-navigation-tree'; import { getProjectNodeId, NAV_NODE_TYPE_PROJECT, ProjectInfoResource } from '@cloudbeaver/core-projects'; import { CachedMapAllKey, ResourceKeyAlias, resourceKeyList, ResourceKeySimple, ResourceKeyUtils } from '@cloudbeaver/core-sdk'; import { createPath } from '@cloudbeaver/core-utils'; -import { ActionService, ACTION_NEW_FOLDER, DATA_CONTEXT_MENU, IAction, IDataContextProvider, MenuService } from '@cloudbeaver/core-view'; -import { DATA_CONTEXT_ELEMENTS_TREE, MENU_ELEMENTS_TREE_TOOLS, type IElementsTree } from '@cloudbeaver/plugin-navigation-tree'; +import { ACTION_NEW_FOLDER, ActionService, DATA_CONTEXT_MENU, IAction, IDataContextProvider, MenuService } from '@cloudbeaver/core-view'; +import { DATA_CONTEXT_ELEMENTS_TREE, type IElementsTree, MENU_ELEMENTS_TREE_TOOLS } from '@cloudbeaver/plugin-navigation-tree'; import { FolderDialog } from '@cloudbeaver/plugin-projects'; import { NAV_NODE_TYPE_CONNECTION } from './NAV_NODE_TYPE_CONNECTION'; @@ -50,7 +73,7 @@ export class ConnectionFoldersBootstrap extends Bootstrap { private readonly notificationService: NotificationService, private readonly navNodeInfoResource: NavNodeInfoResource, private readonly projectInfoResource: ProjectInfoResource, - private readonly projectsNavNodeService: ProjectsNavNodeService + private readonly projectsNavNodeService: ProjectsNavNodeService, ) { super(); } @@ -72,11 +95,7 @@ export class ConnectionFoldersBootstrap extends Bootstrap { } await this.connectionFolderResource.load(CachedMapAllKey); - const nodes = ResourceKeyUtils - .filter( - data, - nodeId => this.connectionFolderResource.fromNodeId(nodeId) !== undefined - ) + const nodes = ResourceKeyUtils.filter(data, nodeId => this.connectionFolderResource.fromNodeId(nodeId) !== undefined) .map(nodeId => this.navNodeInfoResource.get(nodeId)) .filter(Boolean as any) .map(node => node.name) @@ -104,12 +123,7 @@ export class ConnectionFoldersBootstrap extends Bootstrap { isActionApplicable: (context, action) => { const tree = context.tryGet(DATA_CONTEXT_ELEMENTS_TREE); - if ( - action !== ACTION_NEW_FOLDER - || !tree - || !this.userInfoResource.data - || tree.baseRoot !== ROOT_NODE_PATH - ) { + if (action !== ACTION_NEW_FOLDER || !tree || !this.userInfoResource.data || tree.baseRoot !== ROOT_NODE_PATH) { return false; } @@ -139,26 +153,16 @@ export class ConnectionFoldersBootstrap extends Bootstrap { isApplicable: context => context.get(DATA_CONTEXT_MENU) === MENU_ELEMENTS_TREE_TOOLS, getItems: (context, items) => { if (!items.includes(ACTION_NEW_FOLDER)) { - return [ - ...items, - ACTION_NEW_FOLDER, - ]; + return [...items, ACTION_NEW_FOLDER]; } return items; }, }); } - load(): void | Promise { } + load(): void | Promise {} - private async moveConnectionToFolder( - { - type, - targetNode, - moveContexts, - }: INodeMoveData, - contexts: IExecutionContextProvider - ) { + private async moveConnectionToFolder({ type, targetNode, moveContexts }: INodeMoveData, contexts: IExecutionContextProvider) { if (![NAV_NODE_TYPE_PROJECT, NAV_NODE_TYPE_FOLDER].includes(targetNode.nodeType!)) { return; } @@ -173,10 +177,10 @@ export class ConnectionFoldersBootstrap extends Bootstrap { const supported = nodes.every(node => { if ( - ![NAV_NODE_TYPE_CONNECTION, NAV_NODE_TYPE_FOLDER, NAV_NODE_TYPE_PROJECT].includes(node.nodeType!) - || targetProject !== this.projectsNavNodeService.getProject(node.id) - || children.includes(node.id) - || targetNode.id === node.id + ![NAV_NODE_TYPE_CONNECTION, NAV_NODE_TYPE_FOLDER, NAV_NODE_TYPE_PROJECT].includes(node.nodeType!) || + targetProject !== this.projectsNavNodeService.getProject(node.id) || + children.includes(node.id) || + targetNode.id === node.id ) { return false; } @@ -194,26 +198,19 @@ export class ConnectionFoldersBootstrap extends Bootstrap { } } else { const childrenNode = this.navNodeInfoResource.get(resourceKeyList(children)); - const folderDuplicates = nodes.filter(node => ( - node.nodeType === NAV_NODE_TYPE_FOLDER - && ( - childrenNode.some(child => child?.nodeType === NAV_NODE_TYPE_FOLDER && child.name === node.name) - || nodes.some(child => ( - child.nodeType === NAV_NODE_TYPE_FOLDER - && child.name === node.name - && child.id !== node.id - )) - ) - )); + const folderDuplicates = nodes.filter( + node => + node.nodeType === NAV_NODE_TYPE_FOLDER && + (childrenNode.some(child => child?.nodeType === NAV_NODE_TYPE_FOLDER && child.name === node.name) || + nodes.some(child => child.nodeType === NAV_NODE_TYPE_FOLDER && child.name === node.name && child.id !== node.id)), + ); if (folderDuplicates.length > 0) { this.notificationService.logError({ title: 'connections_public_connection_folder_move_failed', - message: this.localizationService.translate( - 'connections_public_connection_folder_move_duplication', - undefined, - { name: folderDuplicates.map(node => `"${node.name}"`).join(', ') } - ), + message: this.localizationService.translate('connections_public_connection_folder_move_duplication', undefined, { + name: folderDuplicates.map(node => `"${node.name}"`).join(', '), + }), }); return; } @@ -251,7 +248,7 @@ export class ConnectionFoldersBootstrap extends Bootstrap { const targetNode = this.getTargetNode(tree); if (!targetNode) { - this.notificationService.logError({ title:'Can\'t create folder', message: 'core_projects_no_default_project' }); + this.notificationService.logError({ title: "Can't create folder", message: 'core_projects_no_default_project' }); return; } @@ -277,24 +274,23 @@ export class ConnectionFoldersBootstrap extends Bootstrap { return false; } - let parentKey: ResourceKeyAlias | IConnectionFolderParam = ConnectionFolderProjectKey(projectId); + let parentKey: + | ResourceKeyAlias< + any, + { + projectId: string; + } + > + | IConnectionFolderParam = ConnectionFolderProjectKey(projectId); if (folder) { - parentKey = createConnectionFolderParam( - projectId, - folder - ); + parentKey = createConnectionFolderParam(projectId, folder); } try { await this.connectionFolderResource.load(parentKey); - return !this.connectionFolderResource.has(createConnectionFolderParam( - projectId, - createPath(folder, trimmed) - )); + return !this.connectionFolderResource.has(createConnectionFolderParam(projectId, createPath(folder, trimmed))); } catch (exception: any) { setMessage('connections_connection_folder_validation'); return false; @@ -308,10 +304,10 @@ export class ConnectionFoldersBootstrap extends Bootstrap { this.navTreeResource.markOutdated( result.folder ? getConnectionFolderId(createConnectionFolderParam(result.projectId, result.folder)) - : getProjectNodeId(result.projectId) + : getProjectNodeId(result.projectId), ); } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t create folder'); + this.notificationService.logException(exception, "Can't create folder"); } } @@ -321,10 +317,7 @@ export class ConnectionFoldersBootstrap extends Bootstrap { } private async syncWithNavTree(key: ResourceKeySimple) { - const isFolder = ResourceKeyUtils.some( - key, - nodeId => this.connectionFolderResource.fromNodeId(nodeId) !== undefined - ); + const isFolder = ResourceKeyUtils.some(key, nodeId => this.connectionFolderResource.fromNodeId(nodeId) !== undefined); if (isFolder) { this.connectionFolderResource.markOutdated(); @@ -359,7 +352,6 @@ export class ConnectionFoldersBootstrap extends Bootstrap { return; } - const project = this.projectsNavNodeService.getByNodeId(projectNode.id); if (!project?.canEditDataSources) { @@ -378,4 +370,4 @@ export class ConnectionFoldersBootstrap extends Bootstrap { selectProject: false, }; } -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-connections/src/NavNodes/NAV_NODE_TYPE_CONNECTION.ts b/webapp/packages/plugin-connections/src/NavNodes/NAV_NODE_TYPE_CONNECTION.ts index f1be784c1d..88a7ac870e 100644 --- a/webapp/packages/plugin-connections/src/NavNodes/NAV_NODE_TYPE_CONNECTION.ts +++ b/webapp/packages/plugin-connections/src/NavNodes/NAV_NODE_TYPE_CONNECTION.ts @@ -6,4 +6,4 @@ * you may not use this file except in compliance with the License. */ -export const NAV_NODE_TYPE_CONNECTION = 'Connection'; \ No newline at end of file +export const NAV_NODE_TYPE_CONNECTION = 'Connection'; diff --git a/webapp/packages/plugin-connections/src/PluginBootstrap.ts b/webapp/packages/plugin-connections/src/PluginBootstrap.ts index 8a9be6b993..2a6930a17c 100644 --- a/webapp/packages/plugin-connections/src/PluginBootstrap.ts +++ b/webapp/packages/plugin-connections/src/PluginBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; @injectable() @@ -14,7 +13,7 @@ export class PluginBootstrap extends Bootstrap { super(); } - register(): void { } + register(): void {} - load(): void { } + load(): void {} } diff --git a/webapp/packages/plugin-connections/src/PluginConnectionsSettingsService.ts b/webapp/packages/plugin-connections/src/PluginConnectionsSettingsService.ts index f720cccdf8..e3abbafde3 100644 --- a/webapp/packages/plugin-connections/src/PluginConnectionsSettingsService.ts +++ b/webapp/packages/plugin-connections/src/PluginConnectionsSettingsService.ts @@ -5,7 +5,6 @@ * 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 { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin'; diff --git a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionForm.tsx b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionForm.tsx index e88675b549..83a1a4f1a1 100644 --- a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionForm.tsx +++ b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionForm.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback } from 'react'; import styled, { css } from 'reshadow'; @@ -30,14 +29,16 @@ export const PublicConnectionForm: React.FC = observer(function PublicConnection return styled(styles)( - {() => service.formState && ( - - )} - + {() => + service.formState && ( + + ) + } + , ); }); diff --git a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts index 7cb588a2ad..bfb51e459e 100644 --- a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts +++ b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, makeObservable, observable } from 'mobx'; import { UserInfoResource } from '@cloudbeaver/core-authentication'; @@ -41,24 +40,26 @@ export class PublicConnectionFormService { private readonly userInfoResource: UserInfoResource, private readonly authenticationService: AuthenticationService, private readonly projectsService: ProjectsService, - private readonly projectInfoResource: ProjectInfoResource + private readonly projectInfoResource: ProjectInfoResource, ) { this.formState = null; this.optionsPanelService.closeTask.addHandler(this.closeHandler); this.connectionInfoResource.onDataUpdate.addPostHandler(this.closeRemoved); this.connectionInfoResource.onItemDelete.addPostHandler(this.closeDeleted); - this.authenticationService.onLogin.addHandler(executorHandlerFilter( - () => !!this.formState && this.optionsPanelService.isOpen(formGetter), - async (event, context) => { - if (event === 'before' && this.userInfoResource.data === null) { - const confirmed = await this.showUnsavedChangesDialog(); - if (!confirmed) { - ExecutorInterrupter.interrupt(context); + this.authenticationService.onLogin.addHandler( + executorHandlerFilter( + () => !!this.formState && this.optionsPanelService.isOpen(formGetter), + async (event, context) => { + if (event === 'before' && this.userInfoResource.data === null) { + const confirmed = await this.showUnsavedChangesDialog(); + if (!confirmed) { + ExecutorInterrupter.interrupt(context); + } } - } - } - )); + }, + ), + ); makeObservable(this, { formState: observable.shallow, @@ -78,17 +79,14 @@ export class PublicConnectionFormService { this.projectsService, this.projectInfoResource, this.connectionFormService, - this.connectionInfoResource + this.connectionInfoResource, ); this.formState.closeTask.addHandler(this.close.bind(this, true)); } this.formState - .setOptions( - config.connectionId ? 'edit' : 'create', - 'public' - ) + .setOptions(config.connectionId ? 'edit' : 'create', 'public') .setConfig(projectId, config) .setAvailableDrivers(availableDrivers || []); @@ -124,14 +122,10 @@ export class PublicConnectionFormService { } async save(): Promise { - const key = ( - (this.formState && this.formState.config.connectionId && this.formState.projectId !== null) - ? createConnectionParam( - this.formState.projectId, - this.formState.config.connectionId - ) - : null - ); + const key = + this.formState && this.formState.config.connectionId && this.formState.projectId !== null + ? createConnectionParam(this.formState.projectId, this.formState.config.connectionId) + : null; await this.close(true); @@ -145,10 +139,7 @@ export class PublicConnectionFormService { return; } - if (!this.connectionInfoResource.has(createConnectionParam( - this.formState.projectId, - this.formState.config.connectionId - ))) { + if (!this.connectionInfoResource.has(createConnectionParam(this.formState.projectId, this.formState.config.connectionId))) { this.close(true); } }; @@ -158,10 +149,7 @@ export class PublicConnectionFormService { return; } - if (this.connectionInfoResource.isIntersect(data, createConnectionParam( - this.formState.projectId, - this.formState.config.connectionId - ))) { + if (this.connectionInfoResource.isIntersect(data, createConnectionParam(this.formState.projectId, this.formState.config.connectionId))) { this.close(true); } }; @@ -176,16 +164,11 @@ export class PublicConnectionFormService { private async showUnsavedChangesDialog(): Promise { if ( - !this.formState - || !this.optionsPanelService.isOpen(formGetter) - || ( - this.formState.config.connectionId - && this.formState.projectId !== null - && !this.connectionInfoResource.has(createConnectionParam( - this.formState.projectId, - this.formState.config.connectionId - )) - ) + !this.formState || + !this.optionsPanelService.isOpen(formGetter) || + (this.formState.config.connectionId && + this.formState.projectId !== null && + !this.connectionInfoResource.has(createConnectionParam(this.formState.projectId, this.formState.config.connectionId))) ) { return true; } diff --git a/webapp/packages/plugin-connections/src/index.ts b/webapp/packages/plugin-connections/src/index.ts index 4e7896a98b..a0c038fc6c 100644 --- a/webapp/packages/plugin-connections/src/index.ts +++ b/webapp/packages/plugin-connections/src/index.ts @@ -1,4 +1,5 @@ import { connectionPlugin } from './manifest'; + export * from './ConnectionAuthentication/IConnectionAuthenticationConfig'; export * from './ConnectionAuthentication/ConnectionAuthenticationFormLoader'; export * from './ConnectionForm/Options/ConnectionOptionsTabService'; diff --git a/webapp/packages/plugin-connections/src/locales/en.ts b/webapp/packages/plugin-connections/src/locales/en.ts index 1db4772eed..63315370df 100644 --- a/webapp/packages/plugin-connections/src/locales/en.ts +++ b/webapp/packages/plugin-connections/src/locales/en.ts @@ -1,7 +1,7 @@ export default [ ['connections_public_connection_edit_menu_item_title', 'Edit Connection'], ['connections_public_connection_edit_cancel_title', 'Cancel confirmation'], - ['connections_public_connection_edit_cancel_message', 'You\'re going to cancel connection changes. Unsaved changes will be lost. Are you sure?'], + ['connections_public_connection_edit_cancel_message', "You're going to cancel connection changes. Unsaved changes will be lost. Are you sure?"], ['connections_public_connection_edit_reconnect_title', 'Connection updated'], ['connections_public_connection_edit_reconnect_message', 'Connection has been updated. Do you want to reconnect?'], ['connections_public_connection_edit_reconnect_failed', 'Failed to reconnect'], @@ -10,8 +10,8 @@ export default [ ['connections_public_connection_cloud_auth_required', 'You need to sign in with "{arg:providerLabel}" credentials to work with connection.'], ['plugin_connections_connection_form_project_invalid', 'You have no access to create connections in selected project'], ['plugin_connections_connection_form_host_configuration_invalid', 'Host configuration is not supported'], - ['plugin_connections_connection_form_name_invalid', 'Field \'Connection name\' can\'t be empty'], - ['plugin_connections_connection_form_host_invalid', 'Field \'Host\' can\'t be empty'], + ['plugin_connections_connection_form_name_invalid', "Field 'Connection name' can't be empty"], + ['plugin_connections_connection_form_host_invalid', "Field 'Host' can't be empty"], ['connections_public_connection_folder_delete_confirmation', 'You\'re going to delete "{arg:name}". Connections won\'t be deleted. Are you sure?'], ['plugin_connections_menu_connections_label', 'Connection'], ['plugin_connections_action_disconnect_all_label', 'Disconnect All'], diff --git a/webapp/packages/plugin-connections/src/locales/it.ts b/webapp/packages/plugin-connections/src/locales/it.ts index 71cc88536d..02ff569356 100644 --- a/webapp/packages/plugin-connections/src/locales/it.ts +++ b/webapp/packages/plugin-connections/src/locales/it.ts @@ -1,7 +1,10 @@ export default [ ['connections_public_connection_edit_menu_item_title', 'Modifica Connessione'], - ['connections_public_connection_edit_cancel_title', 'Conferma l\'annullamento'], - ['connections_public_connection_edit_cancel_message', 'Stai per annullare le modifiche alla connessione. Modifiche non salvate saranno perse. Sei sicuro?'], + ['connections_public_connection_edit_cancel_title', "Conferma l'annullamento"], + [ + 'connections_public_connection_edit_cancel_message', + 'Stai per annullare le modifiche alla connessione. Modifiche non salvate saranno perse. Sei sicuro?', + ], ['connections_public_connection_edit_reconnect_title', 'Connection updated'], ['connections_public_connection_edit_reconnect_message', 'Connection has been updated. Do you want to reconnect?'], ['connections_public_connection_edit_reconnect_failed', 'Failed to reconnect'], @@ -9,8 +12,8 @@ export default [ ['connections_public_connection_folder_move_duplication', 'Target folder or selected folders contains folder with the same name ({arg:name})'], ['plugin_connections_connection_form_project_invalid', 'You have no access to create connections in selected project'], ['plugin_connections_connection_form_host_configuration_invalid', 'Host configuration is not supported'], - ['plugin_connections_connection_form_name_invalid', 'Field \'Connection name\' can\'t be empty'], - ['plugin_connections_connection_form_host_invalid', 'Field \'Host\' can\'t be empty'], + ['plugin_connections_connection_form_name_invalid', "Field 'Connection name' can't be empty"], + ['plugin_connections_connection_form_host_invalid', "Field 'Host' can't be empty"], ['connections_public_connection_folder_delete_confirmation', 'You\'re going to delete "{arg:name}". Connections won\'t be deleted. Are you sure?'], ['plugin_connections_menu_connections_label', 'Connessione'], ['plugin_connections_action_disconnect_all_label', 'Scollegati da tutto'], diff --git a/webapp/packages/plugin-connections/src/locales/ru.ts b/webapp/packages/plugin-connections/src/locales/ru.ts index 0db9b6c372..24a65239b4 100644 --- a/webapp/packages/plugin-connections/src/locales/ru.ts +++ b/webapp/packages/plugin-connections/src/locales/ru.ts @@ -9,8 +9,8 @@ export default [ ['connections_public_connection_folder_move_duplication', 'Выбранные папки или папка назначения содержит папки с таким же названием ({arg:name})'], ['plugin_connections_connection_form_project_invalid', 'У вас нет разрешения создавать коннекшены в выбранном проекте'], ['plugin_connections_connection_form_host_configuration_invalid', 'Конфигурация хоста не поддерживается'], - ['plugin_connections_connection_form_name_invalid', 'Поле \'Название подключения\' не может быть пустым'], - ['plugin_connections_connection_form_host_invalid', 'Поле \'Хост\' не может быть пустым'], + ['plugin_connections_connection_form_name_invalid', "Поле 'Название подключения' не может быть пустым"], + ['plugin_connections_connection_form_host_invalid', "Поле 'Хост' не может быть пустым"], ['connections_public_connection_folder_delete_confirmation', 'Вы удаляете "{arg:name}". Подключения не будут удалены. Вы уверены?'], ['plugin_connections_menu_connections_label', 'Подключение'], ['plugin_connections_action_disconnect_all_label', 'Отключить все'], diff --git a/webapp/packages/plugin-connections/src/locales/zh.ts b/webapp/packages/plugin-connections/src/locales/zh.ts index 9dfe224c21..747bde2e20 100644 --- a/webapp/packages/plugin-connections/src/locales/zh.ts +++ b/webapp/packages/plugin-connections/src/locales/zh.ts @@ -9,8 +9,8 @@ export default [ ['connections_public_connection_folder_move_duplication', 'Target folder or selected folders contains folder with the same name ({arg:name})'], ['plugin_connections_connection_form_project_invalid', 'You have no access to create connections in selected project'], ['plugin_connections_connection_form_host_configuration_invalid', 'Host configuration is not supported'], - ['plugin_connections_connection_form_name_invalid', 'Field \'Connection name\' can\'t be empty'], - ['plugin_connections_connection_form_host_invalid', 'Field \'Host\' can\'t be empty'], + ['plugin_connections_connection_form_name_invalid', "Field 'Connection name' can't be empty"], + ['plugin_connections_connection_form_host_invalid', "Field 'Host' can't be empty"], ['connections_public_connection_folder_delete_confirmation', 'You\'re going to delete "{arg:name}". Connections won\'t be deleted. Are you sure?'], ['plugin_connections_menu_connections_label', '连接'], ['plugin_connections_action_disconnect_all_label', '断开所有连接'], diff --git a/webapp/packages/plugin-connections/src/manifest.ts b/webapp/packages/plugin-connections/src/manifest.ts index 0ba8098438..0781bd406f 100644 --- a/webapp/packages/plugin-connections/src/manifest.ts +++ b/webapp/packages/plugin-connections/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { ConnectionAuthService } from './ConnectionAuthService'; diff --git a/webapp/packages/plugin-data-export/src/Bootstrap.ts b/webapp/packages/plugin-data-export/src/Bootstrap.ts index ec170ec03f..182ca1ae8c 100644 --- a/webapp/packages/plugin-data-export/src/Bootstrap.ts +++ b/webapp/packages/plugin-data-export/src/Bootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap as B, injectable } from '@cloudbeaver/core-di'; import { DataExportMenuService } from './DataExportMenuService'; diff --git a/webapp/packages/plugin-data-export/src/DataExportMenuService.ts b/webapp/packages/plugin-data-export/src/DataExportMenuService.ts index d21e29d10a..46bd3dd34e 100644 --- a/webapp/packages/plugin-data-export/src/DataExportMenuService.ts +++ b/webapp/packages/plugin-data-export/src/DataExportMenuService.ts @@ -5,14 +5,13 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createConnectionParam } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; -import { IMenuContext, CommonDialogService } from '@cloudbeaver/core-dialogs'; +import { CommonDialogService, IMenuContext } from '@cloudbeaver/core-dialogs'; import { DATA_CONTEXT_NAV_NODE, EObjectFeature } from '@cloudbeaver/core-navigation-tree'; -import { ActionService, ACTION_EXPORT, DATA_CONTEXT_MENU_NESTED, MenuService } from '@cloudbeaver/core-view'; +import { ACTION_EXPORT, ActionService, DATA_CONTEXT_MENU_NESTED, MenuService } from '@cloudbeaver/core-view'; import { DATA_CONTEXT_CONNECTION } from '@cloudbeaver/plugin-connections'; -import { TableFooterMenuService, ITableFooterMenuContext, IDatabaseDataSource, IDataContainerOptions } from '@cloudbeaver/plugin-data-viewer'; +import { IDatabaseDataSource, IDataContainerOptions, ITableFooterMenuContext, TableFooterMenuService } from '@cloudbeaver/plugin-data-viewer'; import type { IDataQueryOptions } from '@cloudbeaver/plugin-sql-editor'; import { DataExportSettingsService } from './DataExportSettingsService'; @@ -26,7 +25,7 @@ export class DataExportMenuService { private readonly dataExportSettingsService: DataExportSettingsService, private readonly actionService: ActionService, private readonly menuService: MenuService, - ) { } + ) {} register(): void { this.tableFooterMenuService.registerMenuItem({ @@ -40,9 +39,11 @@ export class DataExportMenuService { }, isHidden: () => this.isDisabled(), isDisabled(context) { - return context.data.model.isLoading() - || context.data.model.isDisabled(context.data.resultIndex) - || !context.data.model.getResult(context.data.resultIndex); + return ( + context.data.model.isLoading() || + context.data.model.isDisabled(context.data.resultIndex) || + !context.data.model.getResult(context.data.resultIndex) + ); }, onClick: this.exportData.bind(this), }); @@ -55,25 +56,14 @@ export class DataExportMenuService { return false; } - return ( - !this.isDisabled() - && context.has(DATA_CONTEXT_CONNECTION) - && !context.has(DATA_CONTEXT_MENU_NESTED) - ); + return !this.isDisabled() && context.has(DATA_CONTEXT_CONNECTION) && !context.has(DATA_CONTEXT_MENU_NESTED); }, - getItems: (context, items) => [ - ...items, - ACTION_EXPORT, - ], + getItems: (context, items) => [...items, ACTION_EXPORT], }); this.actionService.addHandler({ id: 'data-export', - isActionApplicable: (context, action) => ( - action === ACTION_EXPORT - && context.has(DATA_CONTEXT_CONNECTION) - && context.has(DATA_CONTEXT_NAV_NODE) - ), + isActionApplicable: (context, action) => action === ACTION_EXPORT && context.has(DATA_CONTEXT_CONNECTION) && context.has(DATA_CONTEXT_NAV_NODE), handler: async (context, action) => { const node = context.get(DATA_CONTEXT_NAV_NODE); const connection = context.get(DATA_CONTEXT_CONNECTION); diff --git a/webapp/packages/plugin-data-export/src/DataExportProcessService.ts b/webapp/packages/plugin-data-export/src/DataExportProcessService.ts index 41b42ddc9c..9d05adf8e5 100644 --- a/webapp/packages/plugin-data-export/src/DataExportProcessService.ts +++ b/webapp/packages/plugin-data-export/src/DataExportProcessService.ts @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IConnectionInfoParams } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; -import { GraphQLService, DataTransferParameters } from '@cloudbeaver/core-sdk'; +import { DataTransferParameters, GraphQLService } from '@cloudbeaver/core-sdk'; import { Deferred, GlobalConstants, OrderedMap } from '@cloudbeaver/core-utils'; import { ExportFromContainerProcess } from './ExportFromContainerProcess'; @@ -32,10 +31,7 @@ export interface ExportProcess { export class DataExportProcessService { readonly exportProcesses = new OrderedMap(value => value.taskId); - constructor( - private readonly graphQLService: GraphQLService, - private readonly notificationService: NotificationService - ) { } + constructor(private readonly graphQLService: GraphQLService, private readonly notificationService: NotificationService) {} async cancel(exportId: string): Promise { const process = this.exportProcesses.get(exportId); @@ -86,10 +82,7 @@ export class DataExportProcessService { return GlobalConstants.absoluteServiceUrl('/data/', dataFileId); } - async exportData( - context: IExportContext, - parameters: DataTransferParameters - ): Promise { + async exportData(context: IExportContext, parameters: DataTransferParameters): Promise { let process: Process | undefined; if (context.contextId && context.resultId) { @@ -114,7 +107,7 @@ export class DataExportProcessService { private async exportFromContainer( connectionKey: IConnectionInfoParams, containerNodePath: string, - parameters: DataTransferParameters + parameters: DataTransferParameters, ): Promise { const process = new ExportFromContainerProcess(this.graphQLService, this.notificationService); const taskId = await process.start(connectionKey, containerNodePath, parameters); @@ -125,7 +118,7 @@ export class DataExportProcessService { connectionKey: IConnectionInfoParams, contextId: string, resultsId: string, - parameters: DataTransferParameters + parameters: DataTransferParameters, ): Promise { const process = new ExportFromResultsProcess(this.graphQLService, this.notificationService); const taskId = await process.start(connectionKey, contextId, resultsId, parameters); diff --git a/webapp/packages/plugin-data-export/src/DataExportService.ts b/webapp/packages/plugin-data-export/src/DataExportService.ts index 8a928729a4..820a55ed0f 100644 --- a/webapp/packages/plugin-data-export/src/DataExportService.ts +++ b/webapp/packages/plugin-data-export/src/DataExportService.ts @@ -5,7 +5,6 @@ * 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 { NotificationService } from '@cloudbeaver/core-events'; import type { DataTransferParameters } from '@cloudbeaver/core-sdk'; @@ -20,8 +19,8 @@ export class DataExportService { constructor( private readonly notificationService: NotificationService, private readonly dataExportProcessService: DataExportProcessService, - readonly processors: DataTransferProcessorsResource - ) { } + readonly processors: DataTransferProcessorsResource, + ) {} async cancel(exportId: string): Promise { await this.dataExportProcessService.cancel(exportId); @@ -35,14 +34,8 @@ export class DataExportService { this.dataExportProcessService.download(exportId); } - async exportData( - context: IExportContext, - parameters: DataTransferParameters - ): Promise { - const taskId = await this.dataExportProcessService.exportData( - context, - parameters - ); + async exportData(context: IExportContext, parameters: DataTransferParameters): Promise { + const taskId = await this.dataExportProcessService.exportData(context, parameters); this.notificationService.customNotification(() => ExportNotification, { source: taskId }); return taskId; diff --git a/webapp/packages/plugin-data-export/src/DataExportSettingsService.test.ts b/webapp/packages/plugin-data-export/src/DataExportSettingsService.test.ts index b68f45dab5..d55ff10f6a 100644 --- a/webapp/packages/plugin-data-export/src/DataExportSettingsService.test.ts +++ b/webapp/packages/plugin-data-export/src/DataExportSettingsService.test.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import '@testing-library/jest-dom'; import { mockAuthentication } from '@cloudbeaver/core-authentication/mocks/mockAuthentication'; @@ -25,19 +24,9 @@ import { DataExportSettings, DataExportSettingsService } from './DataExportSetti import { manifest } from './manifest'; const endpoint = createGQLEndpoint(); -const app = createApp( - datasourceContextSwitch, - navigationTree, - navigationTabs, - objectViewer, - dataViewer, - manifest -); +const app = createApp(datasourceContextSwitch, navigationTree, navigationTabs, objectViewer, dataViewer, manifest); -const server = mockGraphQL( - ...mockAppInit(endpoint), - ...mockAuthentication(endpoint) -); +const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint)); beforeAll(() => app.init()); @@ -70,9 +59,7 @@ test('New settings equal deprecated settings A', async () => { const settings = app.injector.getServiceByClass(DataExportSettingsService); const config = app.injector.getServiceByClass(ServerConfigResource); - server.use( - endpoint.query('serverConfig', mockServerConfig(equalConfigA)), - ); + server.use(endpoint.query('serverConfig', mockServerConfig(equalConfigA))); await config.refresh(); @@ -84,12 +71,10 @@ test('New settings equal deprecated settings B', async () => { const settings = app.injector.getServiceByClass(DataExportSettingsService); const config = app.injector.getServiceByClass(ServerConfigResource); - server.use( - endpoint.query('serverConfig', mockServerConfig(equalConfigB)), - ); + server.use(endpoint.query('serverConfig', mockServerConfig(equalConfigB))); await config.refresh(); expect(settings.settings.getValue('disabled')).toBe(testValueB); expect(settings.deprecatedSettings.getValue('disabled')).toBe(testValueB); -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-data-export/src/DataExportSettingsService.ts b/webapp/packages/plugin-data-export/src/DataExportSettingsService.ts index be64cfbf79..6c1a84599b 100644 --- a/webapp/packages/plugin-data-export/src/DataExportSettingsService.ts +++ b/webapp/packages/plugin-data-export/src/DataExportSettingsService.ts @@ -5,7 +5,6 @@ * 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 { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin'; diff --git a/webapp/packages/plugin-data-export/src/DataTransferProcessorsResource.ts b/webapp/packages/plugin-data-export/src/DataTransferProcessorsResource.ts index 1901159fbc..6f970abf15 100644 --- a/webapp/packages/plugin-data-export/src/DataTransferProcessorsResource.ts +++ b/webapp/packages/plugin-data-export/src/DataTransferProcessorsResource.ts @@ -5,19 +5,19 @@ * 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 { ServerConfigResource } from '@cloudbeaver/core-root'; -import { GraphQLService, CachedMapResource, DataTransferProcessorInfo, resourceKeyList, CachedMapAllKey } from '@cloudbeaver/core-sdk'; +import { CachedMapAllKey, CachedMapResource, DataTransferProcessorInfo, GraphQLService, resourceKeyList } from '@cloudbeaver/core-sdk'; @injectable() export class DataTransferProcessorsResource extends CachedMapResource { - constructor( - private readonly graphQLService: GraphQLService, - serverConfigResource: ServerConfigResource - ) { + constructor(private readonly graphQLService: GraphQLService, serverConfigResource: ServerConfigResource) { super(() => new Map()); - this.sync(serverConfigResource, () => {}, () => CachedMapAllKey); + this.sync( + serverConfigResource, + () => {}, + () => CachedMapAllKey, + ); } protected async loader(): Promise> { diff --git a/webapp/packages/plugin-data-export/src/Dialog/DataExportController.ts b/webapp/packages/plugin-data-export/src/Dialog/DataExportController.ts index 24116f2e5a..1dda3d5148 100644 --- a/webapp/packages/plugin-data-export/src/Dialog/DataExportController.ts +++ b/webapp/packages/plugin-data-export/src/Dialog/DataExportController.ts @@ -5,15 +5,20 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { observable, computed, makeObservable } from 'mobx'; +import { computed, makeObservable, observable } from 'mobx'; import type { IProperty } from '@cloudbeaver/core-blocks'; -import { injectable, IInitializableController, IDestructibleController } from '@cloudbeaver/core-di'; +import { IDestructibleController, IInitializableController, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; import { ErrorDetailsDialog } from '@cloudbeaver/core-notifications'; -import { DataTransferOutputSettings, DataTransferProcessorInfo, GQLErrorCatcher, ObjectPropertyInfo, ObjectPropertyLength } from '@cloudbeaver/core-sdk'; +import { + DataTransferOutputSettings, + DataTransferProcessorInfo, + GQLErrorCatcher, + ObjectPropertyInfo, + ObjectPropertyLength, +} from '@cloudbeaver/core-sdk'; import { DataExportService } from '../DataExportService'; import type { IExportContext } from '../IExportContext'; @@ -21,7 +26,7 @@ import { DefaultExportOutputSettingsResource } from './DefaultExportOutputSettin export enum DataExportStep { DataTransferProcessor, - Configure + Configure, } @injectable() @@ -35,11 +40,7 @@ export class DataExportController implements IInitializableController, IDestruct processor: DataTransferProcessorInfo | null = null; get processors(): DataTransferProcessorInfo[] { - return Array - .from( - this.dataExportService.processors.data.values() - ) - .sort(sortProcessors); + return Array.from(this.dataExportService.processors.data.values()).sort(sortProcessors); } processorProperties: any = {}; @@ -88,19 +89,16 @@ export class DataExportController implements IInitializableController, IDestruct this.isExporting = true; try { - await this.dataExportService.exportData( - this.context, - { - processorId: this.processor.id, - processorProperties: this.processorProperties, - filter: this.context.filter, - outputSettings: this.outputSettings, - } - ); + await this.dataExportService.exportData(this.context, { + processorId: this.processor.id, + processorProperties: this.processorProperties, + filter: this.context.filter, + outputSettings: this.outputSettings, + }); this.close(); } catch (exception: any) { if (!this.error.catch(exception) || this.isDistructed) { - this.notificationService.logException(exception, 'Can\'t export'); + this.notificationService.logException(exception, "Can't export"); } } finally { this.isExporting = false; @@ -113,20 +111,18 @@ export class DataExportController implements IInitializableController, IDestruct }; selectProcessor = (processorId: string) => { - this.processor = this.dataExportService - .processors - .data - .get(processorId)!; + this.processor = this.dataExportService.processors.data.get(processorId)!; - this.properties = this.processor.properties?.map(property => ({ - id: property.id!, - key: property.id!, - displayName: property.displayName, - description: property.description, - validValues: property.validValues, - defaultValue: property.defaultValue, - valuePlaceholder: property.defaultValue, - })) || []; + this.properties = + this.processor.properties?.map(property => ({ + id: property.id!, + key: property.id!, + displayName: property.displayName, + description: property.description, + validValues: property.validValues, + defaultValue: property.defaultValue, + valuePlaceholder: property.defaultValue, + })) || []; this.processorProperties = {}; @@ -144,7 +140,7 @@ export class DataExportController implements IInitializableController, IDestruct try { await this.dataExportService.processors.load(); } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t load data export processors'); + this.notificationService.logException(exception, "Can't load data export processors"); } } @@ -155,14 +151,14 @@ export class DataExportController implements IInitializableController, IDestruct Object.assign(this.outputSettings, data.outputSettings); } } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t load output settings'); + this.notificationService.logException(exception, "Can't load output settings"); } } } function sortProcessors(processorA: DataTransferProcessorInfo, processorB: DataTransferProcessorInfo): number { if (processorA.order === processorB.order) { - return (processorA.name || '').localeCompare((processorB.name || '')); + return (processorA.name || '').localeCompare(processorB.name || ''); } return processorA.order - processorB.order; diff --git a/webapp/packages/plugin-data-export/src/Dialog/DataExportDialog.tsx b/webapp/packages/plugin-data-export/src/Dialog/DataExportDialog.tsx index cb1a618d56..4283b7d21d 100644 --- a/webapp/packages/plugin-data-export/src/Dialog/DataExportDialog.tsx +++ b/webapp/packages/plugin-data-export/src/Dialog/DataExportDialog.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useController } from '@cloudbeaver/core-di'; @@ -16,10 +15,7 @@ import { DataExportController, DataExportStep } from './DataExportController'; import { ProcessorConfigureDialog } from './ProcessorConfigureDialog'; import { ProcessorSelectDialog } from './ProcessorSelectDialog'; -export const DataExportDialog: DialogComponent = observer(function DataExportDialog({ - payload, - rejectDialog, -}) { +export const DataExportDialog: DialogComponent = observer(function DataExportDialog({ payload, rejectDialog }) { const controller = useController(DataExportController, payload, rejectDialog); if (controller.step === DataExportStep.Configure && controller.processor) { diff --git a/webapp/packages/plugin-data-export/src/Dialog/DefaultExportOutputSettingsResource.ts b/webapp/packages/plugin-data-export/src/Dialog/DefaultExportOutputSettingsResource.ts index e704308216..3cf66d1835 100644 --- a/webapp/packages/plugin-data-export/src/Dialog/DefaultExportOutputSettingsResource.ts +++ b/webapp/packages/plugin-data-export/src/Dialog/DefaultExportOutputSettingsResource.ts @@ -5,18 +5,11 @@ * 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 { - GraphQLService, - CachedDataResource, - DataTransferDefaultExportSettings -} from '@cloudbeaver/core-sdk'; +import { CachedDataResource, DataTransferDefaultExportSettings, GraphQLService } from '@cloudbeaver/core-sdk'; @injectable() -export class DefaultExportOutputSettingsResource - extends CachedDataResource { - +export class DefaultExportOutputSettingsResource extends CachedDataResource { constructor(private readonly graphQLService: GraphQLService) { super(() => null); } diff --git a/webapp/packages/plugin-data-export/src/Dialog/ExportProcessorList/ExportProcessorList.tsx b/webapp/packages/plugin-data-export/src/Dialog/ExportProcessorList/ExportProcessorList.tsx index d853c5f39b..54d859e9ed 100644 --- a/webapp/packages/plugin-data-export/src/Dialog/ExportProcessorList/ExportProcessorList.tsx +++ b/webapp/packages/plugin-data-export/src/Dialog/ExportProcessorList/ExportProcessorList.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { ItemList } from '@cloudbeaver/core-blocks'; @@ -19,14 +18,12 @@ interface Props { className?: string; } -export const ExportProcessorList = observer(function ExportProcessorList({ - processors, - onSelect, - className, -}) { +export const ExportProcessorList = observer(function ExportProcessorList({ processors, onSelect, className }) { return ( - {processors.map(processor => )} + {processors.map(processor => ( + + ))} ); }); diff --git a/webapp/packages/plugin-data-export/src/Dialog/ExportProcessorList/ProcessorItem.tsx b/webapp/packages/plugin-data-export/src/Dialog/ExportProcessorList/ProcessorItem.tsx index 83efffaabc..37bd33c79c 100644 --- a/webapp/packages/plugin-data-export/src/Dialog/ExportProcessorList/ProcessorItem.tsx +++ b/webapp/packages/plugin-data-export/src/Dialog/ExportProcessorList/ProcessorItem.tsx @@ -5,14 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback } from 'react'; import styled, { css } from 'reshadow'; -import { - ListItem, ListItemIcon, StaticImage, ListItemName, ListItemDescription -} from '@cloudbeaver/core-blocks'; +import { ListItem, ListItemDescription, ListItemIcon, ListItemName, StaticImage } from '@cloudbeaver/core-blocks'; import type { DataTransferProcessorInfo } from '@cloudbeaver/core-sdk'; interface Props { @@ -21,24 +18,23 @@ interface Props { } const styles = css` - StaticImage { - box-sizing: border-box; - width: 24px; - max-height: 24px; - } - `; + StaticImage { + box-sizing: border-box; + width: 24px; + max-height: 24px; + } +`; -export const ProcessorItem = observer(function ProcessorItem({ - processor, - onSelect, -}) { +export const ProcessorItem = observer(function ProcessorItem({ processor, onSelect }) { const select = useCallback(() => onSelect(processor.id), [processor]); return styled(styles)( - + + + {processor.name} {processor.description} - + , ); }); diff --git a/webapp/packages/plugin-data-export/src/Dialog/OutputOptionsForm.tsx b/webapp/packages/plugin-data-export/src/Dialog/OutputOptionsForm.tsx index 35779349f1..48c7174933 100644 --- a/webapp/packages/plugin-data-export/src/Dialog/OutputOptionsForm.tsx +++ b/webapp/packages/plugin-data-export/src/Dialog/OutputOptionsForm.tsx @@ -26,7 +26,7 @@ const styles = css` FieldCheckbox { margin-bottom: 6px; - margin-left: 24px + margin-left: 24px; } `; @@ -48,21 +48,13 @@ export const OutputOptionsForm = observer(function OutputOptionsForm(props: Prop return styled(styles)( - - Encoding + + Encoding - - Insert BOM + + Insert BOM - + , ); }} diff --git a/webapp/packages/plugin-data-export/src/Dialog/ProcessorConfigureDialog.tsx b/webapp/packages/plugin-data-export/src/Dialog/ProcessorConfigureDialog.tsx index 0e7dfa4fd7..05cdd7a521 100644 --- a/webapp/packages/plugin-data-export/src/Dialog/ProcessorConfigureDialog.tsx +++ b/webapp/packages/plugin-data-export/src/Dialog/ProcessorConfigureDialog.tsx @@ -9,7 +9,7 @@ import { observer } from 'mobx-react-lite'; import { useState } from 'react'; import styled, { css } from 'reshadow'; -import { IProperty, PropertiesTable, ErrorMessage, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { ErrorMessage, IProperty, PropertiesTable, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper } from '@cloudbeaver/core-dialogs'; import type { DataTransferOutputSettings, DataTransferProcessorInfo, GQLErrorCatcher } from '@cloudbeaver/core-sdk'; import { ITabData, Tab, TabList, TabsState, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui'; @@ -18,32 +18,32 @@ import { OutputOptionsForm } from './OutputOptionsForm'; import { ProcessorConfigureDialogFooter } from './ProcessorConfigureDialogFooter'; const styles = css` - Tab { - composes: theme-ripple theme-background-secondary theme-text-on-secondary from global; - } - PropertiesTable { - flex: 1; - overflow: hidden; - padding: 12px 0; - } - message { - margin: auto; - } - ErrorMessage { - composes: theme-background-secondary theme-text-on-secondary from global; - position: sticky; - bottom: 0; - padding: 8px 24px; - } + Tab { + composes: theme-ripple theme-background-secondary theme-text-on-secondary from global; + } + PropertiesTable { + flex: 1; + overflow: hidden; + padding: 12px 0; + } + message { + margin: auto; + } + ErrorMessage { + composes: theme-background-secondary theme-text-on-secondary from global; + position: sticky; + bottom: 0; + padding: 8px 24px; + } - TabList { - margin: 0 10px; - } + TabList { + margin: 0 10px; + } - ObjectPropertyInfoForm { - margin: 12px 0; - } - `; + ObjectPropertyInfoForm { + margin: 12px 0; + } +`; interface Props { processor: DataTransferProcessorInfo; @@ -96,12 +96,12 @@ export const ProcessorConfigureDialog = observer(function ProcessorConfig } return styled(useStyles(UNDERLINE_TAB_STYLES, styles))( - + {!processor.isBinary ? ( - + {translate('data_transfer_format_settings')} @@ -112,21 +112,12 @@ export const ProcessorConfigureDialog = observer(function ProcessorConfig ) : null} {currentTabId === SETTINGS_TABS.EXTRACTION ? ( - + ) : ( )} - {error.responseMessage && ( - - )} + {error.responseMessage && } (function ProcessorConfig onNext={handleNextClick} /> - + , ); }); diff --git a/webapp/packages/plugin-data-export/src/Dialog/ProcessorConfigureDialogFooter.tsx b/webapp/packages/plugin-data-export/src/Dialog/ProcessorConfigureDialogFooter.tsx index 996531360f..3d3785e99f 100644 --- a/webapp/packages/plugin-data-export/src/Dialog/ProcessorConfigureDialogFooter.tsx +++ b/webapp/packages/plugin-data-export/src/Dialog/ProcessorConfigureDialogFooter.tsx @@ -5,13 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; import { Button, useTranslate } from '@cloudbeaver/core-blocks'; - const styles = css` controls { display: flex; @@ -51,43 +49,22 @@ export const ProcessorConfigureDialogFooter = observer(function Processor return styled(styles)( - - {isFinalStep ? ( - ) : ( - )} - + , ); -} -); +}); diff --git a/webapp/packages/plugin-data-export/src/Dialog/ProcessorSelectDialog.tsx b/webapp/packages/plugin-data-export/src/Dialog/ProcessorSelectDialog.tsx index 3ac8ea53b3..42cd4ffcb2 100644 --- a/webapp/packages/plugin-data-export/src/Dialog/ProcessorSelectDialog.tsx +++ b/webapp/packages/plugin-data-export/src/Dialog/ProcessorSelectDialog.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -49,22 +48,13 @@ interface Props { onClose: () => void; } -export const ProcessorSelectDialog = observer(function ProcessorSelectDialog({ - context, - processors, - isLoading, - onSelect, - onClose, -}) { +export const ProcessorSelectDialog = observer(function ProcessorSelectDialog({ context, processors, isLoading, onSelect, onClose }) { const translate = useTranslate(); const { node } = useNode(context.containerNodePath || ''); return styled(styles)( - - + + {!context.sourceName && `${translate('data_transfer_exporting_table')} ${node?.name}`} @@ -73,7 +63,6 @@ export const ProcessorSelectDialog = observer(function ProcessorSelectDia {isLoading && } {!isLoading && } - + , ); -} -); +}); diff --git a/webapp/packages/plugin-data-export/src/ExportFromContainerProcess.ts b/webapp/packages/plugin-data-export/src/ExportFromContainerProcess.ts index e22924939d..b80333445f 100644 --- a/webapp/packages/plugin-data-export/src/ExportFromContainerProcess.ts +++ b/webapp/packages/plugin-data-export/src/ExportFromContainerProcess.ts @@ -5,15 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IConnectionInfoParams } from '@cloudbeaver/core-connections'; import type { NotificationService } from '@cloudbeaver/core-events'; -import { - AsyncTaskInfo, GraphQLService, ServerInternalError, DataTransferParameters -} from '@cloudbeaver/core-sdk'; -import { - CancellablePromise, cancellableTimeout, Deferred, EDeferredState -} from '@cloudbeaver/core-utils'; +import { AsyncTaskInfo, DataTransferParameters, GraphQLService, ServerInternalError } from '@cloudbeaver/core-sdk'; +import { CancellablePromise, cancellableTimeout, Deferred, EDeferredState } from '@cloudbeaver/core-utils'; const DELAY_BETWEEN_TRIES = 1000; @@ -23,16 +18,11 @@ export class ExportFromContainerProcess extends Deferred { private timeout?: CancellablePromise; private isCancelConfirmed = false; // true when server successfully executed cancelQueryAsync - constructor(private readonly graphQLService: GraphQLService, - private readonly notificationService: NotificationService) { + constructor(private readonly graphQLService: GraphQLService, private readonly notificationService: NotificationService) { super(); } - async start( - connectionKey: IConnectionInfoParams, - containerNodePath: string, - parameters: DataTransferParameters - ): Promise { + async start(connectionKey: IConnectionInfoParams, containerNodePath: string, parameters: DataTransferParameters): Promise { // start async task try { const { taskInfo } = await this.graphQLService.sdk.exportDataFromContainer({ @@ -96,7 +86,7 @@ export class ExportFromContainerProcess extends Deferred { try { this.timeout = cancellableTimeout(DELAY_BETWEEN_TRIES); await this.timeout; - } catch { } + } catch {} } } diff --git a/webapp/packages/plugin-data-export/src/ExportFromResultsProcess.ts b/webapp/packages/plugin-data-export/src/ExportFromResultsProcess.ts index 474f550609..7d8ae9bca5 100644 --- a/webapp/packages/plugin-data-export/src/ExportFromResultsProcess.ts +++ b/webapp/packages/plugin-data-export/src/ExportFromResultsProcess.ts @@ -5,15 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IConnectionInfoParams } from '@cloudbeaver/core-connections'; import type { NotificationService } from '@cloudbeaver/core-events'; -import { - AsyncTaskInfo, GraphQLService, ServerInternalError, DataTransferParameters -} from '@cloudbeaver/core-sdk'; -import { - CancellablePromise, cancellableTimeout, Deferred, EDeferredState -} from '@cloudbeaver/core-utils'; +import { AsyncTaskInfo, DataTransferParameters, GraphQLService, ServerInternalError } from '@cloudbeaver/core-sdk'; +import { CancellablePromise, cancellableTimeout, Deferred, EDeferredState } from '@cloudbeaver/core-utils'; const DELAY_BETWEEN_TRIES = 1000; @@ -23,17 +18,11 @@ export class ExportFromResultsProcess extends Deferred { private timeout?: CancellablePromise; private isCancelConfirmed = false; // true when server successfully executed cancelQueryAsync - constructor(private readonly graphQLService: GraphQLService, - private readonly notificationService: NotificationService) { + constructor(private readonly graphQLService: GraphQLService, private readonly notificationService: NotificationService) { super(); } - async start( - connectionKey: IConnectionInfoParams, - contextId: string, - resultsId: string, - parameters: DataTransferParameters - ): Promise { + async start(connectionKey: IConnectionInfoParams, contextId: string, resultsId: string, parameters: DataTransferParameters): Promise { // start async task try { const { taskInfo } = await this.graphQLService.sdk.exportDataFromResults({ @@ -98,7 +87,7 @@ export class ExportFromResultsProcess extends Deferred { try { this.timeout = cancellableTimeout(DELAY_BETWEEN_TRIES); await this.timeout; - } catch { } + } catch {} } } diff --git a/webapp/packages/plugin-data-export/src/ExportNotification/ExportNotification.tsx b/webapp/packages/plugin-data-export/src/ExportNotification/ExportNotification.tsx index e44e8599e2..62282b0b31 100644 --- a/webapp/packages/plugin-data-export/src/ExportNotification/ExportNotification.tsx +++ b/webapp/packages/plugin-data-export/src/ExportNotification/ExportNotification.tsx @@ -5,13 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import { - Button, SnackbarWrapper, SnackbarStatus, SnackbarContent, SnackbarBody, SnackbarFooter, useTranslate -} from '@cloudbeaver/core-blocks'; +import { Button, SnackbarBody, SnackbarContent, SnackbarFooter, SnackbarStatus, SnackbarWrapper, useTranslate } from '@cloudbeaver/core-blocks'; import { useController } from '@cloudbeaver/core-di'; import { ENotificationType, NotificationComponentProps } from '@cloudbeaver/core-events'; import { EDeferredState } from '@cloudbeaver/core-utils'; @@ -45,9 +42,7 @@ type Props = NotificationComponentProps<{ source: string; }>; -export const ExportNotification = observer(function ExportNotification({ - notification, -}) { +export const ExportNotification = observer(function ExportNotification({ notification }) { const controller = useController(ExportNotificationController, notification); const translate = useTranslate(); const { title, status, message } = controller.status; @@ -60,41 +55,22 @@ export const ExportNotification = observer(function ExportNotification({ {message && {message}} {controller.sourceName} - {controller.task?.context.sourceName && ( -
-                {controller.task.context.sourceName}
-              
- )} + {controller.task?.context.sourceName &&
{controller.task.context.sourceName}
}
{status === ENotificationType.Info && controller.downloadUrl && ( <> - - )} {status === ENotificationType.Error && ( - )} @@ -110,7 +86,6 @@ export const ExportNotification = observer(function ExportNotification({ )} - - + , ); }); diff --git a/webapp/packages/plugin-data-export/src/ExportNotification/ExportNotificationController.ts b/webapp/packages/plugin-data-export/src/ExportNotification/ExportNotificationController.ts index 9b338a6713..84aa293b06 100644 --- a/webapp/packages/plugin-data-export/src/ExportNotification/ExportNotificationController.ts +++ b/webapp/packages/plugin-data-export/src/ExportNotification/ExportNotificationController.ts @@ -5,8 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { observable, computed, makeObservable } from 'mobx'; +import { computed, makeObservable, observable } from 'mobx'; import { IInitializableController, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; @@ -14,7 +13,7 @@ import { ENotificationType, INotification } from '@cloudbeaver/core-events'; import { LocalizationService } from '@cloudbeaver/core-localization'; import { NavNodeManagerService } from '@cloudbeaver/core-navigation-tree'; import { ErrorDetailsDialog } from '@cloudbeaver/core-notifications'; -import { ServerInternalError, ServerErrorType } from '@cloudbeaver/core-sdk'; +import { ServerErrorType, ServerInternalError } from '@cloudbeaver/core-sdk'; import { Deferred, EDeferredState, errorOf } from '@cloudbeaver/core-utils'; import { DataExportProcessService, ExportProcess } from '../DataExportProcessService'; @@ -100,7 +99,7 @@ export class ExportNotificationController implements IInitializableController { private readonly commonDialogService: CommonDialogService, private readonly dataExportProcessService: DataExportProcessService, private readonly navNodeManagerService: NavNodeManagerService, - private readonly localization: LocalizationService + private readonly localization: LocalizationService, ) { makeObservable(this, { isDetailsDialogOpen: observable, diff --git a/webapp/packages/plugin-data-export/src/IExportContext.ts b/webapp/packages/plugin-data-export/src/IExportContext.ts index 63a1b5f89f..7714e63181 100644 --- a/webapp/packages/plugin-data-export/src/IExportContext.ts +++ b/webapp/packages/plugin-data-export/src/IExportContext.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IConnectionInfoParams } from '@cloudbeaver/core-connections'; import type { SqlDataFilter } from '@cloudbeaver/core-sdk'; diff --git a/webapp/packages/plugin-data-export/src/LocaleService.ts b/webapp/packages/plugin-data-export/src/LocaleService.ts index 144237a086..e3649a06b4 100644 --- a/webapp/packages/plugin-data-export/src/LocaleService.ts +++ b/webapp/packages/plugin-data-export/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-data-export/src/locales/it.ts b/webapp/packages/plugin-data-export/src/locales/it.ts index d8b070f865..c53e827cc2 100644 --- a/webapp/packages/plugin-data-export/src/locales/it.ts +++ b/webapp/packages/plugin-data-export/src/locales/it.ts @@ -3,7 +3,7 @@ export default [ ['data_transfer_dialog_export', 'Esporta'], ['data_transfer_dialog_export_tooltip', 'Esporta i risultati in un file'], ['data_transfer_dialog_configuration_title', 'Esporta la configurazione'], - ['data_transfer_dialog_preparation', 'Sto preparando l\'esportazione in un file. Attendi...'], + ['data_transfer_dialog_preparation', "Sto preparando l'esportazione in un file. Attendi..."], ['data_transfer_notification_preparation', 'Sto preparando il download del tuo file. Attendi...'], ['data_transfer_notification_ready', 'Il file è pronto per il download'], ['data_transfer_notification_error', 'Preparazione fallita o annullata'], diff --git a/webapp/packages/plugin-data-export/src/locales/zh.ts b/webapp/packages/plugin-data-export/src/locales/zh.ts index 2758b522fb..045bc97bca 100644 --- a/webapp/packages/plugin-data-export/src/locales/zh.ts +++ b/webapp/packages/plugin-data-export/src/locales/zh.ts @@ -1,15 +1,15 @@ export default [ - ['data_transfer_dialog_title', '导出数据'], - ['data_transfer_dialog_export', '导出'], - ['data_transfer_dialog_export_tooltip', '将结果集导出为文件'], - ['data_transfer_dialog_configuration_title', '导出配置'], - ['data_transfer_dialog_preparation', '我们准备您的文件以供导出。请稍等...'], - ['data_transfer_notification_preparation', '我们准备您的文件以供下载。请稍等...'], - ['data_transfer_notification_ready', '文件已经准备好下载'], - ['data_transfer_notification_error', '数据导出失败'], - ['data_transfer_notification_cancelled', '数据导出已取消'], - ['data_transfer_notification_download', '下载'], - ['data_transfer_notification_delete', '删除'], - ['data_transfer_exporting_table', '表:'], - ['data_transfer_exporting_sql', 'SQL:'], - ]; + ['data_transfer_dialog_title', '导出数据'], + ['data_transfer_dialog_export', '导出'], + ['data_transfer_dialog_export_tooltip', '将结果集导出为文件'], + ['data_transfer_dialog_configuration_title', '导出配置'], + ['data_transfer_dialog_preparation', '我们准备您的文件以供导出。请稍等...'], + ['data_transfer_notification_preparation', '我们准备您的文件以供下载。请稍等...'], + ['data_transfer_notification_ready', '文件已经准备好下载'], + ['data_transfer_notification_error', '数据导出失败'], + ['data_transfer_notification_cancelled', '数据导出已取消'], + ['data_transfer_notification_download', '下载'], + ['data_transfer_notification_delete', '删除'], + ['data_transfer_exporting_table', '表:'], + ['data_transfer_exporting_sql', 'SQL:'], +]; diff --git a/webapp/packages/plugin-data-export/src/manifest.ts b/webapp/packages/plugin-data-export/src/manifest.ts index 0eefc82705..0841f74ce2 100644 --- a/webapp/packages/plugin-data-export/src/manifest.ts +++ b/webapp/packages/plugin-data-export/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { Bootstrap } from './Bootstrap'; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellEditor/CellEditor.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellEditor/CellEditor.tsx index 4a4306078d..b06883984b 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellEditor/CellEditor.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellEditor/CellEditor.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { forwardRef, useContext, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; @@ -44,113 +43,111 @@ export interface IEditorRef { const lockNavigation = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End', 'Enter']; -export const CellEditor = observer, 'row' | 'column' | 'onClose'>, IEditorRef>(forwardRef(function CellEditor({ - row, - column, - onClose, -}, ref) { - const dataGridContext = useContext(DataGridContext); - const tableDataContext = useContext(TableDataContext); - const inputRef = useRef(null); - const [elementRef, setElementRef] = useState(null); - const [popperRef, setPopperRef] = useState(null); - const popper = usePopper(elementRef, popperRef, { - placement: 'right', - modifiers: [ - { name: 'flip', enabled: false }, - ], - }); +export const CellEditor = observer, 'row' | 'column' | 'onClose'>, IEditorRef>( + forwardRef(function CellEditor({ row, column, onClose }, ref) { + const dataGridContext = useContext(DataGridContext); + const tableDataContext = useContext(TableDataContext); + const inputRef = useRef(null); + const [elementRef, setElementRef] = useState(null); + const [popperRef, setPopperRef] = useState(null); + const popper = usePopper(elementRef, popperRef, { + placement: 'right', + modifiers: [{ name: 'flip', enabled: false }], + }); - if (!dataGridContext || !tableDataContext || column.columnDataIndex === null) { - throw new Error('DataGridContext should be provided'); - } - - useImperativeHandle(ref, () => ({ - focus: () => inputRef.current?.focus(), - })); - - useEffect(() => { - function resize(data: IColumnResizeInfo) { - if (elementRef && popperRef && data.column === column.idx) { - popperRef.style.width = (data.width + 1) + 'px'; - } + if (!dataGridContext || !tableDataContext || column.columnDataIndex === null) { + throw new Error('DataGridContext should be provided'); } - dataGridContext.columnResize.addHandler(resize); + useImperativeHandle(ref, () => ({ + focus: () => inputRef.current?.focus(), + })); - return () => dataGridContext.columnResize.removeHandler(resize); - }, [elementRef, popperRef, column]); - - useLayoutEffect(() => { - if (elementRef && popperRef) { - const size = elementRef.closest('[role="gridcell"]')?.getBoundingClientRect(); - - if (size) { - popperRef.style.width = (size.width + 1) + 'px'; - popperRef.style.height = (size.height + 1) + 'px'; + useEffect(() => { + function resize(data: IColumnResizeInfo) { + if (elementRef && popperRef && data.column === column.idx) { + popperRef.style.width = data.width + 1 + 'px'; + } } - } - }); - const cellKey: IResultSetElementKey = { row, column: column.columnDataIndex }; + dataGridContext.columnResize.addHandler(resize); - const value = tableDataContext.format - .getText(tableDataContext.getCellValue(cellKey)!) ?? ''; + return () => dataGridContext.columnResize.removeHandler(resize); + }, [elementRef, popperRef, column]); - const handleSave = () => onClose(false); - const handleReject = () => { - tableDataContext.editor.revert(cellKey); - onClose(false); - }; - const handleChange = (value: string) => { - tableDataContext.editor.set(cellKey, value); - }; - const handleUndo = () => { - tableDataContext.editor.revert(cellKey); - onClose(false); - }; + useLayoutEffect(() => { + if (elementRef && popperRef) { + const size = elementRef.closest('[role="gridcell"]')?.getBoundingClientRect(); - const handleKeyDown = (event: React.KeyboardEvent) => { - if (lockNavigation.includes(event.key)) { + if (size) { + popperRef.style.width = size.width + 1 + 'px'; + popperRef.style.height = size.height + 1 + 'px'; + } + } + }); + + const cellKey: IResultSetElementKey = { row, column: column.columnDataIndex }; + + const value = tableDataContext.format.getText(tableDataContext.getCellValue(cellKey)!) ?? ''; + + const handleSave = () => onClose(false); + const handleReject = () => { + tableDataContext.editor.revert(cellKey); + onClose(false); + }; + const handleChange = (value: string) => { + tableDataContext.editor.set(cellKey, value); + }; + const handleUndo = () => { + tableDataContext.editor.revert(cellKey); + onClose(false); + }; + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (lockNavigation.includes(event.key)) { + event.stopPropagation(); + } + }; + + const preventClick = (event: React.MouseEvent) => { + EventContext.set(event, EventStopPropagationFlag); // better but not works event.stopPropagation(); - } - }; + }; - const preventClick = (event: React.MouseEvent) => { - EventContext.set(event, EventStopPropagationFlag); // better but not works - event.stopPropagation(); - }; - - return styled(styles)( - - {createPortal(( - - - - ), dataGridContext.getEditorPortal()!) as any} - - ); -})); + return styled(styles)( + + { + createPortal( + + + , + dataGridContext.getEditorPortal()!, + ) as any + } + , + ); + }), +); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellContext.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellContext.ts index 6a8d5129fe..0bb702b6ca 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellContext.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellContext.ts @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createContext } from 'react'; import type { IMouseHook } from '@cloudbeaver/core-blocks'; -import type { IResultSetElementKey, DatabaseEditChangeType } from '@cloudbeaver/plugin-data-viewer'; +import type { DatabaseEditChangeType, IResultSetElementKey } from '@cloudbeaver/plugin-data-viewer'; import type { CellPosition } from '../../Editing/EditingContext'; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellRenderer.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellRenderer.tsx index 927fd3fca4..3353cbb247 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellRenderer.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellRenderer.tsx @@ -5,16 +5,14 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed, observable } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useContext, useEffect } from 'react'; - import { getComputed, useMouse, useObjectRef, useObservableRef } from '@cloudbeaver/core-blocks'; import { EventContext, EventStopPropagationFlag } from '@cloudbeaver/core-events'; import { clsx } from '@cloudbeaver/core-utils'; -import { IResultSetElementKey, IResultSetRowKey, isBooleanValuePresentationAvailable, DatabaseEditChangeType } from '@cloudbeaver/plugin-data-viewer'; +import { DatabaseEditChangeType, IResultSetElementKey, IResultSetRowKey, isBooleanValuePresentationAvailable } from '@cloudbeaver/plugin-data-viewer'; import { CalculatedColumn, Cell, CellRendererProps } from '@cloudbeaver/plugin-react-data-grid'; import { CellPosition, EditingContext } from '../../Editing/EditingContext'; @@ -33,48 +31,54 @@ export const CellRenderer = observer ({ - mouse, - get position(): CellPosition { - return { idx: this.column.idx, rowIdx: this.rowIdx }; - }, - get cell(): IResultSetElementKey | undefined { - if (this.column.columnDataIndex === null) { - return undefined; - } - return { row: this.row, column: this.column.columnDataIndex }; - }, - get isEditing(): boolean { - return editingContext.isEditing(this.position) || false; - }, - get isSelected(): boolean { - return selectionContext.isSelected(this.position.rowIdx, this.position.idx) || false; - }, - get editionState(): DatabaseEditChangeType | null { - if (!this.cell) { - return null; - } + const cellContext = useObservableRef( + () => ({ + mouse, + get position(): CellPosition { + return { idx: this.column.idx, rowIdx: this.rowIdx }; + }, + get cell(): IResultSetElementKey | undefined { + if (this.column.columnDataIndex === null) { + return undefined; + } + return { row: this.row, column: this.column.columnDataIndex }; + }, + get isEditing(): boolean { + return editingContext.isEditing(this.position) || false; + }, + get isSelected(): boolean { + return selectionContext.isSelected(this.position.rowIdx, this.position.idx) || false; + }, + get editionState(): DatabaseEditChangeType | null { + if (!this.cell) { + return null; + } - return tableDataContext.getEditionState(this.cell); + return tableDataContext.getEditionState(this.cell); + }, + }), + { + row: observable.ref, + column: observable.ref, + rowIdx: observable.ref, + position: computed, + cell: computed, + isEditing: computed, + isSelected: computed, + editionState: computed, }, - }), { - row: observable.ref, - column: observable.ref, - rowIdx: observable.ref, - position: computed, - cell: computed, - isEditing: computed, - isSelected: computed, - editionState: computed, - }, { row, column, rowIdx }); + { row, column, rowIdx }, + ); - const classes = getComputed(() => clsx({ - 'rdg-cell-custom-selected': cellContext.isSelected, - 'rdg-cell-custom-editing': cellContext.isEditing, - 'rdg-cell-custom-added': cellContext.editionState === DatabaseEditChangeType.add, - 'rdg-cell-custom-deleted': cellContext.editionState === DatabaseEditChangeType.delete, - 'rdg-cell-custom-edited': cellContext.editionState === DatabaseEditChangeType.update, - })); + const classes = getComputed(() => + clsx({ + 'rdg-cell-custom-selected': cellContext.isSelected, + 'rdg-cell-custom-editing': cellContext.isEditing, + 'rdg-cell-custom-added': cellContext.editionState === DatabaseEditChangeType.add, + 'rdg-cell-custom-deleted': cellContext.editionState === DatabaseEditChangeType.delete, + 'rdg-cell-custom-edited': cellContext.editionState === DatabaseEditChangeType.update, + }), + ); function isEditable(column: CalculatedColumn): boolean { if (!cellContext.cell) { @@ -90,57 +94,58 @@ export const CellRenderer = observer ({ - mouseDown(event: React.MouseEvent) { - // this.selectCell(this.row, this.column); - }, - mouseUp(event: React.MouseEvent) { - if ( - // !this.dataGridContext.isGridInFocus() - EventContext.has(event, EventStopPropagationFlag) - ) { - return; - } + const state = useObjectRef( + () => ({ + mouseDown(event: React.MouseEvent) { + // this.selectCell(this.row, this.column); + }, + mouseUp(event: React.MouseEvent) { + if ( + // !this.dataGridContext.isGridInFocus() + EventContext.has(event, EventStopPropagationFlag) + ) { + return; + } - this.selectionContext.select( - { - colIdx: this.column.idx, - rowIdx: this.rowIdx, - }, - event.ctrlKey || event.metaKey, - event.shiftKey, - false - ); - }, - doubleClick(event: React.MouseEvent) { - if ( - !this.isEditable(this.column) - // !this.dataGridContext.isGridInFocus() - || EventContext.has(event, EventStopPropagationFlag) - ) { - return; - } + this.selectionContext.select( + { + colIdx: this.column.idx, + rowIdx: this.rowIdx, + }, + event.ctrlKey || event.metaKey, + event.shiftKey, + false, + ); + }, + doubleClick(event: React.MouseEvent) { + if ( + !this.isEditable(this.column) || + // !this.dataGridContext.isGridInFocus() + EventContext.has(event, EventStopPropagationFlag) + ) { + return; + } - this.editingContext.edit(cellContext.position); + this.editingContext.edit(cellContext.position); + }, + }), + { + row, + column, + rowIdx, + isCellSelected, + selectionContext, + dataGridContext, + editingContext, + tableDataContext, + isEditable, + selectCell, }, - }), { - row, - column, - rowIdx, - isCellSelected, - selectionContext, - dataGridContext, - editingContext, - tableDataContext, - isEditable, - selectCell, - }, ['doubleClick', 'mouseUp', 'mouseDown']); + ['doubleClick', 'mouseUp', 'mouseDown'], + ); useEffect(() => () => editingContext.closeEditor(cellContext.position), []); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContext.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContext.ts index db9b90dfa0..34bd583d33 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContext.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContext.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 { createContext } from 'react'; - import type { IExecutor } from '@cloudbeaver/core-executor'; import type { IDatabaseDataModel, IDataTableActions } from '@cloudbeaver/plugin-data-viewer'; import type { DataGridHandle } from '@cloudbeaver/plugin-react-data-grid'; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuCellEditingService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuCellEditingService.ts index ea88803828..f8278fae6f 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuCellEditingService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuCellEditingService.ts @@ -5,9 +5,15 @@ * 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 { isBooleanValuePresentationAvailable, DatabaseEditChangeType, ResultSetEditAction, ResultSetFormatAction, ResultSetViewAction, ResultSetSelectAction } from '@cloudbeaver/plugin-data-viewer'; +import { + DatabaseEditChangeType, + isBooleanValuePresentationAvailable, + ResultSetEditAction, + ResultSetFormatAction, + ResultSetSelectAction, + ResultSetViewAction, +} from '@cloudbeaver/plugin-data-viewer'; import { DataGridContextMenuService } from './DataGridContextMenuService'; @@ -15,246 +21,195 @@ import { DataGridContextMenuService } from './DataGridContextMenuService'; export class DataGridContextMenuCellEditingService { private static readonly menuEditingToken = 'menuEditing'; - constructor( - private readonly dataGridContextMenuService: DataGridContextMenuService - ) { } + constructor(private readonly dataGridContextMenuService: DataGridContextMenuService) {} getMenuEditingToken(): string { return DataGridContextMenuCellEditingService.menuEditingToken; } register(): void { - this.dataGridContextMenuService.add( - this.dataGridContextMenuService.getMenuToken(), - { - id: this.getMenuEditingToken(), - order: 4, - title: 'data_grid_table_editing', - icon: 'edit', - isPanel: true, - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - return context.data.model.isDisabled(context.data.resultIndex) - || context.data.model.isReadonly(context.data.resultIndex); - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuEditingToken(), - { - id: 'open_inline_editor', - order: 0, - title: 'data_grid_table_editing_open_inline_editor', - icon: 'edit', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - const format = context.data.model.source.getAction(context.data.resultIndex, ResultSetFormatAction); - const view = context.data.model.source.getAction(context.data.resultIndex, ResultSetViewAction); - const cellValue = view.getCellValue(context.data.key); - const column = view.getColumn(context.data.key.column); + this.dataGridContextMenuService.add(this.dataGridContextMenuService.getMenuToken(), { + id: this.getMenuEditingToken(), + order: 4, + title: 'data_grid_table_editing', + icon: 'edit', + isPanel: true, + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + return context.data.model.isDisabled(context.data.resultIndex) || context.data.model.isReadonly(context.data.resultIndex); + }, + }); + this.dataGridContextMenuService.add(this.getMenuEditingToken(), { + id: 'open_inline_editor', + order: 0, + title: 'data_grid_table_editing_open_inline_editor', + icon: 'edit', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + const format = context.data.model.source.getAction(context.data.resultIndex, ResultSetFormatAction); + const view = context.data.model.source.getAction(context.data.resultIndex, ResultSetViewAction); + const cellValue = view.getCellValue(context.data.key); + const column = view.getColumn(context.data.key.column); - if (!column || cellValue === undefined || format.isReadOnly(context.data.key)) { - return true; - } + if (!column || cellValue === undefined || format.isReadOnly(context.data.key)) { + return true; + } - return isBooleanValuePresentationAvailable(cellValue, column); - }, - onClick(context) { - context.data.spreadsheetActions.edit(context.data.key); - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuEditingToken(), - { - id: 'set_to_null', - order: 1, - title: 'data_grid_table_editing_set_to_null', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - const { key, model, resultIndex } = context.data; - const view = model.source.getAction(resultIndex, ResultSetViewAction); - const format = model.source.getAction(resultIndex, ResultSetFormatAction); - const cellValue = view.getCellValue(key); + return isBooleanValuePresentationAvailable(cellValue, column); + }, + onClick(context) { + context.data.spreadsheetActions.edit(context.data.key); + }, + }); + this.dataGridContextMenuService.add(this.getMenuEditingToken(), { + id: 'set_to_null', + order: 1, + title: 'data_grid_table_editing_set_to_null', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + const { key, model, resultIndex } = context.data; + const view = model.source.getAction(resultIndex, ResultSetViewAction); + const format = model.source.getAction(resultIndex, ResultSetFormatAction); + const cellValue = view.getCellValue(key); - return ( - cellValue === undefined - || format.isReadOnly(context.data.key) - || view.getColumn(key.column)?.required - || format.isNull(cellValue) - ); - }, - onClick(context) { - context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction) - .set(context.data.key, null); - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuEditingToken(), - { - id: 'row_add', - order: 5, - icon: '/icons/data_add_sm.svg', - title: 'data_grid_table_editing_row_add', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); - return !editor.hasFeature('add'); - }, - onClick(context) { - const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); - editor.addRow(context.data.key.row); - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuEditingToken(), - { - id: 'row_add_copy', - order: 5.5, - icon: '/icons/data_add_copy_sm.svg', - title: 'data_grid_table_editing_row_add_copy', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); - return !editor.hasFeature('add'); - }, - onClick(context) { - const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); - editor.duplicateRow(context.data.key.row); - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuEditingToken(), - { - id: 'row_delete', - order: 6, - icon: '/icons/data_delete_sm.svg', - title: 'data_grid_table_editing_row_delete', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); + return cellValue === undefined || format.isReadOnly(context.data.key) || view.getColumn(key.column)?.required || format.isNull(cellValue); + }, + onClick(context) { + context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction).set(context.data.key, null); + }, + }); + this.dataGridContextMenuService.add(this.getMenuEditingToken(), { + id: 'row_add', + order: 5, + icon: '/icons/data_add_sm.svg', + title: 'data_grid_table_editing_row_add', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); + return !editor.hasFeature('add'); + }, + onClick(context) { + const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); + editor.addRow(context.data.key.row); + }, + }); + this.dataGridContextMenuService.add(this.getMenuEditingToken(), { + id: 'row_add_copy', + order: 5.5, + icon: '/icons/data_add_copy_sm.svg', + title: 'data_grid_table_editing_row_add_copy', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); + return !editor.hasFeature('add'); + }, + onClick(context) { + const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); + editor.duplicateRow(context.data.key.row); + }, + }); + this.dataGridContextMenuService.add(this.getMenuEditingToken(), { + id: 'row_delete', + order: 6, + icon: '/icons/data_delete_sm.svg', + title: 'data_grid_table_editing_row_delete', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); - if (context.data.model.isReadonly(context.data.resultIndex) || !editor.hasFeature('delete')) { - return true; - } + if (context.data.model.isReadonly(context.data.resultIndex) || !editor.hasFeature('delete')) { + return true; + } - const format = context.data.model.source.getAction(context.data.resultIndex, ResultSetFormatAction); - return ( - format.isReadOnly(context.data.key) - || editor.getElementState(context.data.key) === DatabaseEditChangeType.delete - ); - }, - onClick(context) { - const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); - editor.deleteRow(context.data.key.row); - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuEditingToken(), - { - id: 'row_delete_selected', - order: 6.1, - icon: '/icons/data_delete_sm.svg', - title: 'data_viewer_action_edit_delete', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); + const format = context.data.model.source.getAction(context.data.resultIndex, ResultSetFormatAction); + return format.isReadOnly(context.data.key) || editor.getElementState(context.data.key) === DatabaseEditChangeType.delete; + }, + onClick(context) { + const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); + editor.deleteRow(context.data.key.row); + }, + }); + this.dataGridContextMenuService.add(this.getMenuEditingToken(), { + id: 'row_delete_selected', + order: 6.1, + icon: '/icons/data_delete_sm.svg', + title: 'data_viewer_action_edit_delete', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); - if (context.data.model.isReadonly(context.data.resultIndex) || !editor.hasFeature('delete')) { - return true; - } + if (context.data.model.isReadonly(context.data.resultIndex) || !editor.hasFeature('delete')) { + return true; + } - const select = context.data.model.source.getActionImplementation( - context.data.resultIndex, - ResultSetSelectAction - ); + const select = context.data.model.source.getActionImplementation(context.data.resultIndex, ResultSetSelectAction); - const selectedElements = select?.getSelectedElements() || []; + const selectedElements = select?.getSelectedElements() || []; - return !selectedElements.some(key => editor.getElementState(key) !== DatabaseEditChangeType.delete); - }, - onClick(context) { - const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); - const select = context.data.model.source.getActionImplementation( - context.data.resultIndex, - ResultSetSelectAction - ); + return !selectedElements.some(key => editor.getElementState(key) !== DatabaseEditChangeType.delete); + }, + onClick(context) { + const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); + const select = context.data.model.source.getActionImplementation(context.data.resultIndex, ResultSetSelectAction); - const selectedElements = select?.getSelectedElements() || []; + const selectedElements = select?.getSelectedElements() || []; - editor.delete(...selectedElements); - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuEditingToken(), - { - id: 'row_revert', - order: 7, - icon: '/icons/data_revert_sm.svg', - title: 'data_grid_table_editing_row_revert', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); - return editor.getElementState(context.data.key) === null; - }, - onClick(context) { - const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); - editor.revert(context.data.key); - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuEditingToken(), - { - id: 'row_revert_selected', - order: 7.1, - icon: '/icons/data_revert_sm.svg', - title: 'data_viewer_action_edit_revert', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); - const select = context.data.model.source.getActionImplementation( - context.data.resultIndex, - ResultSetSelectAction - ); + editor.delete(...selectedElements); + }, + }); + this.dataGridContextMenuService.add(this.getMenuEditingToken(), { + id: 'row_revert', + order: 7, + icon: '/icons/data_revert_sm.svg', + title: 'data_grid_table_editing_row_revert', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); + return editor.getElementState(context.data.key) === null; + }, + onClick(context) { + const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); + editor.revert(context.data.key); + }, + }); + this.dataGridContextMenuService.add(this.getMenuEditingToken(), { + id: 'row_revert_selected', + order: 7.1, + icon: '/icons/data_revert_sm.svg', + title: 'data_viewer_action_edit_revert', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); + const select = context.data.model.source.getActionImplementation(context.data.resultIndex, ResultSetSelectAction); - const selectedElements = select?.getSelectedElements() || []; - return !selectedElements.some(key => editor.getElementState(key) !== null); - }, - onClick(context) { - const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); - const select = context.data.model.source.getActionImplementation( - context.data.resultIndex, - ResultSetSelectAction - ); + const selectedElements = select?.getSelectedElements() || []; + return !selectedElements.some(key => editor.getElementState(key) !== null); + }, + onClick(context) { + const editor = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction); + const select = context.data.model.source.getActionImplementation(context.data.resultIndex, ResultSetSelectAction); - const selectedElements = select?.getSelectedElements() || []; - editor.revert(...selectedElements); - }, - } - ); + const selectedElements = select?.getSelectedElements() || []; + editor.revert(...selectedElements); + }, + }); } } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuFilter/DataGridContextMenuFilterService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuFilter/DataGridContextMenuFilterService.ts index 195063e966..c74e9c1d6d 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuFilter/DataGridContextMenuFilterService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuFilter/DataGridContextMenuFilterService.ts @@ -5,24 +5,23 @@ * 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 { CommonDialogService, DialogueStateResult, IContextMenuItem, IMenuContext, ComputedContextMenuModel } from '@cloudbeaver/core-dialogs'; +import { CommonDialogService, ComputedContextMenuModel, DialogueStateResult, IContextMenuItem, IMenuContext } from '@cloudbeaver/core-dialogs'; import { ClipboardService } from '@cloudbeaver/core-ui'; import { replaceMiddle } from '@cloudbeaver/core-utils'; import { - wrapOperationArgument, IDatabaseDataModel, - nullOperationsFilter, - ResultSetConstraintAction, + IDatabaseDataOptions, + IDatabaseResultSet, + IResultSetColumnKey, IS_NOT_NULL_ID, IS_NULL_ID, - ResultSetDataAction, - IDatabaseResultSet, - IDatabaseDataOptions, - ResultSetFormatAction, isFilterConstraint, - IResultSetColumnKey + nullOperationsFilter, + ResultSetConstraintAction, + ResultSetDataAction, + ResultSetFormatAction, + wrapOperationArgument, } from '@cloudbeaver/plugin-data-viewer'; import { DataGridContextMenuService, IDataGridCellMenuContext } from '../DataGridContextMenuService'; @@ -115,331 +114,286 @@ export class DataGridContextMenuFilterService { } register(): void { - this.dataGridContextMenuService.add( - this.dataGridContextMenuService.getMenuToken(), - { - id: this.getMenuFilterToken(), - order: 2, - title: 'data_grid_table_filter', - icon: 'filter', - isPanel: true, - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - if (context.data.model.isDisabled(context.data.resultIndex)) { - return true; + this.dataGridContextMenuService.add(this.dataGridContextMenuService.getMenuToken(), { + id: this.getMenuFilterToken(), + order: 2, + title: 'data_grid_table_filter', + icon: 'filter', + isPanel: true, + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + if (context.data.model.isDisabled(context.data.resultIndex)) { + return true; + } + + const constraints = context.data.model.source.getAction(context.data.resultIndex, ResultSetConstraintAction); + return !constraints.supported; + }, + }); + this.dataGridContextMenuService.add(this.dataGridContextMenuService.getMenuToken(), { + id: 'deleteFiltersAndOrders', + order: 3, + title: 'data_grid_table_delete_filters_and_orders', + icon: 'erase', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + if (context.data.model.isDisabled(context.data.resultIndex)) { + return true; + } + + const constraints = context.data.model.source.getAction(context.data.resultIndex, ResultSetConstraintAction); + return constraints.orderConstraints.length === 0 && constraints.filterConstraints.length === 0; + }, + onClick: async context => { + const { model, resultIndex } = context.data; + const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); + + await model.requestDataAction(async () => { + constraints.deleteData(); + await model.request(true); + }); + }, + }); + this.dataGridContextMenuService.add(this.getMenuFilterToken(), { + id: 'clipboardValue', + order: 0, + title: 'ui_clipboard', + icon: 'filter-clipboard', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden: context => { + if (!this.clipboardService.clipboardAvailable || this.clipboardService.state === 'denied') { + return true; + } + + const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); + const supportedOperations = data.getColumnOperations(context.data.key.column); + + return supportedOperations.length === 0; + }, + panel: new ComputedContextMenuModel({ + id: 'clipboardValuePanel', + menuItemsGetter: context => { + if (context.contextType !== DataGridContextMenuService.cellContext) { + return []; } - const constraints = context.data.model.source.getAction(context.data.resultIndex, ResultSetConstraintAction); - return !constraints.supported; - }, - } - ); - this.dataGridContextMenuService.add( - this.dataGridContextMenuService.getMenuToken(), - { - id: 'deleteFiltersAndOrders', - order: 3, - title: 'data_grid_table_delete_filters_and_orders', - icon: 'erase', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - if (context.data.model.isDisabled(context.data.resultIndex)) { - return true; - } + const valueGetter = () => this.clipboardService.clipboardValue || ''; + const items = this.getGeneralizedMenuItems(context, valueGetter, 'filter-clipboard', () => this.clipboardService.state === 'prompt'); - const constraints = context.data.model.source.getAction(context.data.resultIndex, ResultSetConstraintAction); - return ( - constraints.orderConstraints.length === 0 - && constraints.filterConstraints.length === 0 - ); - }, - onClick: async context => { - const { model, resultIndex } = context.data; - const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); - - await model.requestDataAction(async () => { - constraints.deleteData(); - await model.request(true); - }); - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuFilterToken(), - { - id: 'clipboardValue', - order: 0, - title: 'ui_clipboard', - icon: 'filter-clipboard', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden: context => { - if (!this.clipboardService.clipboardAvailable || this.clipboardService.state === 'denied') { - return true; - } - - const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); - const supportedOperations = data.getColumnOperations(context.data.key.column); - - return supportedOperations.length === 0; - }, - panel: new ComputedContextMenuModel({ - id: 'clipboardValuePanel', - menuItemsGetter: context => { - if (context.contextType !== DataGridContextMenuService.cellContext) { - return []; - } - - const valueGetter = () => this.clipboardService.clipboardValue || ''; - const items = this.getGeneralizedMenuItems( - context, - valueGetter, - 'filter-clipboard', - () => this.clipboardService.state === 'prompt' - ); - - return [ - { - id: 'permission', - isPresent: () => true, - isHidden: () => this.clipboardService.state !== 'prompt', - isDisabled(context) { - return context.data.model.isLoading(); - }, - title: 'data_grid_table_context_menu_filter_clipboard_permission', - icon: 'permission', - onClick: async () => { - await this.clipboardService.read(); - }, + return [ + { + id: 'permission', + isPresent: () => true, + isHidden: () => this.clipboardService.state !== 'prompt', + isDisabled(context) { + return context.data.model.isLoading(); }, - ...items, - ]; - }, - }), - } - ); - this.dataGridContextMenuService.add( - this.getMenuFilterToken(), - { - id: 'cellValue', - order: 1, - title: 'data_grid_table_filter_cell_value', - icon: 'filter', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; + title: 'data_grid_table_context_menu_filter_clipboard_permission', + icon: 'permission', + onClick: async () => { + await this.clipboardService.read(); + }, + }, + ...items, + ]; }, - isHidden: context => { - const { model, resultIndex, key } = context.data; - const data = model.source.getAction(resultIndex, ResultSetDataAction); - const format = model.source.getAction(resultIndex, ResultSetFormatAction); - const supportedOperations = data.getColumnOperations(key.column); - const value = data.getCellValue(key); + }), + }); + this.dataGridContextMenuService.add(this.getMenuFilterToken(), { + id: 'cellValue', + order: 1, + title: 'data_grid_table_filter_cell_value', + icon: 'filter', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden: context => { + const { model, resultIndex, key } = context.data; + const data = model.source.getAction(resultIndex, ResultSetDataAction); + const format = model.source.getAction(resultIndex, ResultSetFormatAction); + const supportedOperations = data.getColumnOperations(key.column); + const value = data.getCellValue(key); - return value === undefined || supportedOperations.length === 0 || format.isNull(value); - }, - panel: new ComputedContextMenuModel({ - id: 'cellValuePanel', - menuItemsGetter: context => { - const { model, resultIndex, key } = context.data; - const data = model.source.getAction(resultIndex, ResultSetDataAction); - const cellValue = data.getCellValue(key); - const items = this.getGeneralizedMenuItems(context, cellValue, 'filter'); - return items; - }, - }), - } - ); - this.dataGridContextMenuService.add( - this.getMenuFilterToken(), - { - id: 'customValue', - order: 2, - title: 'data_grid_table_filter_custom_value', - icon: 'filter-custom', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden: context => { + return value === undefined || supportedOperations.length === 0 || format.isNull(value); + }, + panel: new ComputedContextMenuModel({ + id: 'cellValuePanel', + menuItemsGetter: context => { const { model, resultIndex, key } = context.data; const data = model.source.getAction(resultIndex, ResultSetDataAction); const cellValue = data.getCellValue(key); + const items = this.getGeneralizedMenuItems(context, cellValue, 'filter'); + return items; + }, + }), + }); + this.dataGridContextMenuService.add(this.getMenuFilterToken(), { + id: 'customValue', + order: 2, + title: 'data_grid_table_filter_custom_value', + icon: 'filter-custom', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden: context => { + const { model, resultIndex, key } = context.data; + const data = model.source.getAction(resultIndex, ResultSetDataAction); + const cellValue = data.getCellValue(key); + const supportedOperations = data.getColumnOperations(key.column); + + return cellValue === undefined || supportedOperations.length === 0; + }, + panel: new ComputedContextMenuModel({ + id: 'customValuePanel', + menuItemsGetter: context => { + const { model, resultIndex, key } = context.data; + const format = model.source.getAction(resultIndex, ResultSetFormatAction); + const data = model.source.getAction(resultIndex, ResultSetDataAction); const supportedOperations = data.getColumnOperations(key.column); + const cellValue = data.getCellValue(key) ?? ''; + const columnLabel = data.getColumn(key.column)?.label || ''; - return cellValue === undefined || supportedOperations.length === 0; - }, - panel: new ComputedContextMenuModel({ - id: 'customValuePanel', - menuItemsGetter: context => { - const { model, resultIndex, key } = context.data; - const format = model.source.getAction(resultIndex, ResultSetFormatAction); - const data = model.source.getAction(resultIndex, ResultSetDataAction); - const supportedOperations = data.getColumnOperations(key.column); - const cellValue = data.getCellValue(key) ?? ''; - const columnLabel = data.getColumn(key.column)?.label || ''; + return supportedOperations + .filter(operation => !nullOperationsFilter(operation)) + .map(operation => { + const title = `${columnLabel} ${operation.expression}`; - return supportedOperations - .filter(operation => !nullOperationsFilter(operation)) - .map(operation => { - const title = `${columnLabel} ${operation.expression}`; + return { + id: operation.id, + isPresent: () => true, + isDisabled(context) { + return context.data.model.isLoading(); + }, + title: title + ' ..', + icon: 'filter-custom', + onClick: async () => { + const stringifyCellValue = format.toDisplayString(cellValue); + const customValue = await this.commonDialogService.open(FilterCustomValueDialog, { + defaultValue: stringifyCellValue, + inputTitle: title + ':', + }); - return { - id: operation.id, - isPresent: () => true, - isDisabled(context) { - return context.data.model.isLoading(); - }, - title: title + ' ..', - icon: 'filter-custom', - onClick: async () => { - const stringifyCellValue = format.toDisplayString(cellValue); - const customValue = await this.commonDialogService.open( - FilterCustomValueDialog, - { - defaultValue: stringifyCellValue, - inputTitle: title + ':', - } - ); + if (customValue === DialogueStateResult.Rejected || customValue === DialogueStateResult.Resolved) { + return; + } - if (customValue === DialogueStateResult.Rejected || customValue === DialogueStateResult.Resolved) { - return; - } + await this.applyFilter(model, resultIndex, key.column, operation.id, customValue); + }, + }; + }); + }, + }), + }); + this.dataGridContextMenuService.add(this.getMenuFilterToken(), { + id: 'isNullValue', + order: 3, + icon: 'filter', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden: context => { + const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); + const supportedOperations = data.getColumnOperations(context.data.key.column); - await this.applyFilter( - model, - resultIndex, - key.column, - operation.id, - customValue - ); - }, - }; - }); - }, - }), - } - ); - this.dataGridContextMenuService.add( - this.getMenuFilterToken(), - { - id: 'isNullValue', - order: 3, - icon: 'filter', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden: context => { - const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); - const supportedOperations = data.getColumnOperations(context.data.key.column); + return !supportedOperations.some(operation => operation.id === IS_NULL_ID); + }, + titleGetter: context => { + const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); + const columnLabel = data.getColumn(context.data.key.column)?.label || ''; + return `${columnLabel} IS NULL`; + }, + onClick: async context => { + await this.applyFilter(context.data.model, context.data.resultIndex, context.data.key.column, IS_NULL_ID); + }, + }); + this.dataGridContextMenuService.add(this.getMenuFilterToken(), { + id: 'isNotNullValue', + order: 4, + icon: 'filter', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden: context => { + const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); + const supportedOperations = data.getColumnOperations(context.data.key.column); - return !supportedOperations.some(operation => operation.id === IS_NULL_ID); - }, - titleGetter: context => { - const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); - const columnLabel = data.getColumn(context.data.key.column)?.label || ''; - return `${columnLabel} IS NULL`; - }, - onClick: async context => { - await this.applyFilter(context.data.model, context.data.resultIndex, context.data.key.column, IS_NULL_ID); - }, + return !supportedOperations.some(operation => operation.id === IS_NOT_NULL_ID); + }, + titleGetter: context => { + const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); + const columnLabel = data.getColumn(context.data.key.column)?.label || ''; + return `${columnLabel} IS NOT NULL`; + }, + onClick: async context => { + await this.applyFilter(context.data.model, context.data.resultIndex, context.data.key.column, IS_NOT_NULL_ID); + }, + }); + this.dataGridContextMenuService.add(this.getMenuFilterToken(), { + id: 'deleteFilter', + order: 5, + icon: 'filter-reset', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden: context => { + const { model, resultIndex, key } = context.data; + const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); + const data = model.source.getAction(resultIndex, ResultSetDataAction); + const resultColumn = data.getColumn(key.column); + const currentConstraint = resultColumn ? constraints.get(resultColumn.position) : undefined; - } - ); - this.dataGridContextMenuService.add( - this.getMenuFilterToken(), - { - id: 'isNotNullValue', - order: 4, - icon: 'filter', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden: context => { - const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); - const supportedOperations = data.getColumnOperations(context.data.key.column); + return !currentConstraint || !isFilterConstraint(currentConstraint); + }, + titleGetter: context => { + const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); + const columnLabel = data.getColumn(context.data.key.column)?.name || ''; + return `Delete filter for ${columnLabel}`; + }, + onClick: async context => { + const { model, resultIndex, key } = context.data; + const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); + const data = model.source.getAction(resultIndex, ResultSetDataAction); + const resultColumn = data.getColumn(key.column); - return !supportedOperations.some(operation => operation.id === IS_NOT_NULL_ID); - }, - titleGetter: context => { - const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); - const columnLabel = data.getColumn(context.data.key.column)?.label || ''; - return `${columnLabel} IS NOT NULL`; - }, - onClick: async context => { - await this.applyFilter(context.data.model, context.data.resultIndex, context.data.key.column, IS_NOT_NULL_ID); - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuFilterToken(), - { - id: 'deleteFilter', - order: 5, - icon: 'filter-reset', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden: context => { - const { model, resultIndex, key } = context.data; - const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); - const data = model.source.getAction(resultIndex, ResultSetDataAction); - const resultColumn = data.getColumn(key.column); - const currentConstraint = resultColumn ? constraints.get(resultColumn.position) : undefined; + if (!resultColumn) { + throw new Error(`Failed to get result column info for the following column index: "${key.column.index}"`); + } - return !currentConstraint || !isFilterConstraint(currentConstraint); - }, - titleGetter: context => { - const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); - const columnLabel = data.getColumn(context.data.key.column)?.name || ''; - return `Delete filter for ${columnLabel}`; - }, - onClick: async context => { - const { model, resultIndex, key } = context.data; - const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); - const data = model.source.getAction(resultIndex, ResultSetDataAction); - const resultColumn = data.getColumn(key.column); + await model.requestDataAction(async () => { + constraints.deleteFilter(resultColumn.position); + await model.request(true); + }); + }, + }); + this.dataGridContextMenuService.add(this.getMenuFilterToken(), { + id: 'deleteAllFilters', + order: 6, + icon: 'filter-reset-all', + title: 'data_grid_table_filter_reset_all_filters', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden: context => { + const { model, resultIndex } = context.data; + const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); - if (!resultColumn) { - throw new Error(`Failed to get result column info for the following column index: "${key.column.index}"`); - } + return constraints.filterConstraints.length === 0 && !model.requestInfo.requestFilter; + }, + onClick: async context => { + const { model, resultIndex } = context.data; + const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); - await model.requestDataAction(async () => { - constraints.deleteFilter(resultColumn.position); - await model.request(true); - }); - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuFilterToken(), - { - id: 'deleteAllFilters', - order: 6, - icon: 'filter-reset-all', - title: 'data_grid_table_filter_reset_all_filters', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden: context => { - const { model, resultIndex } = context.data; - const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); - - return constraints.filterConstraints.length === 0 && !model.requestInfo.requestFilter; - }, - onClick: async context => { - const { model, resultIndex } = context.data; - const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); - - await model.requestDataAction(async () => { - constraints.deleteDataFilters(); - await model.request(true); - }); - }, - } - ); + await model.requestDataAction(async () => { + constraints.deleteDataFilters(); + await model.request(true); + }); + }, + }); } } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuFilter/FilterCustomValueDialog.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuFilter/FilterCustomValueDialog.tsx index 147a17bc55..7bdf97a47d 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuFilter/FilterCustomValueDialog.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuFilter/FilterCustomValueDialog.tsx @@ -5,14 +5,20 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import { useState, useCallback, useRef, useEffect } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import styled, { css } from 'reshadow'; import { Button, InputField, useTranslate } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; -import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent, DialogComponentProps } from '@cloudbeaver/core-dialogs'; +import { + CommonDialogBody, + CommonDialogFooter, + CommonDialogHeader, + CommonDialogWrapper, + DialogComponent, + DialogComponentProps, +} from '@cloudbeaver/core-dialogs'; import { ClipboardService } from '@cloudbeaver/core-ui'; export const dialogStyle = css` @@ -28,60 +34,53 @@ interface IPayload { defaultValue: string | number; } -export const FilterCustomValueDialog: DialogComponent = observer( - function FilterCustomValueDialog({ - payload, - resolveDialog, - rejectDialog, - }: DialogComponentProps) { - const clipboardService = useService(ClipboardService); - const inputRef = useRef(null); +export const FilterCustomValueDialog: DialogComponent = observer(function FilterCustomValueDialog({ + payload, + resolveDialog, + rejectDialog, +}: DialogComponentProps) { + const clipboardService = useService(ClipboardService); + const inputRef = useRef(null); - const [value, setValue] = useState(payload.defaultValue); - const handleApply = useCallback(() => resolveDialog(value), [value, resolveDialog]); - const translate = useTranslate(); + const [value, setValue] = useState(payload.defaultValue); + const handleApply = useCallback(() => resolveDialog(value), [value, resolveDialog]); + const translate = useTranslate(); - const getValueFromClipboard = useCallback(async () => { - const value = await clipboardService.read(); - if (value) { - setValue(value); - } - if (inputRef.current) { - inputRef.current.focus(); - } - }, [clipboardService]); + const getValueFromClipboard = useCallback(async () => { + const value = await clipboardService.read(); + if (value) { + setValue(value); + } + if (inputRef.current) { + inputRef.current.focus(); + } + }, [clipboardService]); - useEffect(() => { - inputRef.current?.focus(); - }, []); + useEffect(() => { + inputRef.current?.focus(); + }, []); - return styled(dialogStyle)( - - - - - {payload.inputTitle} - - - - {clipboardService.clipboardAvailable && clipboardService.state !== 'denied' && ( - - )} - - - - - ); - } -); + )} + + + + , + ); +}); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuOrderService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuOrderService.ts index 290b61f77c..4f24ca586b 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuOrderService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuOrderService.ts @@ -5,9 +5,15 @@ * 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 { EOrder, IDatabaseDataModel, ResultSetConstraintAction, ResultSetDataAction, Order, IResultSetColumnKey } from '@cloudbeaver/plugin-data-viewer'; +import { + EOrder, + IDatabaseDataModel, + IResultSetColumnKey, + Order, + ResultSetConstraintAction, + ResultSetDataAction, +} from '@cloudbeaver/plugin-data-viewer'; import { DataGridContextMenuService } from './DataGridContextMenuService'; @@ -15,20 +21,13 @@ import { DataGridContextMenuService } from './DataGridContextMenuService'; export class DataGridContextMenuOrderService { private static readonly menuOrderToken = 'menuOrder'; - constructor( - private readonly dataGridContextMenuService: DataGridContextMenuService, - ) { } + constructor(private readonly dataGridContextMenuService: DataGridContextMenuService) {} getMenuOrderToken(): string { return DataGridContextMenuOrderService.menuOrderToken; } - private async changeOrder( - model: IDatabaseDataModel, - resultIndex: number, - column: IResultSetColumnKey, - order: Order - ) { + private async changeOrder(model: IDatabaseDataModel, resultIndex: number, column: IResultSetColumnKey, order: Order) { const data = model.source.getAction(resultIndex, ResultSetDataAction); const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); const resultColumn = data.getColumn(column); @@ -44,113 +43,98 @@ export class DataGridContextMenuOrderService { } register(): void { - this.dataGridContextMenuService.add( - this.dataGridContextMenuService.getMenuToken(), - { - id: this.getMenuOrderToken(), - order: 1, - title: 'data_grid_table_order', - icon: 'order-arrow-unknown', - isPanel: true, - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - const constraints = context.data.model.source.getAction(context.data.resultIndex, ResultSetConstraintAction); - return !constraints.supported || context.data.model.isDisabled(context.data.resultIndex); - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuOrderToken(), - { - id: 'asc', - type: 'radio', - title: 'ASC', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isDisabled: context => context.data.model.isLoading(), - onClick: async context => { - await this.changeOrder(context.data.model, context.data.resultIndex, context.data.key.column, EOrder.asc); - }, - isChecked: context => { - const { model, resultIndex, key } = context.data; - const data = model.source.getAction(resultIndex, ResultSetDataAction); - const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); - const resultColumn = data.getColumn(key.column); + this.dataGridContextMenuService.add(this.dataGridContextMenuService.getMenuToken(), { + id: this.getMenuOrderToken(), + order: 1, + title: 'data_grid_table_order', + icon: 'order-arrow-unknown', + isPanel: true, + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + const constraints = context.data.model.source.getAction(context.data.resultIndex, ResultSetConstraintAction); + return !constraints.supported || context.data.model.isDisabled(context.data.resultIndex); + }, + }); + this.dataGridContextMenuService.add(this.getMenuOrderToken(), { + id: 'asc', + type: 'radio', + title: 'ASC', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isDisabled: context => context.data.model.isLoading(), + onClick: async context => { + await this.changeOrder(context.data.model, context.data.resultIndex, context.data.key.column, EOrder.asc); + }, + isChecked: context => { + const { model, resultIndex, key } = context.data; + const data = model.source.getAction(resultIndex, ResultSetDataAction); + const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); + const resultColumn = data.getColumn(key.column); - return !!resultColumn && constraints.getOrder(resultColumn.position) === EOrder.asc; - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuOrderToken(), - { - id: 'desc', - type: 'radio', - title: 'DESC', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isDisabled: context => context.data.model.isLoading(), - onClick: async context => { - await this.changeOrder(context.data.model, context.data.resultIndex, context.data.key.column, EOrder.desc); - }, - isChecked: context => { - const { model, resultIndex, key } = context.data; - const data = model.source.getAction(resultIndex, ResultSetDataAction); - const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); - const resultColumn = data.getColumn(key.column); + return !!resultColumn && constraints.getOrder(resultColumn.position) === EOrder.asc; + }, + }); + this.dataGridContextMenuService.add(this.getMenuOrderToken(), { + id: 'desc', + type: 'radio', + title: 'DESC', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isDisabled: context => context.data.model.isLoading(), + onClick: async context => { + await this.changeOrder(context.data.model, context.data.resultIndex, context.data.key.column, EOrder.desc); + }, + isChecked: context => { + const { model, resultIndex, key } = context.data; + const data = model.source.getAction(resultIndex, ResultSetDataAction); + const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); + const resultColumn = data.getColumn(key.column); - return !!resultColumn && constraints.getOrder(resultColumn.position) === EOrder.desc; - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuOrderToken(), - { - id: 'disableOrder', - type: 'radio', - title: 'data_grid_table_disable_order', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isDisabled: context => context.data.model.isLoading(), - onClick: async context => { - await this.changeOrder(context.data.model, context.data.resultIndex, context.data.key.column, null); - }, - isChecked: context => { - const { model, resultIndex, key } = context.data; - const data = model.source.getAction(resultIndex, ResultSetDataAction); - const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); - const resultColumn = data.getColumn(key.column); + return !!resultColumn && constraints.getOrder(resultColumn.position) === EOrder.desc; + }, + }); + this.dataGridContextMenuService.add(this.getMenuOrderToken(), { + id: 'disableOrder', + type: 'radio', + title: 'data_grid_table_disable_order', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isDisabled: context => context.data.model.isLoading(), + onClick: async context => { + await this.changeOrder(context.data.model, context.data.resultIndex, context.data.key.column, null); + }, + isChecked: context => { + const { model, resultIndex, key } = context.data; + const data = model.source.getAction(resultIndex, ResultSetDataAction); + const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); + const resultColumn = data.getColumn(key.column); - return !!resultColumn && constraints.getOrder(resultColumn.position) === null; - }, - } - ); - this.dataGridContextMenuService.add( - this.getMenuOrderToken(), - { - id: 'disableOrders', - title: 'data_grid_table_disable_all_orders', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden: context => { - const constraints = context.data.model.source.getAction(context.data.resultIndex, ResultSetConstraintAction); - return !constraints.orderConstraints.length; - }, - isDisabled: context => context.data.model.isLoading(), - onClick: async context => { - const constraints = context.data.model.source.getAction(context.data.resultIndex, ResultSetConstraintAction); - await context.data.model.requestDataAction(async () => { - constraints.deleteOrders(); - await context.data.model.request(true); - }); - }, - } - ); + return !!resultColumn && constraints.getOrder(resultColumn.position) === null; + }, + }); + this.dataGridContextMenuService.add(this.getMenuOrderToken(), { + id: 'disableOrders', + title: 'data_grid_table_disable_all_orders', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden: context => { + const constraints = context.data.model.source.getAction(context.data.resultIndex, ResultSetConstraintAction); + return !constraints.orderConstraints.length; + }, + isDisabled: context => context.data.model.isLoading(), + onClick: async context => { + const constraints = context.data.model.source.getAction(context.data.resultIndex, ResultSetConstraintAction); + await context.data.model.requestDataAction(async () => { + constraints.deleteOrders(); + await context.data.model.request(true); + }); + }, + }); } } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuSaveContentService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuSaveContentService.ts index 8d66bda091..616af6741b 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuSaveContentService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuSaveContentService.ts @@ -5,7 +5,6 @@ * 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 { NotificationService } from '@cloudbeaver/core-events'; import { ResultSetDataContentAction, ResultSetDataKeysUtils } from '@cloudbeaver/plugin-data-viewer'; @@ -16,48 +15,41 @@ import { DataGridContextMenuService } from './DataGridContextMenuService'; export class DataGridContextMenuSaveContentService { private static readonly menuContentSaveToken = 'menuContentSave'; - constructor( - private readonly dataGridContextMenuService: DataGridContextMenuService, - private readonly notificationService: NotificationService - ) { } + constructor(private readonly dataGridContextMenuService: DataGridContextMenuService, private readonly notificationService: NotificationService) {} getMenuContentSaveToken(): string { return DataGridContextMenuSaveContentService.menuContentSaveToken; } register(): void { - this.dataGridContextMenuService.add( - this.dataGridContextMenuService.getMenuToken(), - { - id: this.getMenuContentSaveToken(), - order: 4, - title: 'ui_download', - icon: '/icons/export.svg', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - onClick: async context => { - const content = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataContentAction); - try { - await content.downloadFileData(context.data.key); - } catch (exception: any) { - this.notificationService.logException(exception, 'data_grid_table_context_menu_save_value_error'); - } - }, - isHidden: context => { - const content = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataContentAction); - return !content.isDownloadable(context.data.key); - }, - isDisabled: context => { - const content = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataContentAction); + this.dataGridContextMenuService.add(this.dataGridContextMenuService.getMenuToken(), { + id: this.getMenuContentSaveToken(), + order: 4, + title: 'ui_download', + icon: '/icons/export.svg', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + onClick: async context => { + const content = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataContentAction); + try { + await content.downloadFileData(context.data.key); + } catch (exception: any) { + this.notificationService.logException(exception, 'data_grid_table_context_menu_save_value_error'); + } + }, + isHidden: context => { + const content = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataContentAction); + return !content.isDownloadable(context.data.key); + }, + isDisabled: context => { + const content = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataContentAction); - return context.data.model.isLoading() || ( - !!content.activeElement && ResultSetDataKeysUtils.isElementsKeyEqual( - context.data.key, content.activeElement - ) - ); - }, - } - ); + return ( + context.data.model.isLoading() || + (!!content.activeElement && ResultSetDataKeysUtils.isElementsKeyEqual(context.data.key, content.activeElement)) + ); + }, + }); } } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuService.ts index af3241319b..408de50586 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuService.ts @@ -5,7 +5,6 @@ * 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 { ContextMenuService, IContextMenuItem, IMenuPanel } from '@cloudbeaver/core-dialogs'; import { Executor, IExecutor } from '@cloudbeaver/core-executor'; @@ -26,9 +25,7 @@ export class DataGridContextMenuService { static cellContext = 'data-grid-cell-context-menu'; private static readonly menuToken = 'dataGridCell'; - constructor( - private readonly contextMenuService: ContextMenuService, - ) { + constructor(private readonly contextMenuService: ContextMenuService) { this.onRootMenuOpen = new Executor(); } @@ -42,13 +39,16 @@ export class DataGridContextMenuService { spreadsheetActions: IDataPresentationActions, resultIndex: number, key: IResultSetElementKey, - simple: boolean + simple: boolean, ): IMenuPanel { - return this.contextMenuService.createContextMenu({ - menuId: this.getMenuToken(), - contextType: DataGridContextMenuService.cellContext, - data: { model, actions, spreadsheetActions, resultIndex, key, simple }, - }, this.getMenuToken()); + return this.contextMenuService.createContextMenu( + { + menuId: this.getMenuToken(), + contextType: DataGridContextMenuService.cellContext, + data: { model, actions, spreadsheetActions, resultIndex, key, simple }, + }, + this.getMenuToken(), + ); } openMenu( @@ -57,7 +57,7 @@ export class DataGridContextMenuService { spreadsheetActions: IDataPresentationActions, resultIndex: number, key: IResultSetElementKey, - simple: boolean + simple: boolean, ): void { this.onRootMenuOpen.execute({ model, actions, spreadsheetActions, resultIndex, key, simple }); } @@ -66,5 +66,5 @@ export class DataGridContextMenuService { this.contextMenuService.addMenuItem(panelId, menuItem); } - register(): void { } + register(): void {} } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridLoader.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridLoader.tsx index db1eb96ed8..f8f42c12cb 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridLoader.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridLoader.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { ComplexLoader, createComplexLoader } from '@cloudbeaver/core-blocks'; import type { IDataPresentationProps } from '@cloudbeaver/plugin-data-viewer'; @@ -15,11 +14,5 @@ const loader = createComplexLoader(async function loader() { }); export const DataGridLoader: React.FC = function DataGridLoader(props) { - return ( - - {({ DataGridTable }) => ( - - )} - - ); + return {({ DataGridTable }) => }; }; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridSelection/DataGridSelectionContext.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridSelection/DataGridSelectionContext.ts index 9fe354d8c6..3e19ee5f8b 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridSelection/DataGridSelectionContext.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridSelection/DataGridSelectionContext.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createContext } from 'react'; import type { IResultSetElementKey } from '@cloudbeaver/plugin-data-viewer'; @@ -18,12 +17,7 @@ export interface IDataGridSelectionContext { selectColumn: (colIdx: number, multiple: boolean) => void; selectTable: () => void; isSelected: (rowIdx: number, colIdx: number) => boolean; - selectRange: ( - startPosition: IDraggingPosition, - lastPosition: IDraggingPosition, - multiple: boolean, - temporary: boolean - ) => void; + selectRange: (startPosition: IDraggingPosition, lastPosition: IDraggingPosition, multiple: boolean, temporary: boolean) => void; } export const DataGridSelectionContext = createContext(undefined as any); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridSelection/useGridSelectionContext.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridSelection/useGridSelectionContext.tsx index 94b22cccf5..b89afee0ab 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridSelection/useGridSelectionContext.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridSelection/useGridSelectionContext.tsx @@ -5,12 +5,17 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, observable } from 'mobx'; import { useState } from 'react'; import { useObjectRef } from '@cloudbeaver/core-blocks'; -import { IResultSetColumnKey, IResultSetElementKey, IResultSetRowKey, ResultSetDataKeysUtils, ResultSetSelectAction } from '@cloudbeaver/plugin-data-viewer'; +import { + IResultSetColumnKey, + IResultSetElementKey, + IResultSetRowKey, + ResultSetDataKeysUtils, + ResultSetSelectAction, +} from '@cloudbeaver/plugin-data-viewer'; import type { ITableData } from '../TableDataContext'; import type { IDraggingPosition } from '../useGridDragging'; @@ -22,24 +27,23 @@ interface IGridSelectionState { lastSelectedCell: IDraggingPosition | null; } -export function useGridSelectionContext( - tableData: ITableData, - selectionAction: ResultSetSelectAction -): IDataGridSelectionContext { +export function useGridSelectionContext(tableData: ITableData, selectionAction: ResultSetSelectAction): IDataGridSelectionContext { const props = useObjectRef({ tableData, selectionAction }); - const [state] = useState(() => observable({ - range: false, - temporarySelection: new Map(), - lastSelectedCell: null, - })); + const [state] = useState(() => + observable({ + range: false, + temporarySelection: new Map(), + lastSelectedCell: null, + }), + ); const selectRows = action(function selectRows( startRow: IResultSetRowKey, lastRow: IResultSetRowKey, columns: IResultSetColumnKey[] = [], multiple = false, - temporary = false + temporary = false, ) { const { selectionAction } = props; const { temporarySelection } = state; @@ -88,20 +92,18 @@ export function useGridSelectionContext( for (let rowIdx = firstRowIndex; rowIdx <= lastRowIndex; rowIdx++) { const row = props.tableData.getRow(rowIdx)!; const newElements = rowSelection - .filter( - element => !rowsSelection[i] - .some(column => ResultSetDataKeysUtils.isEqual(column.column, element)) - ) + .filter(element => !rowsSelection[i].some(column => ResultSetDataKeysUtils.isEqual(column.column, element))) .map(column => ({ row, column })); - temporarySelection.set(ResultSetDataKeysUtils.serialize(row), - [...rowsSelection[i], ...newElements] - .filter(column => { - if (selected) { - return !rowSelection.some(key => ResultSetDataKeysUtils.isEqual(key, column.column)); - } - return true; - })); + temporarySelection.set( + ResultSetDataKeysUtils.serialize(row), + [...rowsSelection[i], ...newElements].filter(column => { + if (selected) { + return !rowSelection.some(key => ResultSetDataKeysUtils.isEqual(key, column.column)); + } + return true; + }), + ); i++; } return; @@ -116,12 +118,7 @@ export function useGridSelectionContext( } }); - function selectRange( - startPosition: IDraggingPosition, - lastPosition: IDraggingPosition, - multiple: boolean, - temporary = false - ) { + function selectRange(startPosition: IDraggingPosition, lastPosition: IDraggingPosition, multiple: boolean, temporary = false) { state.range = temporary; const columnsInRange = props.tableData.getColumnsInRange(startPosition.colIdx, lastPosition.colIdx); const isIndexColumnInRange = props.tableData.isIndexColumnInRange(columnsInRange); @@ -132,28 +129,19 @@ export function useGridSelectionContext( selectRows( startRow, lastRow, - isIndexColumnInRange - ? undefined - : (columnsInRange - .filter(column => column.columnDataIndex !== null) - .map(column => column.columnDataIndex!)), + isIndexColumnInRange ? undefined : columnsInRange.filter(column => column.columnDataIndex !== null).map(column => column.columnDataIndex!), multiple, - temporary + temporary, ); } } - const selectColumn = action(function selectColumn( - colIdx: number, - multiple: boolean - ) { + const selectColumn = action(function selectColumn(colIdx: number, multiple: boolean) { const { selectionAction, tableData } = props; state.temporarySelection.clear(); - const column = tableData - .getColumn(colIdx) - ?.columnDataIndex ?? undefined; + const column = tableData.getColumn(colIdx)?.columnDataIndex ?? undefined; const selected = selectionAction.isElementSelected({ column }); @@ -170,9 +158,7 @@ export function useGridSelectionContext( } function isSelected(rowIdx: number, colIdx: number) { - const column = props.tableData - .getColumn(colIdx) - ?.columnDataIndex ?? undefined; + const column = props.tableData.getColumn(colIdx)?.columnDataIndex ?? undefined; const row = props.tableData.getRow(rowIdx); @@ -252,14 +238,17 @@ export function useGridSelectionContext( } } - return useObjectRef(() => ({ - get selectedCells() { - return props.selectionAction.selectedElements; - }, - select, - selectColumn, - selectTable, - isSelected, - selectRange, - }), false); + return useObjectRef( + () => ({ + get selectedCells() { + return props.selectionAction.selectedElements; + }, + select, + selectColumn, + selectTable, + isSelected, + selectRange, + }), + false, + ); } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridTable.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridTable.tsx index 520e175900..73a4120164 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridTable.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridTable.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import styled from 'reshadow'; @@ -16,8 +15,15 @@ import { EventContext, EventStopPropagationFlag } from '@cloudbeaver/core-events import { Executor } from '@cloudbeaver/core-executor'; import { ClipboardService } from '@cloudbeaver/core-ui'; import { - DatabaseDataSelectActionsData, DatabaseEditChangeType, IDatabaseResultSet, IDataPresentationProps, - IResultSetEditActionData, IResultSetElementKey, IResultSetPartialKey, ResultSetDataKeysUtils, ResultSetSelectAction + DatabaseDataSelectActionsData, + DatabaseEditChangeType, + IDatabaseResultSet, + IDataPresentationProps, + IResultSetEditActionData, + IResultSetElementKey, + IResultSetPartialKey, + ResultSetDataKeysUtils, + ResultSetSelectAction, } from '@cloudbeaver/plugin-data-viewer'; import type { DataGridHandle, Position } from '@cloudbeaver/plugin-react-data-grid'; import DataGrid from '@cloudbeaver/plugin-react-data-grid'; @@ -49,7 +55,13 @@ function isAtBottom(event: React.UIEvent): boolean { const rowHeight = 25; const headerHeight = 28; -export const DataGridTable = observer>(function DataGridTable({ model, actions, resultIndex, simple, className }) { +export const DataGridTable = observer>(function DataGridTable({ + model, + actions, + resultIndex, + simple, + className, +}) { const translate = useTranslate(); const clipboardService = useService(ClipboardService); @@ -57,10 +69,13 @@ export const DataGridTable = observer(null); const dataGridDivRef = useRef(null); const dataGridRef = useRef(null); - const innerState = useObjectRef(() => ({ - lastCount: 0, - lastScrollTop: 0, - }), false); + const innerState = useObjectRef( + () => ({ + lastCount: 0, + lastScrollTop: 0, + }), + false, + ); const styles = useStyles(reactGridStyles, baseStyles); const [columnResize] = useState(() => new Executor()); @@ -145,11 +160,7 @@ export const DataGridTable = observer ({ selectCell(pos: Position, scroll = false): void { - if ( - dataGridRef.current?.selectedCell.idx !== pos.idx - || dataGridRef.current.selectedCell.rowIdx !== pos.rowIdx - || scroll - ) { + if (dataGridRef.current?.selectedCell.idx !== pos.idx || dataGridRef.current.selectedCell.rowIdx !== pos.rowIdx || scroll) { dataGridRef.current?.selectCell(pos); } }, @@ -212,8 +223,7 @@ export const DataGridTable = observer tableData.editor.getElementState(cell) !== DatabaseEditChangeType.delete); + const filteredRows = activeRows.filter(cell => tableData.editor.getElementState(cell) !== DatabaseEditChangeType.delete); if (filteredRows.length > 0) { const editor = tableData.editor; @@ -264,12 +274,7 @@ export const DataGridTable = observer { function syncEditor(data: IResultSetEditActionData) { const editor = tableData.editor; - if ( - data.resultId !== editor.result.id - || !data.value - || data.value.length === 0 - || data.type === DatabaseEditChangeType.delete - ) { + if (data.resultId !== editor.result.id || !data.value || data.value.length === 0 || data.type === DatabaseEditChangeType.delete) { return; } @@ -310,7 +315,8 @@ export const DataGridTable = observer) { - setTimeout(() => { // TODO: update focus after render rows update + setTimeout(() => { + // TODO: update focus after render rows update if (data.type === 'focus') { if (!data.key?.column || !data.key.row) { return; @@ -337,9 +343,9 @@ export const DataGridTable = observer model.source.count - && model.source.count * rowHeight < gridDiv.scrollTop + gridDiv.clientHeight - headerHeight + gridDiv && + innerState.lastCount > model.source.count && + model.source.count * rowHeight < gridDiv.scrollTop + gridDiv.clientHeight - headerHeight ) { gridDiv.scrollTo({ top: model.source.count * rowHeight - gridDiv.clientHeight + headerHeight - 1, @@ -350,11 +356,7 @@ export const DataGridTable = observer { - if ( - focusSyncRef.current - && focusSyncRef.current.idx === position.idx - && focusSyncRef.current.rowIdx === position.rowIdx - ) { + if (focusSyncRef.current && focusSyncRef.current.idx === position.idx && focusSyncRef.current.rowIdx === position.rowIdx) { focusSyncRef.current = null; return; } @@ -388,20 +390,23 @@ export const DataGridTable = observer(() => ({ - model, - actions, - columnResize, - resultIndex, - simple, - isGridInFocus, - getEditorPortal: () => editorRef.current, - getDataGridApi: () => dataGridRef.current, - focus: restoreFocus, - }), [model, actions, resultIndex, simple, editorRef, dataGridRef, gridContainerRef, restoreFocus]); + const gridContext = useMemo( + () => ({ + model, + actions, + columnResize, + resultIndex, + simple, + isGridInFocus, + getEditorPortal: () => editorRef.current, + getDataGridApi: () => dataGridRef.current, + focus: restoreFocus, + }), + [model, actions, resultIndex, simple, editorRef, dataGridRef, gridContainerRef, restoreFocus], + ); if (!tableData.columns.length) { return {translate('data_grid_table_empty_placeholder')}; @@ -445,6 +450,6 @@ export const DataGridTable = observer - + , ); }); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.tsx index 60c669b956..ff32574560 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useContext, useState } from 'react'; import styled, { css } from 'reshadow'; @@ -51,11 +50,7 @@ export const CellFormatter = observer(function CellFormatter({ className, const editingContext = useContext(EditingContext); const [menuVisible, setMenuVisible] = useState(false); const isEditing = cellContext.isEditing; - const showCellMenu = getComputed(() => !isEditing && ( - rest.isCellSelected - || cellContext.mouse.state.mouseEnter - || menuVisible - )); + const showCellMenu = getComputed(() => !isEditing && (rest.isCellSelected || cellContext.mouse.state.mouseEnter || menuVisible)); const spreadsheetActions = useObjectRef>({ edit(position) { @@ -73,7 +68,7 @@ export const CellFormatter = observer(function CellFormatter({ className, - {showCellMenu && cellContext.cell && !rest.isScrolling && ( + {showCellMenu && cellContext.cell && !rest.isScrolling && ( (function CellFormatter({ className, /> )} - + , ); }); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatterFactory.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatterFactory.tsx index 9e43fb9579..b0951a4d52 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatterFactory.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatterFactory.tsx @@ -5,14 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useContext, useRef } from 'react'; import { IResultSetRowKey, isBooleanValuePresentationAvailable } from '@cloudbeaver/plugin-data-viewer'; import type { FormatterProps } from '@cloudbeaver/plugin-react-data-grid'; - import { CellContext } from '../CellRenderer/CellContext'; import { TableDataContext } from '../TableDataContext'; import { BooleanFormatter } from './CellFormatters/BooleanFormatter'; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/BooleanFormatter.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/BooleanFormatter.tsx index 5220440787..3089039b9d 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/BooleanFormatter.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/BooleanFormatter.tsx @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useContext, useMemo } from 'react'; -import styled, { use, css } from 'reshadow'; +import styled, { css, use } from 'reshadow'; import type { IResultSetRowKey } from '@cloudbeaver/plugin-data-viewer'; import type { FormatterProps } from '@cloudbeaver/plugin-react-data-grid'; @@ -47,16 +46,12 @@ export const BooleanFormatter = observer>(funct const formatter = tableDataContext.format; const rawValue = useMemo( () => computed(() => formatter.get(tableDataContext.getCellValue(cellContext!.cell!)!)), - [tableDataContext, cellContext.cell, formatter] + [tableDataContext, cellContext.cell, formatter], ).get(); const value = typeof rawValue === 'string' ? rawValue.toLowerCase() === 'true' : rawValue; const stringifiedValue = formatter.toDisplayString(value); const valueRepresentation = value === null ? stringifiedValue : `[${value ? 'v' : ' '}]`; - const disabled = ( - !column.editable - || editingContext.readonly - || formatter.isReadOnly(cellContext.cell) - ); + const disabled = !column.editable || editingContext.readonly || formatter.isReadOnly(cellContext.cell); function toggleValue() { if (disabled || !tableDataContext || !cellContext.cell) { @@ -76,12 +71,12 @@ export const BooleanFormatter = observer>(funct return styled(styles)( {valueRepresentation} - + , ); }); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/TextFormatter.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/TextFormatter.tsx index 2f884f7482..d7635f5f7c 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/TextFormatter.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/TextFormatter.tsx @@ -5,11 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback, useContext, useEffect, useRef } from 'react'; - import { getComputed, IconOrImage } from '@cloudbeaver/core-blocks'; import { clsx, isValidUrl } from '@cloudbeaver/core-utils'; import type { IResultSetRowKey } from '@cloudbeaver/plugin-data-viewer'; @@ -52,12 +50,7 @@ export const TextFormatter = observer>(function if (cellContext.isEditing) { return (
- +
); } @@ -67,11 +60,11 @@ export const TextFormatter = observer>(function return (
{isUrl && ( - - + + )} -
{value}
+
{value}
); }); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/IndexFormatter.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/IndexFormatter.tsx index fc5e7609d3..88f3a132e3 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/IndexFormatter.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/IndexFormatter.tsx @@ -5,13 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { useContext } from 'react'; import type { IResultSetRowKey } from '@cloudbeaver/plugin-data-viewer'; import type { FormatterProps } from '@cloudbeaver/plugin-react-data-grid'; - import { CellContext } from '../CellRenderer/CellContext'; export const IndexFormatter: React.FC> = function IndexFormatter(props) { diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/Menu/CellMenu.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/Menu/CellMenu.tsx index 9665dd6e95..34769838a8 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/Menu/CellMenu.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/Menu/CellMenu.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; @@ -41,9 +40,7 @@ export const CellMenu = observer(function CellMenu({ }) { const dataGridContextMenuService = useService(DataGridContextMenuService); - const panel = dataGridContextMenuService.constructMenuWithContext( - model, actions, spreadsheetActions, resultIndex, cellKey, simple - ); + const panel = dataGridContextMenuService.constructMenuWithContext(model, actions, spreadsheetActions, resultIndex, cellKey, simple); if (!panel.menuItems.length || panel.menuItems.every(item => item.isHidden)) { return null; @@ -63,20 +60,10 @@ export const CellMenu = observer(function CellMenu({ } return styled(cellMenuStyles)( - - + + - + , ); }); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/Menu/cellMenuStyles.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/Menu/cellMenuStyles.ts index e023c1800b..efbf1869cd 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/Menu/cellMenuStyles.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/Menu/cellMenuStyles.ts @@ -5,34 +5,33 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { css } from 'reshadow'; export const cellMenuStyles = css` - IconOrImage { - composes: theme-text-primary from global; - } - :global(.rdg-cell):not(:global([aria-selected=true])):not(:hover) cell-menu { + IconOrImage { + composes: theme-text-primary from global; + } + :global(.rdg-cell):not(:global([aria-selected='true'])):not(:hover) cell-menu { + display: none; + } + cell-menu { + flex: 0 0 auto; + height: var(--rdg-row-height); + position: absolute; + top: 0px; + right: 0px; + } + MenuTrigger { + height: 100%; + + &:before { display: none; } - cell-menu { - flex: 0 0 auto; - height: var(--rdg-row-height); - position: absolute; - top: 0px; - right: 0px; - } - MenuTrigger { - height: 100%; - &:before { - display: none; - } - - & Icon { - cursor: pointer; - width: 16px; - height: 10px; - } + & Icon { + cursor: pointer; + width: 16px; + height: 10px; } + } `; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/OrderButton.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/OrderButton.tsx index b8326882ea..faecbae305 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/OrderButton.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/OrderButton.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -42,12 +41,7 @@ interface Props { className?: string; } -export const OrderButton = observer(function OrderButton({ - model, - resultIndex, - attributePosition, - className, -}) { +export const OrderButton = observer(function OrderButton({ model, resultIndex, attributePosition, className }) { const translate = useTranslate(); const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); const currentOrder = constraints.getOrder(attributePosition); @@ -74,18 +68,14 @@ export const OrderButton = observer(function OrderButton({ return styled(styles)( - - + + , ); }); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/TableColumnHeader.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/TableColumnHeader.tsx index 09c6fe6a37..9ec9cb5bc8 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/TableColumnHeader.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/TableColumnHeader.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useContext } from 'react'; import styled, { css, use } from 'reshadow'; @@ -63,9 +62,7 @@ const headerStyles = css` } `; -export const TableColumnHeader = observer>(function TableColumnHeader({ - column: calculatedColumn, -}) { +export const TableColumnHeader = observer>(function TableColumnHeader({ column: calculatedColumn }) { const dataGridContext = useContext(DataGridContext); const tableDataContext = useContext(TableDataContext); const gridSelectionContext = useContext(DataGridSelectionContext); @@ -76,9 +73,7 @@ export const TableColumnHeader = observer>(function Tab const dndData = useTableColumnDnD(model, resultIndex, calculatedColumn.columnDataIndex); const dataReadonly = getComputed(() => tableDataContext.isReadOnly() || model.isReadonly(resultIndex)); - const sortingDisabled = getComputed( - () => !tableDataContext.constraints.supported || !model.source.executionContext?.context - ); + const sortingDisabled = getComputed(() => !tableDataContext.constraints.supported || !model.source.executionContext?.context); let resultColumn: SqlResultColumn | undefined; let icon = calculatedColumn.icon; @@ -114,20 +109,14 @@ export const TableColumnHeader = observer>(function Tab return styled(headerStyles)( - + {icon && } - {!dataReadonly && columnReadOnly && } + {!dataReadonly && columnReadOnly && } {columnName} - {!sortingDisabled && resultColumn && ( - - )} - + {!sortingDisabled && resultColumn && } + , ); }); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/TableIndexColumnHeader.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/TableIndexColumnHeader.tsx index 57dc688861..87e766e097 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/TableIndexColumnHeader.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/TableIndexColumnHeader.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useContext } from 'react'; import styled, { css } from 'reshadow'; @@ -42,10 +41,7 @@ export const TableIndexColumnHeader = observer>(functio throw new Error('Contexts required'); } - const readonly = getComputed(() => ( - tableDataContext.isReadOnly() - || dataGridContext.model.isReadonly(dataGridContext.resultIndex) - )); + const readonly = getComputed(() => tableDataContext.isReadOnly() || dataGridContext.model.isReadonly(dataGridContext.resultIndex)); function handleClick(event: React.MouseEvent) { selectionContext.selectTable(); @@ -54,8 +50,8 @@ export const TableIndexColumnHeader = observer>(functio return styled(styles)( - {readonly && } + {readonly && } {props.column.name} - + , ); }); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/useTableColumnDnD.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/useTableColumnDnD.ts index 2e2f0f3144..fbf9344f7c 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/useTableColumnDnD.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/useTableColumnDnD.ts @@ -5,16 +5,17 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { IDNDData, useDNDData } from '@cloudbeaver/core-ui'; import { useDataContext } from '@cloudbeaver/core-view'; -import { DATA_CONTEXT_DV_DDM, DATA_CONTEXT_DV_DDM_RESULT_INDEX, DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY, IDatabaseDataModel, IResultSetColumnKey } from '@cloudbeaver/plugin-data-viewer'; +import { + DATA_CONTEXT_DV_DDM, + DATA_CONTEXT_DV_DDM_RESULT_INDEX, + DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY, + IDatabaseDataModel, + IResultSetColumnKey, +} from '@cloudbeaver/plugin-data-viewer'; -export function useTableColumnDnD( - model: IDatabaseDataModel, - resultIndex: number, - columnKey: IResultSetColumnKey | null -): IDNDData { +export function useTableColumnDnD(model: IDatabaseDataModel, resultIndex: number, columnKey: IResultSetColumnKey | null): IDNDData { const context = useDataContext(); context.set(DATA_CONTEXT_DV_DDM, model); @@ -26,4 +27,4 @@ export function useTableColumnDnD( }); return dndData; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableDataContext.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableDataContext.ts index 1700d6dc68..c1d6558471 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableDataContext.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableDataContext.ts @@ -5,14 +5,20 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createContext } from 'react'; - import type { SqlResultColumn } from '@cloudbeaver/core-sdk'; import type { - IResultSetColumnKey, IResultSetElementKey, IResultSetRowKey, IResultSetValue, DatabaseEditChangeType, - ResultSetDataAction, ResultSetEditAction, ResultSetFormatAction, ResultSetViewAction, ResultSetConstraintAction + DatabaseEditChangeType, + IResultSetColumnKey, + IResultSetElementKey, + IResultSetRowKey, + IResultSetValue, + ResultSetConstraintAction, + ResultSetDataAction, + ResultSetEditAction, + ResultSetFormatAction, + ResultSetViewAction, } from '@cloudbeaver/plugin-data-viewer'; import type { Column } from '@cloudbeaver/plugin-react-data-grid'; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridDragging.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridDragging.ts index 551f30e00d..704b669d7e 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridDragging.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridDragging.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { useCallback, useEffect } from 'react'; import { useObjectRef } from '@cloudbeaver/core-blocks'; @@ -23,7 +22,7 @@ interface IMousePosition { type DraggingCallback = ( startPosition: IDraggingPosition, currentPosition: IDraggingPosition, - event: React.MouseEvent | MouseEvent + event: React.MouseEvent | MouseEvent, ) => void; interface IDraggingState { @@ -35,10 +34,7 @@ interface IDraggingState { } interface IDraggingCallbacks { - onDragStart?: ( - startPosition: IDraggingPosition, - event: React.MouseEvent | MouseEvent - ) => void; + onDragStart?: (startPosition: IDraggingPosition, event: React.MouseEvent | MouseEvent) => void; onDragOver?: DraggingCallback; onDragEnd?: DraggingCallback; } @@ -88,13 +84,16 @@ function isDraggingStarted(delta: number | null, threshold: number) { export function useGridDragging(props: IDraggingCallbacks) { const callbacks = useObjectRef(props); - const state = useObjectRef(() => ({ - startDraggingCell: null, - currentDraggingCell: null, - startMousePosition: null, - dragging: false, - mouseDown: false, - }), false); + const state = useObjectRef( + () => ({ + startDraggingCell: null, + currentDraggingCell: null, + startMousePosition: null, + dragging: false, + mouseDown: false, + }), + false, + ); const onMouseDownHandler = useCallback((event: React.MouseEvent) => { const position = getCellPositionFromEvent(event); @@ -134,8 +133,7 @@ export function useGridDragging(props: IDraggingCallbacks) { } // check if the new cell is equal to the previous cell - if (position.rowIdx === state.currentDraggingCell?.rowIdx - && position.colIdx === state.currentDraggingCell.colIdx) { + if (position.rowIdx === state.currentDraggingCell?.rowIdx && position.colIdx === state.currentDraggingCell.colIdx) { return; } @@ -151,7 +149,8 @@ export function useGridDragging(props: IDraggingCallbacks) { colIdx: position.colIdx, rowIdx: position.rowIdx, }, - event); + event, + ); } }, []); @@ -173,7 +172,8 @@ export function useGridDragging(props: IDraggingCallbacks) { colIdx: state.currentDraggingCell.colIdx, rowIdx: state.currentDraggingCell.rowIdx, }, - event); + event, + ); } state.dragging = false; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridSelectedCellsCopy.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridSelectedCellsCopy.ts index 87a8d2d1cf..1dd5ad7aaa 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridSelectedCellsCopy.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridSelectedCellsCopy.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { useCallback } from 'react'; import { useObjectRef } from '@cloudbeaver/core-blocks'; @@ -26,13 +25,9 @@ function getCellCopyValue(tableData: ITableData, key: IResultSetElementKey): str return cellValue ?? ''; } -function getSelectedCellsValue( - tableData: ITableData, - selectedCells: Map -) { +function getSelectedCellsValue(tableData: ITableData, selectedCells: Map) { const orderedSelectedCells = new Map( - [...selectedCells] - .sort((a, b) => tableData.getRowIndexFromKey(a[1][0].row) - tableData.getRowIndexFromKey(b[1][0].row)) + [...selectedCells].sort((a, b) => tableData.getRowIndexFromKey(a[1][0].row) - tableData.getRowIndexFromKey(b[1][0].row)), ); const selectedColumns: IResultSetColumnKey[] = []; @@ -46,9 +41,7 @@ function getSelectedCellsValue( for (const rowSelection of orderedSelectedCells.values()) { const rowCellsValues: string[] = []; for (const column of tableData.view.columnKeys) { - if ( - !selectedColumns.some(columnKey => ResultSetDataKeysUtils.isEqual(columnKey, column)) - ) { + if (!selectedColumns.some(columnKey => ResultSetDataKeysUtils.isEqual(columnKey, column))) { continue; } @@ -69,7 +62,7 @@ function getSelectedCellsValue( export function useGridSelectedCellsCopy( tableData: ITableData, resultSetSelectAction: ResultSetSelectAction, - selectionContext: IDataGridSelectionContext + selectionContext: IDataGridSelectionContext, ) { const props = useObjectRef({ tableData, selectionContext, resultSetSelectAction }); @@ -81,10 +74,7 @@ export function useGridSelectedCellsCopy( let value: string | null = null; if (Array.from(props.selectionContext.selectedCells.keys()).length > 0) { - value = getSelectedCellsValue( - props.tableData, - props.selectionContext.selectedCells - ); + value = getSelectedCellsValue(props.tableData, props.selectionContext.selectedCells); } else if (focusedElement) { value = getCellCopyValue(tableData, focusedElement); } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useTableData.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useTableData.ts index 4ad366146e..212e2a1387 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useTableData.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useTableData.ts @@ -5,16 +5,22 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed, observable } from 'mobx'; - import { useObservableRef } from '@cloudbeaver/core-blocks'; import { TextTools } from '@cloudbeaver/core-utils'; import { - IDatabaseDataModel, IDatabaseResultSet, IResultSetColumnKey, IResultSetElementKey, IResultSetRowKey, - ResultSetConstraintAction, ResultSetDataAction, ResultSetDataKeysUtils, - ResultSetEditAction, ResultSetFormatAction, ResultSetViewAction + IDatabaseDataModel, + IDatabaseResultSet, + IResultSetColumnKey, + IResultSetElementKey, + IResultSetRowKey, + ResultSetConstraintAction, + ResultSetDataAction, + ResultSetDataKeysUtils, + ResultSetEditAction, + ResultSetFormatAction, + ResultSetViewAction, } from '@cloudbeaver/plugin-data-viewer'; import type { Column } from '@cloudbeaver/plugin-react-data-grid'; @@ -40,7 +46,7 @@ export function useTableData( model: IDatabaseDataModel, resultIndex: number, gridDIVElement: React.RefObject, - onCellKeyDown?: (event: React.KeyboardEvent) => void + onCellKeyDown?: (event: React.KeyboardEvent) => void, ): ITableData { const format = model.source.getAction(resultIndex, ResultSetFormatAction); const data = model.source.getAction(resultIndex, ResultSetDataAction); @@ -48,37 +54,37 @@ export function useTableData( const view = model.source.getAction(resultIndex, ResultSetViewAction); const constraints = model.source.getAction(resultIndex, ResultSetConstraintAction); - return useObservableRef }>(() => ({ - get gridDiv(): HTMLDivElement | null { - return this.gridDIVElement.current; - }, - get columnKeys(): IResultSetColumnKey[] { - return this.view.columnKeys; - }, - get rows(): IResultSetRowKey[] { - return this.view.rowKeys; - }, - get columns() { - if (this.columnKeys.length === 0) { - return []; - } - const columnNames = this.format.getHeaders(); - const rowStrings = this.format.getLongestCells(); + return useObservableRef }>( + () => ({ + get gridDiv(): HTMLDivElement | null { + return this.gridDIVElement.current; + }, + get columnKeys(): IResultSetColumnKey[] { + return this.view.columnKeys; + }, + get rows(): IResultSetRowKey[] { + return this.view.rowKeys; + }, + get columns() { + if (this.columnKeys.length === 0) { + return []; + } + const columnNames = this.format.getHeaders(); + const rowStrings = this.format.getLongestCells(); - // TODO: seems better to do not measure container size - // for detecting max columns size, better to use configurable variable - const measuredCells = TextTools.getWidth({ - font: '400 14px Roboto', - text: columnNames.map((cell, i) => { - if (cell.length > (rowStrings[i] || '').length) { - return cell; - } - return rowStrings[i]; - }), - }).map(v => v + 16 + 32 + 20); + // TODO: seems better to do not measure container size + // for detecting max columns size, better to use configurable variable + const measuredCells = TextTools.getWidth({ + font: '400 14px Roboto', + text: columnNames.map((cell, i) => { + if (cell.length > (rowStrings[i] || '').length) { + return cell; + } + return rowStrings[i]; + }), + }).map(v => v + 16 + 32 + 20); - const columns: Array> = this.columnKeys.map>( - (col, index) => ({ + const columns: Array> = this.columnKeys.map>((col, index) => ({ // key: uuid(), key: ResultSetDataKeysUtils.serialize(col), columnDataIndex: { index }, @@ -90,115 +96,108 @@ export function useTableData( onCellKeyDown, }, })); - columns.unshift(indexColumn); + columns.unshift(indexColumn); - return columns; - }, - getMetrics(columnIndex) { - if (columnIndex < 0 || columnIndex > this.columns.length) { - return undefined; - } + return columns; + }, + getMetrics(columnIndex) { + if (columnIndex < 0 || columnIndex > this.columns.length) { + return undefined; + } - let left = 0; - for (let i = 0; i < columnIndex; i++) { - const column = this.columns[i]; - left += column.width as number; - } + let left = 0; + for (let i = 0; i < columnIndex; i++) { + const column = this.columns[i]; + left += column.width as number; + } - const column = this.getColumn(columnIndex)!; + const column = this.getColumn(columnIndex)!; - return { - left, - right: left + (column.width as number), - width: column.width as number, - }; - }, - getRow(rowIndex) { - return this.rows[rowIndex]; - }, - getColumn(columnIndex) { - return this.columns[columnIndex]; - }, - getColumnByDataIndex(key) { - return this.columns.find(column => ( - column.columnDataIndex !== null - && ResultSetDataKeysUtils.isEqual(column.columnDataIndex, key) - ))!; - }, - getColumnInfo(key) { - return this.data.getColumn(key); - }, - getCellValue(key) { - return this.view.getCellValue(key); - }, - getColumnIndexFromKey(key) { - return this.columns.findIndex(column => column.key === key); - }, - getColumnIndexFromColumnKey(columnKey) { - return this.columns - .findIndex(column => ( - column.columnDataIndex !== null - && ResultSetDataKeysUtils.isEqual(columnKey, column.columnDataIndex) - )); - }, - getRowIndexFromKey(rowKey) { - return this.rows.findIndex(row => ResultSetDataKeysUtils.isEqual(rowKey, row)); - }, - getColumnsInRange(startIndex, endIndex) { - if (startIndex === endIndex) { - return [this.columns[startIndex]]; - } + return { + left, + right: left + (column.width as number), + width: column.width as number, + }; + }, + getRow(rowIndex) { + return this.rows[rowIndex]; + }, + getColumn(columnIndex) { + return this.columns[columnIndex]; + }, + getColumnByDataIndex(key) { + return this.columns.find(column => column.columnDataIndex !== null && ResultSetDataKeysUtils.isEqual(column.columnDataIndex, key))!; + }, + getColumnInfo(key) { + return this.data.getColumn(key); + }, + getCellValue(key) { + return this.view.getCellValue(key); + }, + getColumnIndexFromKey(key) { + return this.columns.findIndex(column => column.key === key); + }, + getColumnIndexFromColumnKey(columnKey) { + return this.columns.findIndex(column => column.columnDataIndex !== null && ResultSetDataKeysUtils.isEqual(columnKey, column.columnDataIndex)); + }, + getRowIndexFromKey(rowKey) { + return this.rows.findIndex(row => ResultSetDataKeysUtils.isEqual(rowKey, row)); + }, + getColumnsInRange(startIndex, endIndex) { + if (startIndex === endIndex) { + return [this.columns[startIndex]]; + } - const firstIndex = Math.min(startIndex, endIndex); - const lastIndex = Math.max(startIndex, endIndex); - return this.columns.slice(firstIndex, lastIndex + 1); - }, - getEditionState(key) { - return this.editor.getElementState(key); - }, - inBounds(position) { - return this.view.has(position); - }, - isCellEdited(key) { - return this.editor.isElementEdited(key); - }, - isIndexColumn(columnKey) { - return columnKey === indexColumn.key; - }, - isIndexColumnInRange(columnsRange) { - return columnsRange.some(column => this.isIndexColumn(column.key)); - }, - isReadOnly() { - return this.columnKeys.every(column => this.getColumnInfo(column)?.readOnly); - }, - isCellReadonly(key: Partial) { - if (!key.column) { - return true; - } + const firstIndex = Math.min(startIndex, endIndex); + const lastIndex = Math.max(startIndex, endIndex); + return this.columns.slice(firstIndex, lastIndex + 1); + }, + getEditionState(key) { + return this.editor.getElementState(key); + }, + inBounds(position) { + return this.view.has(position); + }, + isCellEdited(key) { + return this.editor.isElementEdited(key); + }, + isIndexColumn(columnKey) { + return columnKey === indexColumn.key; + }, + isIndexColumnInRange(columnsRange) { + return columnsRange.some(column => this.isIndexColumn(column.key)); + }, + isReadOnly() { + return this.columnKeys.every(column => this.getColumnInfo(column)?.readOnly); + }, + isCellReadonly(key: Partial) { + if (!key.column) { + return true; + } - const column = this.getColumnByDataIndex(key.column); + const column = this.getColumnByDataIndex(key.column); - return ( - !column.editable - || this.format.isReadOnly(key) - ); + return !column.editable || this.format.isReadOnly(key); + }, + }), + { + columns: computed, + rows: computed, + columnKeys: computed, + format: observable.ref, + data: observable.ref, + editor: observable.ref, + view: observable.ref, + constraints: observable.ref, + gridDIVElement: observable.ref, }, - }), { - columns: computed, - rows: computed, - columnKeys: computed, - format: observable.ref, - data: observable.ref, - editor: observable.ref, - view: observable.ref, - constraints: observable.ref, - gridDIVElement: observable.ref, - }, { - format, - data, - editor, - view, - constraints, - gridDIVElement, - }); + { + format, + data, + editor, + view, + constraints, + gridDIVElement, + }, + ); } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGridSettingsService.test.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGridSettingsService.test.ts index 7351f1bf13..0f273cb3a1 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGridSettingsService.test.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGridSettingsService.test.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import '@testing-library/jest-dom'; import { mockAuthentication } from '@cloudbeaver/core-authentication/mocks/mockAuthentication'; @@ -25,19 +24,9 @@ import { DataGridSettings, DataGridSettingsService } from './DataGridSettingsSer import { manifest } from './manifest'; const endpoint = createGQLEndpoint(); -const app = createApp( - datasourceContextSwitch, - navigationTree, - navigationTabs, - objectViewer, - dataViewer, - manifest -); +const app = createApp(datasourceContextSwitch, navigationTree, navigationTabs, objectViewer, dataViewer, manifest); -const server = mockGraphQL( - ...mockAppInit(endpoint), - ...mockAuthentication(endpoint) -); +const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint)); beforeAll(() => app.init()); @@ -70,9 +59,7 @@ test('New settings equal deprecated settings A', async () => { const settings = app.injector.getServiceByClass(DataGridSettingsService); const config = app.injector.getServiceByClass(ServerConfigResource); - server.use( - endpoint.query('serverConfig', mockServerConfig(equalConfigA)), - ); + server.use(endpoint.query('serverConfig', mockServerConfig(equalConfigA))); await config.refresh(); @@ -84,12 +71,10 @@ test('New settings equal deprecated settings B', async () => { const settings = app.injector.getServiceByClass(DataGridSettingsService); const config = app.injector.getServiceByClass(ServerConfigResource); - server.use( - endpoint.query('serverConfig', mockServerConfig(equalConfigB)), - ); + server.use(endpoint.query('serverConfig', mockServerConfig(equalConfigB))); await config.refresh(); expect(settings.settings.getValue('hidden')).toBe(testValueB); expect(settings.deprecatedSettings.getValue('hidden')).toBe(testValueB); -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGridSettingsService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGridSettingsService.ts index 8be1043f96..c220e2f9c1 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGridSettingsService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGridSettingsService.ts @@ -5,7 +5,6 @@ * 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 { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin'; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/Editing/EditingContext.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/Editing/EditingContext.tsx index 73967607d6..658519794a 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/Editing/EditingContext.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/Editing/EditingContext.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createContext } from 'react'; export interface IEditingContext { diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/Editing/useEditing.ts b/webapp/packages/plugin-data-spreadsheet-new/src/Editing/useEditing.ts index 52fabde8b5..a7c2eb743c 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/Editing/useEditing.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/Editing/useEditing.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable } from 'mobx'; import { useState } from 'react'; @@ -29,13 +28,17 @@ interface IEditingOptions { } export function useEditing(options: IEditingOptions): IEditingContext { - const state = useObservableRef(() => ({ - editingCells: new MetadataMap(() => ({ editing: false })), - editorOpened: false, - }), { - editorOpened: observable.ref, - readonly: observable.ref, - }, { options, readonly: !!options.readonly }); + const state = useObservableRef( + () => ({ + editingCells: new MetadataMap(() => ({ editing: false })), + editorOpened: false, + }), + { + editorOpened: observable.ref, + readonly: observable.ref, + }, + { options, readonly: !!options.readonly }, + ); const [context] = useState({ get readonly() { @@ -75,9 +78,7 @@ export function useEditing(options: IEditingOptions): IEditingContext { return state.editorOpened; }, isEditing(position: CellPosition) { - return state.editingCells - .get(getPositionHash(position)) - .editing; + return state.editingCells.get(getPositionHash(position)).editing; }, }); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/LocaleService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/LocaleService.ts index 144237a086..e3649a06b4 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/LocaleService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetBootstrap.ts b/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetBootstrap.ts index b1ca1e038a..ffb1bab96d 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetBootstrap.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { ExceptionsCatcherService } from '@cloudbeaver/core-events'; import { ResultDataFormat } from '@cloudbeaver/core-sdk'; @@ -29,7 +28,7 @@ export class SpreadsheetBootstrap extends Bootstrap { private readonly dataGridContextMenuCellEditingService: DataGridContextMenuCellEditingService, private readonly dataGridContextMenuService: DataGridContextMenuService, private readonly dataGridContextMenuSaveContentService: DataGridContextMenuSaveContentService, - exceptionsCatcherService: ExceptionsCatcherService + exceptionsCatcherService: ExceptionsCatcherService, ) { super(); exceptionsCatcherService.ignore('ResizeObserver loop limit exceeded'); // Produces by react-data-grid @@ -40,11 +39,10 @@ export class SpreadsheetBootstrap extends Bootstrap { id: 'spreadsheet_grid', dataFormat: ResultDataFormat.Resultset, getPresentationComponent: () => SpreadsheetGrid, - hidden: () => ( + hidden: () => this.dataGridSettingsService.settings.isValueDefault('hidden') ? this.dataGridSettingsService.deprecatedSettings.getValue('hidden') - : this.dataGridSettingsService.settings.getValue('hidden') - ), + : this.dataGridSettingsService.settings.getValue('hidden'), title: 'Table', icon: 'table-icon-sm', }); @@ -53,28 +51,22 @@ export class SpreadsheetBootstrap extends Bootstrap { this.dataGridContextMenuCellEditingService.register(); this.dataGridContextMenuSaveContentService.register(); - this.dataGridContextMenuService.add( - this.dataGridContextMenuService.getMenuToken(), - { - id: 'view_value_panel', - isPresent(context) { - return context.contextType === DataGridContextMenuService.cellContext; - }, - isHidden(context) { - return ( - typeof context.data.actions.valuePresentationId === 'string' - || context.data.simple - ); - }, - order: 0.5, - title: 'data_grid_table_open_value_panel', - icon: 'value-panel', - onClick(context) { - context.data.actions.setValuePresentation(''); - }, - } - ); + this.dataGridContextMenuService.add(this.dataGridContextMenuService.getMenuToken(), { + id: 'view_value_panel', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + return typeof context.data.actions.valuePresentationId === 'string' || context.data.simple; + }, + order: 0.5, + title: 'data_grid_table_open_value_panel', + icon: 'value-panel', + onClick(context) { + context.data.actions.setValuePresentation(''); + }, + }); } - load(): void | Promise { } + load(): void | Promise {} } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetGrid.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetGrid.tsx index d490fd1b1c..96bda26fdd 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetGrid.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetGrid.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IDataPresentationProps } from '@cloudbeaver/plugin-data-viewer'; import { DataGridLoader } from './DataGrid/DataGridLoader'; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/locales/it.ts b/webapp/packages/plugin-data-spreadsheet-new/src/locales/it.ts index 6c82540d8b..53bc025695 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/locales/it.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/locales/it.ts @@ -1,7 +1,7 @@ export default [ ['data_grid_table_editing', 'Modifca'], ['data_grid_table_editing_set_to_null', 'Imposta a NULL'], - ['data_grid_table_editing_open_inline_editor', 'Apri l\'editor contestuale'], + ['data_grid_table_editing_open_inline_editor', "Apri l'editor contestuale"], ['data_grid_table_order', 'Ordinamento'], ['data_grid_table_open_value_panel', 'Mostra nel pannello dei valori'], ['data_grid_table_filter', 'Filtri'], @@ -10,7 +10,7 @@ export default [ ['data_grid_table_filter_reset_all_filters', 'Reimposta tutti i filtri'], ['data_grid_table_disable_order', 'Disabilitato'], ['data_grid_table_disable_all_orders', 'Disabilita tutto'], - ['data_grid_table_delete_filters_and_orders', 'Reimposta i filtri / l\'ordinamento'], + ['data_grid_table_delete_filters_and_orders', "Reimposta i filtri / l'ordinamento"], ['data_grid_table_tooltip_column_header_order', 'Ordina per colonna'], ['data_grid_table_context_menu_filter_dialog_title', 'Modifica valore'], ['data_grid_table_context_menu_filter_clipboard_permission', 'Dai accesso agli appunti'], diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/manifest.ts b/webapp/packages/plugin-data-spreadsheet-new/src/manifest.ts index 325443cdac..6c3fb4aa01 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/manifest.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { DataGridContextMenuCellEditingService } from './DataGrid/DataGridContextMenu/DataGridContextMenuCellEditingService'; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/styles/styles.ts b/webapp/packages/plugin-data-spreadsheet-new/src/styles/styles.ts index cc26903dc8..700ef7dcb5 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/styles/styles.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/styles/styles.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { ThemeSelector } from '@cloudbeaver/core-theming'; export const reactGridStyles: ThemeSelector = async theme => { diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/Actions/ACTION_DATA_VIEWER_GROUPING_CLEAR.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/Actions/ACTION_DATA_VIEWER_GROUPING_CLEAR.ts index 4aad9a99d0..f02153bbc3 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/Actions/ACTION_DATA_VIEWER_GROUPING_CLEAR.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/Actions/ACTION_DATA_VIEWER_GROUPING_CLEAR.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; export const ACTION_DATA_VIEWER_GROUPING_CLEAR = createAction('data-viewer-grouping-clear', { diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/Actions/ACTION_DATA_VIEWER_GROUPING_REMOVE_COLUMN.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/Actions/ACTION_DATA_VIEWER_GROUPING_REMOVE_COLUMN.ts index 7a032ed84e..3c38d776b8 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/Actions/ACTION_DATA_VIEWER_GROUPING_REMOVE_COLUMN.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/Actions/ACTION_DATA_VIEWER_GROUPING_REMOVE_COLUMN.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; export const ACTION_DATA_VIEWER_GROUPING_REMOVE_COLUMN = createAction('data-viewer-grouping-remove-column', { diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/DVResultSetGroupingPluginBootstrap.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/DVResultSetGroupingPluginBootstrap.ts index e92910977a..ea9f23e732 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/DVResultSetGroupingPluginBootstrap.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/DVResultSetGroupingPluginBootstrap.ts @@ -5,11 +5,19 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { ResultDataFormat } from '@cloudbeaver/core-sdk'; import { ActionService, DATA_CONTEXT_MENU, MenuService } from '@cloudbeaver/core-view'; -import { DATA_CONTEXT_DV_DDM, DATA_CONTEXT_DV_DDM_RESULT_INDEX, DATA_VIEWER_DATA_MODEL_ACTIONS_MENU, DataPresentationService, DataPresentationType, ResultSetDataAction, ResultSetSelectAction, ResultSetViewAction } from '@cloudbeaver/plugin-data-viewer'; +import { + DATA_CONTEXT_DV_DDM, + DATA_CONTEXT_DV_DDM_RESULT_INDEX, + DATA_VIEWER_DATA_MODEL_ACTIONS_MENU, + DataPresentationService, + DataPresentationType, + ResultSetDataAction, + ResultSetSelectAction, + ResultSetViewAction, +} from '@cloudbeaver/plugin-data-viewer'; import { ACTION_DATA_VIEWER_GROUPING_CLEAR } from './Actions/ACTION_DATA_VIEWER_GROUPING_CLEAR'; import { ACTION_DATA_VIEWER_GROUPING_REMOVE_COLUMN } from './Actions/ACTION_DATA_VIEWER_GROUPING_REMOVE_COLUMN'; @@ -21,7 +29,7 @@ export class DVResultSetGroupingPluginBootstrap extends Bootstrap { constructor( private readonly dataPresentationService: DataPresentationService, private readonly menuService: MenuService, - private readonly actionService: ActionService + private readonly actionService: ActionService, ) { super(); } @@ -31,7 +39,7 @@ export class DVResultSetGroupingPluginBootstrap extends Bootstrap { this.registerActions(); } - load(): void | Promise { } + load(): void | Promise {} private registerActions(): void { this.actionService.addHandler({ @@ -108,11 +116,7 @@ export class DVResultSetGroupingPluginBootstrap extends Bootstrap { return context.has(DATA_CONTEXT_DV_DDM_RS_GROUPING); }, getItems(context, items) { - return [ - ...items, - ACTION_DATA_VIEWER_GROUPING_REMOVE_COLUMN, - ACTION_DATA_VIEWER_GROUPING_CLEAR, - ]; + return [...items, ACTION_DATA_VIEWER_GROUPING_REMOVE_COLUMN, ACTION_DATA_VIEWER_GROUPING_CLEAR]; }, }); } @@ -124,11 +128,7 @@ export class DVResultSetGroupingPluginBootstrap extends Bootstrap { title: 'plugin_data_viewer_result_set_grouping_title', icon: '/icons/plugin_data_viewer_result_set_grouping_m.svg', dataFormat: ResultDataFormat.Resultset, - hidden: ( - dataFormat, - model, - resultIndex - ) => { + hidden: (dataFormat, model, resultIndex) => { if (!model.source.hasResult(resultIndex)) { return true; } @@ -139,5 +139,4 @@ export class DVResultSetGroupingPluginBootstrap extends Bootstrap { getPresentationComponent: () => DVResultSetGroupingPresentation, }); } - -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/DVResultSetGroupingPresentation.tsx b/webapp/packages/plugin-data-viewer-result-set-grouping/src/DVResultSetGroupingPresentation.tsx index b7c052bd03..9bb867ab70 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/DVResultSetGroupingPresentation.tsx +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/DVResultSetGroupingPresentation.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useContext, useState } from 'react'; @@ -29,7 +28,8 @@ const styles = css` position: relative; overflow: auto; - &[|active]::after, &[|negative]::after { + &[|active]::after, + &[|negative]::after { position: absolute; top: 0; left: 0; @@ -54,7 +54,7 @@ const styles = css` display: flex; height: 100%; width: 100%; - + & message { box-sizing: border-box; padding: 24px; @@ -66,7 +66,7 @@ const styles = css` } throw-box { position: fixed; - + &:not([|showDropOutside]) { left: 0; top: 0; @@ -112,20 +112,24 @@ export const DVResultSetGroupingPresentation: DataPresentationComponent(() => ({ - getColumns() { - return this.state.columns; + const groupingData = useObservableRef( + () => ({ + getColumns() { + return this.state.columns; + }, + removeColumn(...columns) { + this.state.columns = this.state.columns.filter(column => !columns.includes(column)); + }, + clear() { + this.state.presentationId = ''; + this.state.columns = []; + }, + }), + { + clear: action, }, - removeColumn(...columns) { - this.state.columns = this.state.columns.filter(column => !columns.includes(column)); - }, - clear() { - this.state.presentationId = ''; - this.state.columns = []; - }, - }), { - clear: action, - }, { state }); + { state }, + ); context.set(DATA_CONTEXT_DV_DDM_RS_GROUPING, groupingData); @@ -148,9 +152,7 @@ export const DVResultSetGroupingPresentation: DataPresentationComponent {state.columns.length === 0 ? ( - - {translate('plugin_data_viewer_result_set_grouping_placeholder')} - + {translate('plugin_data_viewer_result_set_grouping_placeholder')} ) : ( )} - + , ); -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/DataContext/DATA_CONTEXT_DV_DDM_RS_GROUPING.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/DataContext/DATA_CONTEXT_DV_DDM_RS_GROUPING.ts index e5acf2dd5b..2aa5d80faa 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/DataContext/DATA_CONTEXT_DV_DDM_RS_GROUPING.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/DataContext/DATA_CONTEXT_DV_DDM_RS_GROUPING.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createDataContext } from '@cloudbeaver/core-view'; export interface IResultSetGroupingData { diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/GroupingDataSource.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/GroupingDataSource.ts index 8b2fda1f52..d8d42f43a6 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/GroupingDataSource.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/GroupingDataSource.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IDatabaseResultSet } from '@cloudbeaver/plugin-data-viewer'; import { IDataQueryOptions, QueryDataSource } from '@cloudbeaver/plugin-sql-editor'; @@ -44,4 +43,4 @@ export class GroupingDataSource extends QueryDataSource { throw exception; } } -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/IGroupingQueryState.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/IGroupingQueryState.ts index d3ccc7d392..f41b39b1e4 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/IGroupingQueryState.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/IGroupingQueryState.ts @@ -8,4 +8,4 @@ export interface IGroupingQueryState { columns: string[]; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/LocaleService.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/LocaleService.ts index 144237a086..e3649a06b4 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/LocaleService.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/index.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/index.ts index 958a96fea8..dc9e65d40b 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/index.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/index.ts @@ -1,4 +1,4 @@ import { dvResultSetGroupingPlugin } from './manifest'; export { dvResultSetGroupingPlugin }; -export default dvResultSetGroupingPlugin; \ No newline at end of file +export default dvResultSetGroupingPlugin; diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/locales/it.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/locales/it.ts index 9f25cb126f..d6d1738de6 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/locales/it.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/locales/it.ts @@ -1,2 +1 @@ -export default [ -]; +export default []; diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/locales/zh.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/locales/zh.ts index 9f25cb126f..d6d1738de6 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/locales/zh.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/locales/zh.ts @@ -1,2 +1 @@ -export default [ -]; +export default []; diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/manifest.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/manifest.ts index 41f96bc2f4..1e0732d10b 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/manifest.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { DVResultSetGroupingPluginBootstrap } from './DVResultSetGroupingPluginBootstrap'; @@ -13,8 +12,5 @@ import { LocaleService } from './LocaleService'; export const dvResultSetGroupingPlugin: PluginManifest = { info: { name: 'Result Set Grouping plugin' }, - providers: [ - DVResultSetGroupingPluginBootstrap, - LocaleService, - ], -}; \ No newline at end of file + providers: [DVResultSetGroupingPluginBootstrap, LocaleService], +}; diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/useGroupingDataModel.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/useGroupingDataModel.ts index 1b4cc72917..52d14ef628 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/useGroupingDataModel.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/useGroupingDataModel.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { reaction } from 'mobx'; import { useEffect } from 'react'; @@ -14,7 +13,14 @@ import { ConnectionInfoResource, createConnectionParam } from '@cloudbeaver/core import { App, useService } from '@cloudbeaver/core-di'; import { AsyncTaskInfoService, GraphQLService } from '@cloudbeaver/core-sdk'; import { isObjectsEqual } from '@cloudbeaver/core-utils'; -import { DataViewerSettingsService, DatabaseDataAccessMode, DatabaseDataModel, IDatabaseDataModel, IDatabaseResultSet, TableViewerStorageService } from '@cloudbeaver/plugin-data-viewer'; +import { + DatabaseDataAccessMode, + DatabaseDataModel, + DataViewerSettingsService, + IDatabaseDataModel, + IDatabaseResultSet, + TableViewerStorageService, +} from '@cloudbeaver/plugin-data-viewer'; import { GroupingDataSource, IDataGroupingOptions } from './GroupingDataSource'; import type { IGroupingQueryState } from './IGroupingQueryState'; @@ -38,36 +44,29 @@ export function useGroupingDataModel( const contextInfo = executionContext?.context; const connectionKey = contextInfo ? createConnectionParam(contextInfo.projectId, contextInfo.connectionId) : null; - const connectionInfoLoader = useResource( - useGroupingDataModel, - ConnectionInfoResource, - connectionKey - ); + const connectionInfoLoader = useResource(useGroupingDataModel, ConnectionInfoResource, connectionKey); const connectionInfo = connectionInfoLoader.data; - const model = useObjectRef(() => { - const source = new GroupingDataSource( - app.getServiceInjector(), - graphQLService, - asyncTaskInfoService, - ); + const model = useObjectRef( + () => { + const source = new GroupingDataSource(app.getServiceInjector(), graphQLService, asyncTaskInfoService); - const model = tableViewerStorageService.add(new DatabaseDataModel(source)); + const model = tableViewerStorageService.add(new DatabaseDataModel(source)); - model - .setAccess(DatabaseDataAccessMode.Readonly) - .setCountGain(dataViewerSettingsService.getDefaultRowsCount()) - .setSlice(0); + model.setAccess(DatabaseDataAccessMode.Readonly).setCountGain(dataViewerSettingsService.getDefaultRowsCount()).setSlice(0); - return { - source, - model, - dispose() { - this.model.dispose(); - tableViewerStorageService.remove(this.model.id); - }, - }; - }, false, ['dispose']); + return { + source, + model, + dispose() { + this.model.dispose(); + tableViewerStorageService.remove(this.model.id); + }, + }; + }, + false, + ['dispose'], + ); useEffect(() => { sourceModel.onDispose.addHandler(model.dispose); @@ -77,54 +76,48 @@ export function useGroupingDataModel( }, [sourceModel]); useEffect(() => { - const sub = reaction(() => { - const result = sourceModel.source.hasResult(sourceResultIndex) - ? sourceModel.source.getResult(sourceResultIndex) - : null; + const sub = reaction( + () => { + const result = sourceModel.source.hasResult(sourceResultIndex) ? sourceModel.source.getResult(sourceResultIndex) : null; - return { - columns: state.columns, - sourceResultId: result?.id, - }; - }, async ({ columns, sourceResultId }) => { - if (columns.length !== 0 && sourceResultId) { - const executionContext = sourceModel.source.executionContext; - model.model.source - .setExecutionContext(executionContext) - .setSupportedDataFormats(connectionInfo?.supportedDataFormats ?? []); + return { + columns: state.columns, + sourceResultId: result?.id, + }; + }, + async ({ columns, sourceResultId }) => { + if (columns.length !== 0 && sourceResultId) { + const executionContext = sourceModel.source.executionContext; + model.model.source.setExecutionContext(executionContext).setSupportedDataFormats(connectionInfo?.supportedDataFormats ?? []); - if (executionContext?.context) { - const connectionKey = createConnectionParam( - executionContext.context.projectId, - executionContext.context.connectionId - ); + if (executionContext?.context) { + const connectionKey = createConnectionParam(executionContext.context.projectId, executionContext.context.connectionId); + model.model + .setOptions({ + query: '', + columns, + sourceResultId, + connectionKey, + constraints: [], + whereFilter: '', + }) + .setCountGain(dataViewerSettingsService.getDefaultRowsCount()) + .setSlice(0) + .source.resetData(); + } + } else { model.model - .setOptions({ - query: '', - columns, - sourceResultId, - connectionKey, - constraints: [], - whereFilter: '', - }) .setCountGain(dataViewerSettingsService.getDefaultRowsCount()) .setSlice(0) - .source - .resetData(); + .source.setExecutionContext(null) + .setSupportedDataFormats([]) + .clearError() + .setResults([]); } - } else { - model.model - .setCountGain(dataViewerSettingsService.getDefaultRowsCount()) - .setSlice(0) - .source - .setExecutionContext(null) - .setSupportedDataFormats([]) - .clearError() - .setResults([]); - } - - }, { fireImmediately: true, equals: isObjectsEqual }); + }, + { fireImmediately: true, equals: isObjectsEqual }, + ); return sub; }, [state, sourceModel, sourceResultIndex]); @@ -134,4 +127,4 @@ export function useGroupingDataModel( return { model: model.model, }; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/useGroupingDnDColumns.ts b/webapp/packages/plugin-data-viewer-result-set-grouping/src/useGroupingDnDColumns.ts index a0b192742c..ca30042d3d 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/useGroupingDnDColumns.ts +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/useGroupingDnDColumns.ts @@ -5,9 +5,16 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { IDNDBox, useDNDBox } from '@cloudbeaver/core-ui'; -import { DATA_CONTEXT_DV_DDM, DATA_CONTEXT_DV_DDM_RESULT_INDEX, DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY, IDatabaseDataModel, IDatabaseResultSet, IResultSetColumnKey, ResultSetDataAction } from '@cloudbeaver/plugin-data-viewer'; +import { + DATA_CONTEXT_DV_DDM, + DATA_CONTEXT_DV_DDM_RESULT_INDEX, + DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY, + IDatabaseDataModel, + IDatabaseResultSet, + IResultSetColumnKey, + ResultSetDataAction, +} from '@cloudbeaver/plugin-data-viewer'; import type { IGroupingQueryState } from './IGroupingQueryState'; import type { IGroupingDataModel } from './useGroupingDataModel'; @@ -20,14 +27,13 @@ interface IGroupingQueryResult { export function useGroupingDnDColumns( state: IGroupingQueryState, sourceModel: IDatabaseDataModel, - groupingModel: IGroupingDataModel + groupingModel: IGroupingDataModel, ): IGroupingQueryResult { - async function dropItem( model: IDatabaseDataModel, resultIndex: number, columnKey: IResultSetColumnKey | null, - outside: boolean + outside: boolean, ) { if (!columnKey) { return; @@ -48,19 +54,14 @@ export function useGroupingDnDColumns( } state.columns = columnNames; - } catch (e) { - - } + } catch (e) {} } const dndBox = useDNDBox({ canDrop: context => { const model = context.tryGet(DATA_CONTEXT_DV_DDM); - return ( - context.has(DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY) - && model === sourceModel - ); + return context.has(DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY) && model === sourceModel; }, onDrop: async context => { const model = context.get(DATA_CONTEXT_DV_DDM); @@ -75,10 +76,7 @@ export function useGroupingDnDColumns( canDrop: context => { const model = context.tryGet(DATA_CONTEXT_DV_DDM); - return ( - context.has(DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY) - && model?.id === groupingModel.model.id - ); + return context.has(DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY) && model?.id === groupingModel.model.id; }, onDrop: async context => { const model = context.get(DATA_CONTEXT_DV_DDM); @@ -93,4 +91,4 @@ export function useGroupingDnDColumns( dndBox, dndThrowBox, }; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-data-viewer/src/ContainerDataSource.ts b/webapp/packages/plugin-data-viewer/src/ContainerDataSource.ts index a2e0b3cf26..b11c953016 100644 --- a/webapp/packages/plugin-data-viewer/src/ContainerDataSource.ts +++ b/webapp/packages/plugin-data-viewer/src/ContainerDataSource.ts @@ -5,13 +5,19 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed, makeObservable, observable } from 'mobx'; import type { ConnectionExecutionContextService, IConnectionExecutionContext, IConnectionExecutionContextInfo } from '@cloudbeaver/core-connections'; import type { IServiceInjector } from '@cloudbeaver/core-di'; import type { ITask } from '@cloudbeaver/core-executor'; -import { AsyncTaskInfoService, GraphQLService, ResultDataFormat, SqlExecuteInfo, SqlQueryResults, UpdateResultsDataBatchMutationVariables } from '@cloudbeaver/core-sdk'; +import { + AsyncTaskInfoService, + GraphQLService, + ResultDataFormat, + SqlExecuteInfo, + SqlQueryResults, + UpdateResultsDataBatchMutationVariables, +} from '@cloudbeaver/core-sdk'; import { DocumentEditAction } from './DatabaseDataModel/Actions/Document/DocumentEditAction'; import { ResultSetEditAction } from './DatabaseDataModel/Actions/ResultSet/ResultSetEditAction'; @@ -65,9 +71,7 @@ export class ContainerDataSource extends DatabaseDataSource { + async request(prevResults: IDatabaseResultSet[]): Promise { const options = this.options; if (!options) { @@ -81,10 +85,10 @@ export class ContainerDataSource extends DatabaseDataSource this.asyncTaskInfoService.cancel(task.id), - () => this.asyncTaskInfoService.remove(task.id) + () => this.asyncTaskInfoService.remove(task.id), ); try { @@ -140,9 +144,7 @@ export class ContainerDataSource extends DatabaseDataSource { + async save(prevResults: IDatabaseResultSet[]): Promise { const executionContext = await this.ensureContextCreated(); try { @@ -177,8 +179,9 @@ export class ContainerDataSource extends DatabaseDataSource newResult.id === result.id); + const responseResult = this.transformResults(executionContextInfo, response.result.results, 0).find( + newResult => newResult.id === result.id, + ); if (responseResult) { editor.applyUpdate(responseResult); @@ -222,11 +225,7 @@ export class ContainerDataSource extends DatabaseDataSource(result => ({ id: result.resultSet?.id || '0', uniqueResultId: `${executionContextInfo.connectionId}_${executionContextInfo.id}_${result.resultSet?.id || '0'}`, @@ -250,7 +249,7 @@ export class ContainerDataSource extends DatabaseDataSource { +export interface IDataPresentationProps { dataFormat: ResultDataFormat; model: IDatabaseDataModel; actions: IDataTableActions; @@ -28,13 +24,12 @@ export interface IDataPresentationProps< export enum DataPresentationType { main, - toolsPanel + toolsPanel, } -export type DataPresentationComponent< - TOptions = any, - TResult extends IDatabaseDataResult = IDatabaseDataResult -> = React.FunctionComponent>; +export type DataPresentationComponent = React.FunctionComponent< + IDataPresentationProps +>; export type PresentationTabProps = TabProps & { presentation: IDataPresentationOptions; @@ -49,11 +44,7 @@ export interface IDataPresentationOptions { type?: DataPresentationType; title?: string; icon?: string; - hidden?: ( - dataFormat: ResultDataFormat | null, - model: IDatabaseDataModel, - resultIndex: number - ) => boolean; + hidden?: (dataFormat: ResultDataFormat | null, model: IDatabaseDataModel, resultIndex: number) => boolean; getPresentationComponent: () => DataPresentationComponent; getTabComponent?: () => PresentationTabComponent; onActivate?: () => void; @@ -83,10 +74,7 @@ export class DataPresentationService { resultIndex: number, ): IDataPresentation[] { return Array.from(this.dataPresentations.values()).filter(presentation => { - if ( - presentation.dataFormat !== undefined - && !supportedDataFormats.includes(presentation.dataFormat) - ) { + if (presentation.dataFormat !== undefined && !supportedDataFormats.includes(presentation.dataFormat)) { return false; } @@ -118,9 +106,9 @@ export class DataPresentationService { for (const presentation of this.dataPresentations.values()) { if ( - (presentation.dataFormat === undefined || presentation.dataFormat === dataFormat) - && presentation.type === type - && !presentation.hidden?.(dataFormat, model, resultIndex) + (presentation.dataFormat === undefined || presentation.dataFormat === dataFormat) && + presentation.type === type && + !presentation.hidden?.(dataFormat, model, resultIndex) ) { return presentation; } @@ -130,12 +118,9 @@ export class DataPresentationService { } add(options: IDataPresentationOptions): void { - this.dataPresentations.set( - options.id, - { - ...options, - type: options.type || DataPresentationType.main, - } - ); + this.dataPresentations.set(options.id, { + ...options, + type: options.type || DataPresentationType.main, + }); } } diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerBootstrap.ts b/webapp/packages/plugin-data-viewer/src/DataViewerBootstrap.ts index e531267632..725f34787b 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerBootstrap.ts +++ b/webapp/packages/plugin-data-viewer/src/DataViewerBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { DataViewerTabService } from './DataViewerTabService'; @@ -21,5 +20,5 @@ export class DataViewerBootstrap extends Bootstrap { this.dataViewerTabService.register(); } - load(): void { } + load(): void {} } diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerDataChangeConfirmationService.ts b/webapp/packages/plugin-data-viewer/src/DataViewerDataChangeConfirmationService.ts index 37f2c339af..6c5acd482d 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerDataChangeConfirmationService.ts +++ b/webapp/packages/plugin-data-viewer/src/DataViewerDataChangeConfirmationService.ts @@ -5,7 +5,6 @@ * 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 { CommonDialogService, ConfirmationDialog, DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; @@ -20,7 +19,7 @@ export class DataViewerDataChangeConfirmationService { constructor( private readonly commonDialogService: CommonDialogService, private readonly dataViewerTableService: TableViewerStorageService, - private readonly notificationService: NotificationService + private readonly notificationService: NotificationService, ) { this.checkUnsavedData = this.checkUnsavedData.bind(this); } @@ -33,12 +32,7 @@ export class DataViewerDataChangeConfirmationService { } } - private async checkUnsavedData({ - type, - model, - }: IRequestEventData, - contexts: IExecutionContextProvider> - ) { + private async checkUnsavedData({ type, model }: IRequestEventData, contexts: IExecutionContextProvider>) { if (type === 'before') { const confirmationContext = contexts.getContext(SaveConfirmedContext); @@ -50,10 +44,7 @@ export class DataViewerDataChangeConfirmationService { try { for (let resultIndex = 0; resultIndex < results.length; resultIndex++) { - const editor = model.source.getActionImplementation( - resultIndex, - DatabaseEditAction - ); + const editor = model.source.getActionImplementation(resultIndex, DatabaseEditAction); if (editor?.isEdited() && model.source.executionContext?.context) { if (confirmationContext.confirmed) { @@ -85,7 +76,7 @@ export class DataViewerDataChangeConfirmationService { } } -interface ISaveConfirmedContext{ +interface ISaveConfirmedContext { confirmed: boolean | null; setConfirmed: (state: boolean) => void; } diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerPage/DataViewerPanel.tsx b/webapp/packages/plugin-data-viewer/src/DataViewerPage/DataViewerPanel.tsx index 70300f9452..3a08117c30 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerPage/DataViewerPanel.tsx +++ b/webapp/packages/plugin-data-viewer/src/DataViewerPage/DataViewerPanel.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback } from 'react'; import styled, { css } from 'reshadow'; @@ -24,40 +23,43 @@ const styles = css` } `; -export const DataViewerPanel: ObjectPagePanelComponent = observer(function DataViewerPanel({ - tab, - page, -}) { +export const DataViewerPanel: ObjectPagePanelComponent = observer(function DataViewerPanel({ tab, page }) { const dataViewerDatabaseDataModel = useDataViewerDatabaseDataModel(tab); const pageState = page.getState(tab); - const handlePresentationChange = useCallback((presentationId: string) => { - const pageState = page.getState(tab); + const handlePresentationChange = useCallback( + (presentationId: string) => { + const pageState = page.getState(tab); - if (!pageState) { - page.setState(tab, { - presentationId, - resultIndex: 0, - valuePresentationId: null, - }); - } else { - pageState.presentationId = presentationId; - } - }, [page, tab]); + if (!pageState) { + page.setState(tab, { + presentationId, + resultIndex: 0, + valuePresentationId: null, + }); + } else { + pageState.presentationId = presentationId; + } + }, + [page, tab], + ); - const handleValuePresentationChange = useCallback((valuePresentationId: string | null) => { - const pageState = page.getState(tab); + const handleValuePresentationChange = useCallback( + (valuePresentationId: string | null) => { + const pageState = page.getState(tab); - if (!pageState) { - page.setState(tab, { - presentationId: '', - resultIndex: 0, - valuePresentationId, - }); - } else { - pageState.valuePresentationId = valuePresentationId; - } - }, [page, tab]); + if (!pageState) { + page.setState(tab, { + presentationId: '', + resultIndex: 0, + valuePresentationId, + }); + } else { + pageState.valuePresentationId = valuePresentationId; + } + }, + [page, tab], + ); if (!tab.handlerState.tableId) { return Table model not loaded; @@ -77,6 +79,6 @@ export const DataViewerPanel: ObjectPagePanelComponent = o ) : ( Table model not loaded )} - + , ); }); diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerPage/DataViewerTab.tsx b/webapp/packages/plugin-data-viewer/src/DataViewerPage/DataViewerTab.tsx index 2fbde9c9e0..55a68ec5e8 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerPage/DataViewerTab.tsx +++ b/webapp/packages/plugin-data-viewer/src/DataViewerPage/DataViewerTab.tsx @@ -5,22 +5,18 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; -import { useStyles, Translate } from '@cloudbeaver/core-blocks'; +import { Translate, useStyles } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { NavNodeManagerService } from '@cloudbeaver/core-navigation-tree'; -import { TabIcon, Tab, TabTitle } from '@cloudbeaver/core-ui'; +import { Tab, TabIcon, TabTitle } from '@cloudbeaver/core-ui'; import type { ObjectPageTabComponent } from '@cloudbeaver/plugin-object-viewer'; import type { IDataViewerPageState } from '../IDataViewerPageState'; - -export const DataViewerTab: ObjectPageTabComponent = observer(function DataViewerTab({ - tab, page, onSelect, style, -}) { +export const DataViewerTab: ObjectPageTabComponent = observer(function DataViewerTab({ tab, page, onSelect, style }) { const styles = useStyles(style); const navNodeManagerService = useService(NavNodeManagerService); @@ -30,8 +26,10 @@ export const DataViewerTab: ObjectPageTabComponent = obser return styled(styles)( - - - + + + + + , ); }); diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerPage/useDataViewerDatabaseDataModel.ts b/webapp/packages/plugin-data-viewer/src/DataViewerPage/useDataViewerDatabaseDataModel.ts index fbfec1e74b..c1b7ea7550 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerPage/useDataViewerDatabaseDataModel.ts +++ b/webapp/packages/plugin-data-viewer/src/DataViewerPage/useDataViewerDatabaseDataModel.ts @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, computed, observable } from 'mobx'; import { useEffect } from 'react'; -import { useResource, useObservableRef } from '@cloudbeaver/core-blocks'; +import { useObservableRef, useResource } from '@cloudbeaver/core-blocks'; import { ConnectionInfoResource } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { NavNodeManagerService } from '@cloudbeaver/core-navigation-tree'; @@ -38,121 +37,114 @@ export function useDataViewerDatabaseDataModel(tab: ITab) const dataPresentationService = useService(DataPresentationService); const dataViewerDataChangeConfirmationService = useService(DataViewerDataChangeConfirmationService); - const connection = useResource( - useDataViewerDatabaseDataModel, - ConnectionInfoResource, - tab.handlerState.connectionKey ?? null - ); + const connection = useResource(useDataViewerDatabaseDataModel, ConnectionInfoResource, tab.handlerState.connectionKey ?? null); - const state = useObservableRef(() => ({ - _exception: null, - _loading: false, - get exception() { - if (isContainsException(connection.exception)) { - return connection.exception; - } - return this._exception; - }, - isLoading(): boolean { - return connection.isLoading() || this._loading; - }, - isLoaded(): boolean { - return connection.isLoaded() && dataViewerTableService.get(this.tab.handlerState.tableId || '') !== undefined; - }, - async reload() { - if (isContainsException(connection.exception)) { - connection.reload(); - } - this.init(); - }, - async load() { - if (isContainsException(this.exception)) { - return; - } - - await this.init(); - }, - async init() { - if (this._loading) { - return; - } - this._loading = true; - try { - if (!this.tab.handlerState.connectionKey) { - this._exception = null; + const state = useObservableRef( + () => ({ + _exception: null, + _loading: false, + get exception() { + if (isContainsException(connection.exception)) { + return connection.exception; + } + return this._exception; + }, + isLoading(): boolean { + return connection.isLoading() || this._loading; + }, + isLoaded(): boolean { + return connection.isLoaded() && dataViewerTableService.get(this.tab.handlerState.tableId || '') !== undefined; + }, + async reload() { + if (isContainsException(connection.exception)) { + connection.reload(); + } + this.init(); + }, + async load() { + if (isContainsException(this.exception)) { return; } - const node = navNodeManagerService.getNode({ - nodeId: this.tab.handlerState.objectId, - parentId: this.tab.handlerState.parentId, - }); - - if (!navNodeManagerService.isNodeHasData(node)) { - this._exception = null; + await this.init(); + }, + async init() { + if (this._loading) { return; } - - let model = dataViewerTableService.get(this.tab.handlerState.tableId || ''); - - if ( - model - && !model.source.executionContext?.context - && model.source.results.length > 0 - ) { - model.resetData(); - } - - if (!model) { - await connectionInfoResource.waitLoad(); - const connectionInfo = connectionInfoResource.get(this.tab.handlerState.connectionKey); - - if (!connectionInfo) { - throw new Error('Connection doesn\'t exists'); + this._loading = true; + try { + if (!this.tab.handlerState.connectionKey) { + this._exception = null; + return; } - model = dataViewerTableService.create( - connectionInfo, - node - ); - this.tab.handlerState.tableId = model.id; - model.source.setOutdated(); - dataViewerDataChangeConfirmationService.trackTableDataUpdate(model.id); + const node = navNodeManagerService.getNode({ + nodeId: this.tab.handlerState.objectId, + parentId: this.tab.handlerState.parentId, + }); - const pageState = dataViewerTabService.page.getState(this.tab); + if (!navNodeManagerService.isNodeHasData(node)) { + this._exception = null; + return; + } - if (pageState) { - const presentation = dataPresentationService.get(pageState.presentationId); + let model = dataViewerTableService.get(this.tab.handlerState.tableId || ''); - if (presentation?.dataFormat !== undefined) { - model.setDataFormat(presentation.dataFormat); + if (model && !model.source.executionContext?.context && model.source.results.length > 0) { + model.resetData(); + } + + if (!model) { + await connectionInfoResource.waitLoad(); + const connectionInfo = connectionInfoResource.get(this.tab.handlerState.connectionKey); + + if (!connectionInfo) { + throw new Error("Connection doesn't exists"); + } + + model = dataViewerTableService.create(connectionInfo, node); + this.tab.handlerState.tableId = model.id; + model.source.setOutdated(); + dataViewerDataChangeConfirmationService.trackTableDataUpdate(model.id); + + const pageState = dataViewerTabService.page.getState(this.tab); + + if (pageState) { + const presentation = dataPresentationService.get(pageState.presentationId); + + if (presentation?.dataFormat !== undefined) { + model.setDataFormat(presentation.dataFormat); + } } } - } - model.setName(node?.name || null); - this._exception = null; - } catch (exception: any) { - this._exception = exception; - } finally { - this._loading = false; - } + model.setName(node?.name || null); + this._exception = null; + } catch (exception: any) { + this._exception = exception; + } finally { + this._loading = false; + } + }, + }), + { + exception: computed, + _loading: observable.ref, + _exception: observable.ref, + tab: observable.ref, + isLoaded: action.bound, + isLoading: action.bound, + reload: action.bound, }, - }), { - exception: computed, - _loading: observable.ref, - _exception: observable.ref, - tab: observable.ref, - isLoaded: action.bound, - isLoading: action.bound, - reload: action.bound, - }, { - tab, - }); + { + tab, + }, + ); useEffect(() => { state.load(); }); return state; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerService.ts b/webapp/packages/plugin-data-viewer/src/DataViewerService.ts index 01d0a61ff4..2de32016b6 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerService.ts +++ b/webapp/packages/plugin-data-viewer/src/DataViewerService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { Connection } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; @@ -13,9 +12,7 @@ import { DataViewerSettingsService } from './DataViewerSettingsService'; @injectable() export class DataViewerService { - constructor( - private readonly dataViewerSettingsService: DataViewerSettingsService, - ) { } + constructor(private readonly dataViewerSettingsService: DataViewerSettingsService) {} isDataEditable(connection: Connection) { const disabled = this.dataViewerSettingsService.settings.isValueDefault('disableEdit') @@ -23,4 +20,4 @@ export class DataViewerService { : this.dataViewerSettingsService.settings.getValue('disableEdit'); return !disabled && !connection.readOnly; } -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.test.ts b/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.test.ts index 9cf77aa0e1..ce3f0e7a45 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.test.ts +++ b/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.test.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import '@testing-library/jest-dom'; import { mockAuthentication } from '@cloudbeaver/core-authentication/mocks/mockAuthentication'; @@ -24,18 +23,9 @@ import { DataViewerSettings, DataViewerSettingsService } from './DataViewerSetti import { manifest } from './manifest'; const endpoint = createGQLEndpoint(); -const app = createApp( - datasourceContextSwitch, - navigationTree, - navigationTabs, - objectViewer, - manifest -); +const app = createApp(datasourceContextSwitch, navigationTree, navigationTabs, objectViewer, manifest); -const server = mockGraphQL( - ...mockAppInit(endpoint), - ...mockAuthentication(endpoint) -); +const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint)); beforeAll(() => app.init()); @@ -68,9 +58,7 @@ async function setupSettingsService(mockConfig: any = {}) { const settings = app.injector.getServiceByClass(DataViewerSettingsService); const config = app.injector.getServiceByClass(ServerConfigResource); - server.use( - endpoint.query('serverConfig', mockServerConfig(mockConfig)), - ); + server.use(endpoint.query('serverConfig', mockServerConfig(mockConfig))); await config.refresh(); diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.ts b/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.ts index e4864ee4e8..8310850e78 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.ts +++ b/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.ts @@ -5,7 +5,6 @@ * 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 { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin'; @@ -34,10 +33,7 @@ export class DataViewerSettingsService { count = 0; } return count !== undefined - ? Math.max( - this.settings.getValue('fetchMin'), - Math.min(count, this.settings.getValue('fetchMax')) - ) + ? Math.max(this.settings.getValue('fetchMin'), Math.min(count, this.settings.getValue('fetchMax'))) : this.settings.getValue('fetchDefault'); } -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerTabService.ts b/webapp/packages/plugin-data-viewer/src/DataViewerTabService.ts index c60d0dfdea..121bdce6fc 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerTabService.ts +++ b/webapp/packages/plugin-data-viewer/src/DataViewerTabService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { ConnectionInfoResource, ConnectionsManagerService, IConnectionExecutorData } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; @@ -13,7 +12,7 @@ import { ExecutorInterrupter, IExecutionContextProvider } from '@cloudbeaver/cor import { INodeNavigationData, NavigationType, NavNodeManagerService } from '@cloudbeaver/core-navigation-tree'; import { resourceKeyList } from '@cloudbeaver/core-sdk'; import { ITab, NavigationTabsService } from '@cloudbeaver/plugin-navigation-tabs'; -import { DBObjectPageService, ObjectPage, ObjectViewerTabService, IObjectViewerTabState, isObjectViewerTab } from '@cloudbeaver/plugin-object-viewer'; +import { DBObjectPageService, IObjectViewerTabState, isObjectViewerTab, ObjectPage, ObjectViewerTabService } from '@cloudbeaver/plugin-object-viewer'; import { DataViewerPanel } from './DataViewerPage/DataViewerPanel'; import { DataViewerTab } from './DataViewerPage/DataViewerTab'; @@ -32,7 +31,7 @@ export class DataViewerTabService { private readonly notificationService: NotificationService, private readonly connectionsManagerService: ConnectionsManagerService, private readonly navigationTabsService: NavigationTabsService, - private readonly connectionInfoResource: ConnectionInfoResource + private readonly connectionInfoResource: ConnectionInfoResource, ) { this.page = this.dbObjectPageService.register({ key: 'data_viewer_data', @@ -54,20 +53,19 @@ export class DataViewerTabService { this.navNodeManagerService.navigator.addHandler(this.navigationHandler.bind(this)); } - private async disconnectHandler( - data: IConnectionExecutorData, - contexts: IExecutionContextProvider - ) { + private async disconnectHandler(data: IConnectionExecutorData, contexts: IExecutionContextProvider) { const connectionsKey = resourceKeyList(data.connections); if (data.state === 'before') { - const tabs = Array.from(this.navigationTabsService.findTabs( - isObjectViewerTab(tab => { - if (!tab.handlerState.connectionKey) { - return false; - } - return this.connectionInfoResource.isIntersect(connectionsKey, tab.handlerState.connectionKey); - }) - )); + const tabs = Array.from( + this.navigationTabsService.findTabs( + isObjectViewerTab(tab => { + if (!tab.handlerState.connectionKey) { + return false; + } + return this.connectionInfoResource.isIntersect(connectionsKey, tab.handlerState.connectionKey); + }), + ), + ); for (const tab of tabs) { const canDisconnect = await this.handleTabCanClose(tab); @@ -86,12 +84,7 @@ export class DataViewerTabService { } try { - const { - nodeInfo, - tabInfo, - initTab, - trySwitchPage, - } = await contexts.getContext(this.objectViewerTabService.objectViewerTabContext); + const { nodeInfo, tabInfo, initTab, trySwitchPage } = await contexts.getContext(this.objectViewerTabService.objectViewerTabContext); const node = await this.navNodeManagerService.loadNode(nodeInfo); @@ -122,7 +115,7 @@ export class DataViewerTabService { await model.requestDataAction(() => { canClose = true; }); - } catch { } + } catch {} return canClose; } diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerTableService.ts b/webapp/packages/plugin-data-viewer/src/DataViewerTableService.ts index 1dc76a1a7f..2ecd821dc2 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerTableService.ts +++ b/webapp/packages/plugin-data-viewer/src/DataViewerTableService.ts @@ -5,8 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { ConnectionExecutionContextService, Connection, createConnectionParam } from '@cloudbeaver/core-connections'; +import { Connection, ConnectionExecutionContextService, createConnectionParam } from '@cloudbeaver/core-connections'; import { App, injectable } from '@cloudbeaver/core-di'; import { EObjectFeature, NavNode, NavNodeManagerService } from '@cloudbeaver/core-navigation-tree'; import { AsyncTaskInfoService, GraphQLService } from '@cloudbeaver/core-sdk'; @@ -31,7 +30,7 @@ export class DataViewerTableService { private readonly connectionExecutionContextService: ConnectionExecutionContextService, private readonly dataViewerService: DataViewerService, private readonly dataViewerSettingsService: DataViewerSettingsService, - ) { } + ) {} has(tableId: string): boolean { return this.tableViewerStorageService.has(tableId); @@ -50,12 +49,8 @@ export class DataViewerTableService { } } - create( - connection: Connection, - node: NavNode | undefined - ): IDatabaseDataModel { - const nodeInfo = this.navNodeManagerService - .getNodeContainerInfo(node?.id ?? ''); + create(connection: Connection, node: NavNode | undefined): IDatabaseDataModel { + const nodeInfo = this.navNodeManagerService.getNodeContainerInfo(node?.id ?? ''); const source = new ContainerDataSource( this.app.getServiceInjector(), @@ -77,7 +72,8 @@ export class DataViewerTableService { .setConstraintsAvailable(node?.objectFeatures.includes(EObjectFeature.supportsDataFilter) ?? true); const editable = this.dataViewerService.isDataEditable(connection); - const dataModel = this.tableViewerStorageService.add(new DatabaseDataModel(source)) + const dataModel = this.tableViewerStorageService + .add(new DatabaseDataModel(source)) .setCountGain(this.dataViewerSettingsService.getDefaultRowsCount()) .setSlice(0) .setAccess(editable ? DatabaseDataAccessMode.Default : DatabaseDataAccessMode.Readonly); diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/DatabaseDataActionDecorator.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/DatabaseDataActionDecorator.ts index 5787c683f7..99a265efab 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/DatabaseDataActionDecorator.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/DatabaseDataActionDecorator.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IDatabaseDataActionInterface } from '../IDatabaseDataAction'; const ACTION_PARAMS = 'custom:data-viewer/action/params'; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/DatabaseEditAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/DatabaseEditAction.ts index ae4b570784..4a1bd1e736 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/DatabaseEditAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/DatabaseEditAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor'; import type { ResultDataFormat } from '@cloudbeaver/core-sdk'; @@ -13,12 +12,18 @@ import { DatabaseDataAction } from '../DatabaseDataAction'; import type { IDatabaseDataResult } from '../IDatabaseDataResult'; import type { IDatabaseDataSource } from '../IDatabaseDataSource'; import { databaseDataAction } from './DatabaseDataActionDecorator'; -import type { DatabaseEditChangeType, IDatabaseDataEditAction, IDatabaseDataEditActionData, IDatabaseDataEditApplyActionData } from './IDatabaseDataEditAction'; +import type { + DatabaseEditChangeType, + IDatabaseDataEditAction, + IDatabaseDataEditActionData, + IDatabaseDataEditApplyActionData, +} from './IDatabaseDataEditAction'; @databaseDataAction() export abstract class DatabaseEditAction extends DatabaseDataAction - implements IDatabaseDataEditAction { + implements IDatabaseDataEditAction +{ static dataFormat: ResultDataFormat[] | null = null; readonly action: ISyncExecutor>; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/DatabaseSelectAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/DatabaseSelectAction.ts index e39be2d3b7..8b44552b34 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/DatabaseSelectAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/DatabaseSelectAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor'; import type { ResultDataFormat } from '@cloudbeaver/core-sdk'; @@ -18,7 +17,8 @@ import type { DatabaseDataSelectActionsData, IDatabaseDataSelectAction } from '. @databaseDataAction() export abstract class DatabaseSelectAction extends DatabaseDataAction - implements IDatabaseDataSelectAction { + implements IDatabaseDataSelectAction +{ static dataFormat: ResultDataFormat[] | null = null; readonly actions: ISyncExecutor>; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentDataAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentDataAction.ts index 98fb40fcc5..856964c30a 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentDataAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentDataAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed, makeObservable } from 'mobx'; import { ResultDataFormat } from '@cloudbeaver/core-sdk'; @@ -18,8 +17,7 @@ import type { IDatabaseDataResultAction } from '../IDatabaseDataResultAction'; import type { IDatabaseDataDocument } from './IDatabaseDataDocument'; @databaseDataAction() -export class DocumentDataAction extends DatabaseDataAction - implements IDatabaseDataResultAction { +export class DocumentDataAction extends DatabaseDataAction implements IDatabaseDataResultAction { static dataFormat = [ResultDataFormat.Document]; get documents(): IDatabaseDataDocument[] { diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentEditAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentEditAction.ts index df45c01d2b..fa35ebabdf 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentEditAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentEditAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { makeObservable, observable } from 'mobx'; import { ResultDataFormat, SqlResultRow, UpdateResultsDataBatchMutationVariables } from '@cloudbeaver/core-sdk'; @@ -20,18 +19,13 @@ import type { IDatabaseDataDocument } from './IDatabaseDataDocument'; import type { IDocumentElementKey } from './IDocumentElementKey'; @databaseDataAction() -export class DocumentEditAction - extends DatabaseEditAction { +export class DocumentEditAction extends DatabaseEditAction { static dataFormat = [ResultDataFormat.Document]; readonly editedElements: Map; private readonly data: DocumentDataAction; - constructor( - source: IDatabaseDataSource, - result: IDatabaseResultSet, - data: DocumentDataAction - ) { + constructor(source: IDatabaseDataSource, result: IDatabaseResultSet, data: DocumentDataAction) { super(source, result); this.editedElements = new Map(); this.data = data; @@ -82,11 +76,13 @@ export class DocumentEditAction type: DatabaseEditChangeType.update, revert: false, resultId: this.result.id, - value: [{ - key: key, - prevValue, - value, - }], + value: [ + { + key: key, + prevValue, + value, + }, + ], }); this.removeUnchanged(key); @@ -121,7 +117,7 @@ export class DocumentEditAction ...previousValue, data: value, }, - previousValue + previousValue, ); } @@ -170,7 +166,8 @@ export class DocumentEditAction updatedRows.push({ data: [this.data.get(id)], - updateValues: { // TODO: remove, place new document in data field + updateValues: { + // TODO: remove, place new document in data field 0: document, }, }); diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataConstraintAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataConstraintAction.ts index 8e0845d3e3..e403758390 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataConstraintAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataConstraintAction.ts @@ -5,15 +5,13 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { SqlDataFilterConstraint } from '@cloudbeaver/core-sdk'; import type { IDatabaseDataAction } from '../IDatabaseDataAction'; import type { IDatabaseDataResult } from '../IDatabaseDataResult'; import type { Order } from '../Order'; -export interface IDatabaseDataConstraintAction - extends IDatabaseDataAction { +export interface IDatabaseDataConstraintAction extends IDatabaseDataAction { readonly filterConstraints: SqlDataFilterConstraint[]; readonly orderConstraints: SqlDataFilterConstraint[]; readonly supported: boolean; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataEditAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataEditAction.ts index 927136b134..687b7c6da2 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataEditAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataEditAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { ISyncExecutor } from '@cloudbeaver/core-executor'; import type { IDatabaseDataAction } from '../IDatabaseDataAction'; @@ -15,7 +14,7 @@ import type { IDatabaseDataResult } from '../IDatabaseDataResult'; export enum DatabaseEditChangeType { update, add, - delete + delete, } export interface IDatabaseDataEditActionValue { @@ -43,8 +42,7 @@ export interface IDatabaseDataEditActionData { value?: Array>; } -export interface IDatabaseDataEditAction - extends IDatabaseDataAction { +export interface IDatabaseDataEditAction extends IDatabaseDataAction { readonly action: ISyncExecutor>; readonly applyAction: ISyncExecutor>; isEdited: () => boolean; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataFormatAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataFormatAction.ts index 0fb3ef1d4f..997cd7eebc 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataFormatAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataFormatAction.ts @@ -5,12 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IDatabaseDataAction } from '../IDatabaseDataAction'; import type { IDatabaseDataResult } from '../IDatabaseDataResult'; -export interface IDatabaseDataFormatAction - extends IDatabaseDataAction { +export interface IDatabaseDataFormatAction extends IDatabaseDataAction { isReadOnly: (key: TKey) => boolean; get: (value: any) => any; getText: (value: any) => string | null; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataResultAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataResultAction.ts index 0bdc42a4c6..c74490c590 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataResultAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataResultAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IDatabaseDataAction } from '../IDatabaseDataAction'; import type { IDatabaseDataResult } from '../IDatabaseDataResult'; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataSelectAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataSelectAction.ts index e2dc0964f7..4bfe142982 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataSelectAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataSelectAction.ts @@ -5,28 +5,29 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { ISyncExecutor } from '@cloudbeaver/core-executor'; import type { IDatabaseDataAction } from '../IDatabaseDataAction'; import type { IDatabaseDataResult } from '../IDatabaseDataResult'; -export type DatabaseDataSelectActionsData = { - type: 'select'; - resultId: string | null; - key: TKey; - selected: boolean; -} | { - type: 'focus'; - resultId: string | null; - key: TKey | null; -} | { - type: 'clear'; - resultId: string | null; -}; +export type DatabaseDataSelectActionsData = + | { + type: 'select'; + resultId: string | null; + key: TKey; + selected: boolean; + } + | { + type: 'focus'; + resultId: string | null; + key: TKey | null; + } + | { + type: 'clear'; + resultId: string | null; + }; -export interface IDatabaseDataSelectAction - extends IDatabaseDataAction { +export interface IDatabaseDataSelectAction extends IDatabaseDataAction { readonly actions: ISyncExecutor>; isSelected: () => boolean; isElementSelected: (key: TKey) => boolean; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/Actions/DATA_VIEWER_CONSTRAINTS_DELETE_ACTION.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/Actions/DATA_VIEWER_CONSTRAINTS_DELETE_ACTION.ts index a6fb4f86e6..1270f3eef7 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/Actions/DATA_VIEWER_CONSTRAINTS_DELETE_ACTION.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/Actions/DATA_VIEWER_CONSTRAINTS_DELETE_ACTION.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; export const DATA_VIEWER_CONSTRAINTS_DELETE_ACTION = createAction('data-viewer-constraints-delete', { diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/Actions/DATA_VIEWER_REFRESH_ACTION.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/Actions/DATA_VIEWER_REFRESH_ACTION.ts index a55e8b9ae9..93b469677a 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/Actions/DATA_VIEWER_REFRESH_ACTION.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/Actions/DATA_VIEWER_REFRESH_ACTION.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; export const DATA_VIEWER_REFRESH_ACTION = createAction('data-viewer-refresh', { diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/DataContext/DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/DataContext/DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY.ts index 26b7e8e551..1b1b7eae06 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/DataContext/DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/DataContext/DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY.ts @@ -5,9 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createDataContext } from '@cloudbeaver/core-view'; import type { IResultSetColumnKey } from '../IResultSetDataKey'; -export const DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY = createDataContext('data-viewer-database-data-model-result-set-column-key'); +export const DATA_CONTEXT_DV_DDM_RS_COLUMN_KEY = createDataContext( + 'data-viewer-database-data-model-result-set-column-key', +); diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/IResultSetDataContentAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/IResultSetDataContentAction.ts index dc69d520fd..c4d547220c 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/IResultSetDataContentAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/IResultSetDataContentAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IResultSetContentValue } from './IResultSetContentValue'; import type { IResultSetElementKey } from './IResultSetDataKey'; @@ -18,4 +17,4 @@ export interface IResultSetDataContentAction { retrieveFileDataUrlFromCache: (element: IResultSetElementKey) => string | undefined; downloadFileData: (element: IResultSetElementKey) => Promise; clearCache: () => void; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetConstraintAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetConstraintAction.ts index 4ee8f8cac9..3eb63dc59d 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetConstraintAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetConstraintAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed, makeObservable } from 'mobx'; import { DataTypeLogicalOperation, ResultDataFormat, SqlDataFilterConstraint } from '@cloudbeaver/core-sdk'; @@ -22,8 +21,10 @@ export const IS_NULL_ID = 'IS_NULL'; export const IS_NOT_NULL_ID = 'IS_NOT_NULL'; @databaseDataAction() -export class ResultSetConstraintAction extends DatabaseDataAction - implements IDatabaseDataConstraintAction { +export class ResultSetConstraintAction + extends DatabaseDataAction + implements IDatabaseDataConstraintAction +{ static dataFormat = [ResultDataFormat.Resultset, ResultDataFormat.Document]; get supported(): boolean { @@ -59,8 +60,7 @@ export class ResultSetConstraintAction extends DatabaseDataAction constraint.attributePosition !== attributePosition); + this.source.options.constraints = this.source.options.constraints.filter(constraint => constraint.attributePosition !== attributePosition); } private deleteEmptyConstraint(attributePosition: number) { @@ -72,8 +72,7 @@ export class ResultSetConstraintAction extends DatabaseDataAction constraint.orderPosition !== undefined ? constraint.orderPosition + 1 : -1)); + return Math.max(0, ...this.orderConstraints.map(constraint => (constraint.orderPosition !== undefined ? constraint.orderPosition + 1 : -1))); } get(attributePosition: number): SqlDataFilterConstraint | undefined { @@ -274,8 +273,9 @@ export class ResultSetConstraintAction extends DatabaseDataAction prevConstraint.attributePosition === constraint.attributePosition); + const prevConstraint = this.source.prevOptions?.constraints.find( + prevConstraint => prevConstraint.attributePosition === constraint.attributePosition, + ); constraint.attributePosition = column.position; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts index 390731a30c..97e55d7263 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { computed, makeObservable } from 'mobx'; import { DataTypeLogicalOperation, ResultDataFormat, SqlResultColumn } from '@cloudbeaver/core-sdk'; @@ -21,8 +20,7 @@ import { isResultSetContentValue } from './isResultSetContentValue'; import type { IResultSetValue } from './ResultSetFormatAction'; @databaseDataAction() -export class ResultSetDataAction extends DatabaseDataAction - implements IDatabaseDataResultAction { +export class ResultSetDataAction extends DatabaseDataAction implements IDatabaseDataResultAction { static dataFormat = [ResultDataFormat.Resultset]; get rows(): IResultSetValue[][] { @@ -88,12 +86,7 @@ export class ResultSetDataAction extends DatabaseDataAction= this.rows.length - || cell.column.index >= this.columns.length - ) { + if (cell.row === undefined || cell.column === undefined || cell.row.index >= this.rows.length || cell.column.index >= this.columns.length) { return undefined; } @@ -131,7 +124,6 @@ export class ResultSetDataAction extends DatabaseDataAction operation.argumentCount === 1 || operation.argumentCount === 0); + return column.supportedOperations.filter(operation => operation.argumentCount === 1 || operation.argumentCount === 0); } } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataContentAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataContentAction.ts index d8ae35f0f7..d223d48cd9 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataContentAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataContentAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { makeObservable, observable } from 'mobx'; import { QuotasService } from '@cloudbeaver/core-root'; @@ -28,8 +27,7 @@ import { ResultSetViewAction } from './ResultSetViewAction'; const RESULT_VALUE_PATH = 'sql-result-value'; @databaseDataAction() -export class ResultSetDataContentAction extends DatabaseDataAction - implements IResultSetDataContentAction { +export class ResultSetDataContentAction extends DatabaseDataAction implements IResultSetDataContentAction { static dataFormat = [ResultDataFormat.Resultset]; private readonly view: ResultSetViewAction; @@ -83,17 +81,15 @@ export class ResultSetDataContentAction extends DatabaseDataAction { - try { - this.activeElement = element; - const fileName = await this.loadFileName(this.result, column.position, row); - return this.generateFileDataUrl(fileName); - } finally { - this.activeElement = null; - } + const url = await this.source.runTask(async () => { + try { + this.activeElement = element; + const fileName = await this.loadFileName(this.result, column.position, row); + return this.generateFileDataUrl(fileName); + } finally { + this.activeElement = null; } - ); + }); return url; } @@ -150,4 +146,4 @@ export class ResultSetDataContentAction extends DatabaseDataAction; @databaseDataAction() -export class ResultSetEditAction - extends DatabaseEditAction { +export class ResultSetEditAction extends DatabaseEditAction { static dataFormat = [ResultDataFormat.Resultset]; readonly applyAction: ISyncExecutor>; private readonly editorData: Map; private readonly data: ResultSetDataAction; - constructor( - source: IDatabaseDataSource, - result: IDatabaseResultSet, - data: ResultSetDataAction - ) { + constructor(source: IDatabaseDataSource, result: IDatabaseResultSet, data: ResultSetDataAction) { super(source, result); this.applyAction = new SyncExecutor(); this.editorData = new Map(); @@ -77,22 +77,21 @@ export class ResultSetEditAction } get updates(): IResultSetUpdate[] { - return Array.from(this.editorData.values()) - .sort((a, b) => { - if (a.type !== b.type) { - if (a.type === DatabaseEditChangeType.update) { - return -1; - } - - if (b.type === DatabaseEditChangeType.update) { - return 1; - } - - return a.type - b.type; + return Array.from(this.editorData.values()).sort((a, b) => { + if (a.type !== b.type) { + if (a.type === DatabaseEditChangeType.update) { + return -1; } - return a.row.index - b.row.index; - }); + if (b.type === DatabaseEditChangeType.update) { + return 1; + } + + return a.type - b.type; + } + + return a.row.index - b.row.index; + }); } isEdited(): boolean { @@ -142,9 +141,7 @@ export class ResultSetEditAction } get(key: IResultSetElementKey): IResultSetValue | undefined { - return this.editorData - .get(ResultSetDataKeysUtils.serialize(key.row)) - ?.update[key.column.index]; + return this.editorData.get(ResultSetDataKeysUtils.serialize(key.row))?.update[key.column.index]; } set(key: IResultSetElementKey, value: IResultSetValue): void { @@ -167,11 +164,13 @@ export class ResultSetEditAction resultId: this.result.id, type: update.type, revert: false, - value: [{ - key, - prevValue, - value, - }], + value: [ + { + key, + prevValue, + value, + }, + ], }); this.removeEmptyUpdate(update); @@ -205,9 +204,11 @@ export class ResultSetEditAction resultId: this.result.id, type: update.type, revert: false, - value: [{ - key: { column, row }, - }], + value: [ + { + key: { column, row }, + }, + ], }); } } @@ -232,8 +233,7 @@ export class ResultSetEditAction for (const row of rows) { let value = this.data.getRowValue(row); - const editedValue = this.editorData - .get(ResultSetDataKeysUtils.serialize(row)); + const editedValue = this.editorData.get(ResultSetDataKeysUtils.serialize(row)); if (editedValue) { value = editedValue.update; @@ -299,9 +299,11 @@ export class ResultSetEditAction resultId: this.result.id, type: update.type, revert: false, - value: [{ - key: { column, row: key }, - }], + value: [ + { + key: { column, row: key }, + }, + ], }); } } else if (!silent) { @@ -309,9 +311,11 @@ export class ResultSetEditAction resultId: this.result.id, type: update.type, revert: true, - value: [{ - key: { column, row: key }, - }], + value: [ + { + key: { column, row: key }, + }, + ], }); } } @@ -517,18 +521,12 @@ export class ResultSetEditAction return; } - if (update.source && !update.source.some( - (value, i) => !this.compareCellValue(value, update.update[i]) - )) { + if (update.source && !update.source.some((value, i) => !this.compareCellValue(value, update.update[i]))) { this.editorData.delete(ResultSetDataKeysUtils.serialize(update.row)); } } - private getOrCreateUpdate( - row: IResultSetRowKey, - type: DatabaseEditChangeType, - update?: IResultSetValue[] - ): [IResultSetUpdate, boolean] { + private getOrCreateUpdate(row: IResultSetRowKey, type: DatabaseEditChangeType, update?: IResultSetValue[]): [IResultSetUpdate, boolean] { const key = ResultSetDataKeysUtils.serialize(row); let created = false; @@ -538,14 +536,14 @@ export class ResultSetEditAction if (type !== DatabaseEditChangeType.add) { source = this.data.getRowValue(row); } else { - source = [...update || []]; + source = [...(update || [])]; } this.editorData.set(key, { row, type, source, - update: observable([...source || update || []]), + update: observable([...(source || update || [])]), }); created = true; } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetFormatAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetFormatAction.ts index adb3d7132a..718510da59 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetFormatAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetFormatAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { ResultDataFormat } from '@cloudbeaver/core-sdk'; import { removeLineBreak } from '@cloudbeaver/core-utils'; @@ -20,12 +19,13 @@ import { isResultSetContentValue } from './isResultSetContentValue'; import { ResultSetEditAction } from './ResultSetEditAction'; import { ResultSetViewAction } from './ResultSetViewAction'; -export type IResultSetValue = - string | number | boolean | Record | null> | null; +export type IResultSetValue = string | number | boolean | Record | null> | null; @databaseDataAction() -export class ResultSetFormatAction extends DatabaseDataAction - implements IDatabaseDataFormatAction { +export class ResultSetFormatAction + extends DatabaseDataAction + implements IDatabaseDataFormatAction +{ static dataFormat = [ResultDataFormat.Resultset]; private readonly view: ResultSetViewAction; @@ -35,7 +35,7 @@ export class ResultSetFormatAction extends DatabaseDataAction, result: IDatabaseResultSet, view: ResultSetViewAction, - edit: ResultSetEditAction + edit: ResultSetEditAction, ) { super(source, result); this.view = view; @@ -84,10 +84,7 @@ export class ResultSetFormatAction extends DatabaseDataAction 1000) { - return removeLineBreak(value.split('').map(v => (v.charCodeAt(0) < 32 ? ' ' : v)).join('')); + return removeLineBreak( + value + .split('') + .map(v => (v.charCodeAt(0) < 32 ? ' ' : v)) + .join(''), + ); } return removeLineBreak(String(value)); diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetSelectAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetSelectAction.ts index 023b809134..75bb3f2268 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetSelectAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetSelectAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, computed, IReactionDisposer, makeObservable, observable, reaction, toJS } from 'mobx'; import { ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor'; @@ -46,7 +45,7 @@ export class ResultSetSelectAction extends DatabaseSelectAction this.view.rowKeys, (current, previous) => { - if (this.focusedElement) { - const focus = this.focusedElement; - const currentIndex = current.findIndex(key => ResultSetDataKeysUtils.isEqual(key, focus.row)); + this.validationDisposer = reaction( + () => this.view.rowKeys, + (current, previous) => { + if (this.focusedElement) { + const focus = this.focusedElement; + const currentIndex = current.findIndex(key => ResultSetDataKeysUtils.isEqual(key, focus.row)); - const focusIndex = previous.findIndex(key => ResultSetDataKeysUtils.isEqual(key, focus.row)); + const focusIndex = previous.findIndex(key => ResultSetDataKeysUtils.isEqual(key, focus.row)); - if (currentIndex >= 0 && focusIndex === -1) { - return; - } - - if (focusIndex === -1 || current.length === 0) { - this.focus(null); - return; - } - - if (!current.some(key => ResultSetDataKeysUtils.isEqual(key, focus.row))) { - for (let index = focusIndex; index >= 0; index--) { - const previousElement = previous[index]; - const row = current.find(key => ResultSetDataKeysUtils.isEqual(key, previousElement)); - - if (row) { - this.focus({ ...this.focusedElement, row }); - return; - } - } - for (let index = focusIndex; index <= previous.length; index++) { - const nextElement = previous[index]; - const row = current.find(key => ResultSetDataKeysUtils.isEqual(key, nextElement)); - - if (row) { - this.focus({ ...this.focusedElement, row }); - return; - } + if (currentIndex >= 0 && focusIndex === -1) { + return; } - this.focus({ ...this.focusedElement, row: current[current.length - 1] }); + if (focusIndex === -1 || current.length === 0) { + this.focus(null); + return; + } + + if (!current.some(key => ResultSetDataKeysUtils.isEqual(key, focus.row))) { + for (let index = focusIndex; index >= 0; index--) { + const previousElement = previous[index]; + const row = current.find(key => ResultSetDataKeysUtils.isEqual(key, previousElement)); + + if (row) { + this.focus({ ...this.focusedElement, row }); + return; + } + } + for (let index = focusIndex; index <= previous.length; index++) { + const nextElement = previous[index]; + const row = current.find(key => ResultSetDataKeysUtils.isEqual(key, nextElement)); + + if (row) { + this.focus({ ...this.focusedElement, row }); + return; + } + } + + this.focus({ ...this.focusedElement, row: current[current.length - 1] }); + } } - } - }); + }, + ); this.edit.action.addHandler(this.syncFocus.bind(this)); this.edit.applyAction.addHandler(this.syncFocusOnUpdate.bind(this)); @@ -118,10 +120,7 @@ export class ResultSetSelectAction extends DatabaseSelectAction - implements IDatabaseDataResultAction { +export class ResultSetViewAction extends DatabaseDataAction implements IDatabaseDataResultAction { static dataFormat = [ResultDataFormat.Resultset]; get rowKeys(): IResultSetRowKey[] { - return [ - ...this.editor.addRows, - ...this.data.rows.map((c, index) => ({ index })), - ].sort((a, b) => a.index - b.index); + return [...this.editor.addRows, ...this.data.rows.map((c, index) => ({ index }))].sort((a, b) => a.index - b.index); } get columnKeys(): IResultSetColumnKey[] { @@ -54,7 +49,7 @@ export class ResultSetViewAction extends DatabaseDataAction, result: IDatabaseResultSet, data: ResultSetDataAction, - editor: ResultSetEditAction + editor: ResultSetEditAction, ) { super(source, result); this.data = data; @@ -128,10 +123,7 @@ export class ResultSetViewAction extends DatabaseDataAction= this.rows.length - || cell.column.index >= this.columns.length - ) { + if (cell.row.index >= this.rows.length || cell.column.index >= this.columns.length) { return undefined; } @@ -163,7 +155,6 @@ export class ResultSetViewAction extends DatabaseDataAction operation.argumentCount === 1 || operation.argumentCount === 0); + return column.supportedOperations.filter(operation => operation.argumentCount === 1 || operation.argumentCount === 0); } } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/isResultSetContentValue.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/isResultSetContentValue.ts index d3268f3e89..38303410d7 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/isResultSetContentValue.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/isResultSetContentValue.ts @@ -5,12 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IResultSetContentValue } from './IResultSetContentValue'; export function isResultSetContentValue(value: any): value is IResultSetContentValue { - return value !== null - && typeof value === 'object' - && '$type' in value - && value.$type === 'content'; -} \ No newline at end of file + return value !== null && typeof value === 'object' && '$type' in value && value.$type === 'content'; +} diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DataContext/DATA_CONTEXT_DV_DDM.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DataContext/DATA_CONTEXT_DV_DDM.ts index fd4525fc68..adf6271e05 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DataContext/DATA_CONTEXT_DV_DDM.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DataContext/DATA_CONTEXT_DV_DDM.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createDataContext } from '@cloudbeaver/core-view'; import type { IDatabaseDataModel } from '../IDatabaseDataModel'; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DataContext/DATA_CONTEXT_DV_DDM_RESULT_INDEX.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DataContext/DATA_CONTEXT_DV_DDM_RESULT_INDEX.ts index f7bb63e9b9..150409518e 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DataContext/DATA_CONTEXT_DV_DDM_RESULT_INDEX.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DataContext/DATA_CONTEXT_DV_DDM_RESULT_INDEX.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createDataContext } from '@cloudbeaver/core-view'; export const DATA_CONTEXT_DV_DDM_RESULT_INDEX = createDataContext('data-viewer-database-data-model-result-index'); diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataAction.ts index db580a26ec..55004c5c69 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataAction.ts @@ -5,15 +5,13 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { makeObservable, observable } from 'mobx'; import type { IDatabaseDataAction, IDatabaseDataActionClass, IDatabaseDataActionInterface } from './IDatabaseDataAction'; import type { IDatabaseDataResult } from './IDatabaseDataResult'; import type { IDatabaseDataSource } from './IDatabaseDataSource'; -export abstract class DatabaseDataAction -implements IDatabaseDataAction { +export abstract class DatabaseDataAction implements IDatabaseDataAction { result: TResult; get resultIndex(): number { @@ -39,29 +37,25 @@ implements IDatabaseDataAction { this.result = result; } - updateResults(results: TResult[]): void { } + updateResults(results: TResult[]): void {} - afterResultUpdate(): void { } + afterResultUpdate(): void {} - tryGetAction>( - action: IDatabaseDataActionClass - ): T | undefined { + tryGetAction>(action: IDatabaseDataActionClass): T | undefined { return this.source.actions.tryGet(this.result, action); } - getAction>( - action: IDatabaseDataActionClass - ): T { + getAction>(action: IDatabaseDataActionClass): T { return this.source.actions.get(this.result, action); } getActionImplementation>( - action: IDatabaseDataActionInterface + action: IDatabaseDataActionInterface, ): T | undefined { return this.source.actions.getImplementation(this.result, action); } - dispose(): void { } + dispose(): void {} } export function isDatabaseDataAction(action: any): action is IDatabaseDataActionClass { diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataActions.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataActions.ts index 10a073f9b1..3faf9542e8 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataActions.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataActions.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, makeObservable, observable, runInAction } from 'mobx'; import { getDependingDataActions } from './Actions/DatabaseDataActionDecorator'; @@ -17,8 +16,7 @@ import type { IDatabaseDataSource } from './IDatabaseDataSource'; type ActionsList = Array>; -export class DatabaseDataActions -implements IDatabaseDataActions { +export class DatabaseDataActions implements IDatabaseDataActions { private readonly actions: Map>; private readonly source: IDatabaseDataSource; @@ -33,10 +31,7 @@ implements IDatabaseDataActions { }); } - tryGet>( - result: TResult, - Action: IDatabaseDataActionClass - ): T | undefined { + tryGet>(result: TResult, Action: IDatabaseDataActionClass): T | undefined { if (Action.dataFormat && !Action.dataFormat.includes(result.dataFormat)) { return undefined; } @@ -44,10 +39,7 @@ implements IDatabaseDataActions { return this.get(result, Action); } - get>( - result: TResult, - Action: IDatabaseDataActionClass - ): T { + get>(result: TResult, Action: IDatabaseDataActionClass): T { if (Action.dataFormat && !Action.dataFormat.includes(result.dataFormat)) { throw new Error('DataFormat unsupported'); } @@ -58,8 +50,7 @@ implements IDatabaseDataActions { let action = actions.find(action => action instanceof Action); if (!action) { - const allDeps = getDependingDataActions(Action) - .slice(2); // skip source and result arguments + const allDeps = getDependingDataActions(Action).slice(2); // skip source and result arguments const depends: any[] = []; @@ -84,7 +75,7 @@ implements IDatabaseDataActions { getImplementation>( result: TResult, - Action: IDatabaseDataActionInterface + Action: IDatabaseDataActionInterface, ): T | undefined { const actions = this.getActionsList(result.uniqueResultId); const action = actions?.find(action => action instanceof Action); @@ -122,11 +113,7 @@ implements IDatabaseDataActions { } } - private addActionToList( - resultId: string, - actions: ActionsList, - action: IDatabaseDataAction - ) { + private addActionToList(resultId: string, actions: ActionsList, action: IDatabaseDataAction) { actions.push(action); } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataFormat.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataFormat.ts index f372fc557a..47e1dd344a 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataFormat.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataFormat.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { DatabaseDataModel } from './DatabaseDataModel'; export interface DatabaseDataFormat { diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataModel.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataModel.ts index 0b7a98cc79..0c0deb2a4e 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataModel.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataModel.ts @@ -5,8 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { observable, makeObservable } from 'mobx'; +import { makeObservable, observable } from 'mobx'; import { Executor, ExecutorInterrupter, IExecutor } from '@cloudbeaver/core-executor'; import type { ResultDataFormat } from '@cloudbeaver/core-sdk'; @@ -16,8 +15,7 @@ import type { IDatabaseDataModel, IRequestEventData } from './IDatabaseDataModel import type { IDatabaseDataResult } from './IDatabaseDataResult'; import type { DatabaseDataAccessMode, IDatabaseDataSource, IRequestInfo } from './IDatabaseDataSource'; -export class DatabaseDataModel -implements IDatabaseDataModel { +export class DatabaseDataModel implements IDatabaseDataModel { id: string; name: string | null; source: IDatabaseDataSource; @@ -147,18 +145,12 @@ implements IDatabaseDataModel { } async reload(): Promise { - await this.requestDataAction(() => this.source - .setSlice(0, this.countGain) - .requestData() - ); + await this.requestDataAction(() => this.source.setSlice(0, this.countGain).requestData()); } async requestDataPortion(offset: number, count: number): Promise { if (!this.isDataAvailable(offset, count)) { - await this.requestDataAction(() => this.source - .setSlice(offset, count) - .requestData() - ); + await this.requestDataAction(() => this.source.setSlice(offset, count).requestData()); } } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataSource.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataSource.ts index 1fb86f02aa..e757d3c1bb 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataSource.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataSource.ts @@ -5,8 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { observable, makeObservable, action, toJS } from 'mobx'; +import { action, makeObservable, observable, toJS } from 'mobx'; import type { IConnectionExecutionContext } from '@cloudbeaver/core-connections'; import type { IServiceInjector } from '@cloudbeaver/core-di'; @@ -18,8 +17,7 @@ import type { IDatabaseDataActions } from './IDatabaseDataActions'; import type { IDatabaseDataResult } from './IDatabaseDataResult'; import { DatabaseDataAccessMode, IDatabaseDataSource, IRequestInfo } from './IDatabaseDataSource'; -export abstract class DatabaseDataSource -implements IDatabaseDataSource { +export abstract class DatabaseDataSource implements IDatabaseDataSource { access: DatabaseDataAccessMode; dataFormat: ResultDataFormat; supportedDataFormats: ResultDataFormat[]; @@ -99,15 +97,15 @@ implements IDatabaseDataSource { tryGetAction>( resultIndex: number, - action: IDatabaseDataActionClass + action: IDatabaseDataActionClass, ): T | undefined; tryGetAction>( result: TResult, - action: IDatabaseDataActionClass + action: IDatabaseDataActionClass, ): T | undefined; tryGetAction>( resultIndex: number | TResult, - action: IDatabaseDataActionClass + action: IDatabaseDataActionClass, ): T | undefined { if (typeof resultIndex === 'number') { if (!this.hasResult(resultIndex)) { @@ -119,17 +117,11 @@ implements IDatabaseDataSource { return this.actions.tryGet(resultIndex, action); } - getAction>( - resultIndex: number, - action: IDatabaseDataActionClass - ): T; - getAction>( - result: TResult, - action: IDatabaseDataActionClass - ): T; + getAction>(resultIndex: number, action: IDatabaseDataActionClass): T; + getAction>(result: TResult, action: IDatabaseDataActionClass): T; getAction>( resultIndex: number | TResult, - action: IDatabaseDataActionClass + action: IDatabaseDataActionClass, ): T { if (typeof resultIndex === 'number') { if (!this.hasResult(resultIndex)) { @@ -143,15 +135,15 @@ implements IDatabaseDataSource { getActionImplementation>( resultIndex: number, - action: IDatabaseDataActionInterface + action: IDatabaseDataActionInterface, ): T | undefined; getActionImplementation>( result: TResult, - action: IDatabaseDataActionInterface + action: IDatabaseDataActionInterface, ): T | undefined; getActionImplementation>( resultIndex: number | TResult, - action: IDatabaseDataActionInterface + action: IDatabaseDataActionInterface, ): T | undefined { if (typeof resultIndex === 'number') { if (!this.hasResult(resultIndex)) { @@ -193,10 +185,7 @@ implements IDatabaseDataSource { } isReadonly(resultIndex: number): boolean { - return this.access === DatabaseDataAccessMode.Readonly - || this.results.length > 1 - || !this.executionContext?.context - || this.disabled; + return this.access === DatabaseDataAccessMode.Readonly || this.results.length > 1 || !this.executionContext?.context || this.disabled; } isLoading(): boolean { @@ -255,19 +244,19 @@ implements IDatabaseDataSource { if (this.activeTask) { try { await this.activeTask; - } catch { } + } catch {} } if (this.activeSave) { try { await this.activeSave; - } catch { } + } catch {} } if (this.activeRequest) { try { await this.activeRequest; - } catch { } + } catch {} } this.activeTask = task(); @@ -283,7 +272,8 @@ implements IDatabaseDataSource { if (this.activeSave) { try { await this.activeSave; - } finally { } + } finally { + } } if (this.activeRequest) { @@ -317,7 +307,8 @@ implements IDatabaseDataSource { if (this.activeRequest) { try { await this.activeRequest; - } finally { } + } finally { + } } if (this.activeSave) { diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataAction.ts index fbdb9f7428..99167680e3 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataAction.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { ResultDataFormat } from '@cloudbeaver/core-sdk'; import type { IDatabaseDataResult } from './IDatabaseDataResult'; @@ -14,18 +13,10 @@ import type { IDatabaseDataSource } from './IDatabaseDataSource'; type AbstractConstructorFunction< TOptions, TResult extends IDatabaseDataResult, - TAction extends IDatabaseDataAction -> = abstract new ( - source: IDatabaseDataSource, - result: TResult, - ...actions: any[] -) => TAction; + TAction extends IDatabaseDataAction, +> = abstract new (source: IDatabaseDataSource, result: TResult, ...actions: any[]) => TAction; -type ConstructorFunction< - TOptions, - TResult extends IDatabaseDataResult, - TAction extends IDatabaseDataAction -> = new ( +type ConstructorFunction> = new ( source: IDatabaseDataSource, result: TResult, ...actions: any[] @@ -34,7 +25,7 @@ type ConstructorFunction< export type IDatabaseDataActionInterface< TOptions, TResult extends IDatabaseDataResult, - TAction extends IDatabaseDataAction + TAction extends IDatabaseDataAction, > = AbstractConstructorFunction & { dataFormat: ResultDataFormat[] | null; prototype: TAction; @@ -43,7 +34,7 @@ export type IDatabaseDataActionInterface< export type IDatabaseDataActionClass< TOptions, TResult extends IDatabaseDataResult, - TAction extends IDatabaseDataAction + TAction extends IDatabaseDataAction, > = ConstructorFunction & { dataFormat: ResultDataFormat[] | null; prototype: TAction; @@ -57,14 +48,10 @@ export interface IDatabaseDataAction void; updateResults: (results: TResult[]) => void; afterResultUpdate: () => void; - tryGetAction: >( - action: IDatabaseDataActionClass - ) => T | undefined; - getAction: >( - action: IDatabaseDataActionClass - ) => T; + tryGetAction: >(action: IDatabaseDataActionClass) => T | undefined; + getAction: >(action: IDatabaseDataActionClass) => T; getActionImplementation: >( - action: IDatabaseDataActionInterface + action: IDatabaseDataActionInterface, ) => T | undefined; dispose: () => void; } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataActions.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataActions.ts index 58a837bee6..47726e4b81 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataActions.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataActions.ts @@ -5,22 +5,18 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IDatabaseDataAction, IDatabaseDataActionClass, IDatabaseDataActionInterface } from './IDatabaseDataAction'; import type { IDatabaseDataResult } from './IDatabaseDataResult'; export interface IDatabaseDataActions { tryGet: >( result: TResult, - action: IDatabaseDataActionClass + action: IDatabaseDataActionClass, ) => T | undefined; - get: >( - result: TResult, - action: IDatabaseDataActionClass - ) => T; + get: >(result: TResult, action: IDatabaseDataActionClass) => T; getImplementation: >( result: TResult, - action: IDatabaseDataActionInterface + action: IDatabaseDataActionInterface, ) => T | undefined; updateResults: (results: TResult[]) => void; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataEditor.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataEditor.ts index 669c34fe0c..e153636431 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataEditor.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataEditor.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IExecutor } from '@cloudbeaver/core-executor'; import type { IDatabaseDataResult } from './IDatabaseDataResult'; @@ -13,7 +12,7 @@ import type { IDatabaseDataResult } from './IDatabaseDataResult'; export enum DataUpdateType { delete, update, - add + add, } export interface IResultEditingDiff { diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataModel.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataModel.ts index 481ab465f5..44be18e79c 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataModel.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataModel.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IExecutor } from '@cloudbeaver/core-executor'; import type { ResultDataFormat } from '@cloudbeaver/core-sdk'; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataOptions.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataOptions.ts index b630d8d72d..2b6c946d3a 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataOptions.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataOptions.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IConnectionInfoParams } from '@cloudbeaver/core-connections'; import type { SqlDataFilterConstraint } from '@cloudbeaver/core-sdk'; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataResult.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataResult.ts index 3d268743c4..f0fd9e253a 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataResult.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataResult.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { ResultDataFormat } from '@cloudbeaver/core-sdk'; export interface IDatabaseDataResult { diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataSource.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataSource.ts index 26633874cb..00d33aa2a8 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataSource.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataSource.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IConnectionExecutionContext } from '@cloudbeaver/core-connections'; import type { IServiceInjector } from '@cloudbeaver/core-di'; import type { ResultDataFormat } from '@cloudbeaver/core-sdk'; @@ -24,7 +23,7 @@ export interface IRequestInfo { export enum DatabaseDataAccessMode { Default, - Readonly + Readonly, } export interface IDatabaseDataSource { @@ -55,25 +54,19 @@ export interface IDatabaseDataSource>( resultIndex: number, - action: IDatabaseDataActionClass - ) => T | undefined) & (>( - result: TResult, - action: IDatabaseDataActionClass - ) => T | undefined); - getAction: (>( - resultIndex: number, - action: IDatabaseDataActionClass - ) => T) & (>( - result: TResult, - action: IDatabaseDataActionClass - ) => T); + action: IDatabaseDataActionClass, + ) => T | undefined) & + (>(result: TResult, action: IDatabaseDataActionClass) => T | undefined); + getAction: (>(resultIndex: number, action: IDatabaseDataActionClass) => T) & + (>(result: TResult, action: IDatabaseDataActionClass) => T); getActionImplementation: (>( resultIndex: number, - action: IDatabaseDataActionInterface - ) => T | undefined) & (>( - result: TResult, - action: IDatabaseDataActionInterface - ) => T | undefined); + action: IDatabaseDataActionInterface, + ) => T | undefined) & + (>( + result: TResult, + action: IDatabaseDataActionInterface, + ) => T | undefined); getResult: (index: number) => TResult | null; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseResultSet.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseResultSet.ts index 10e7c97ed4..355895e5d0 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseResultSet.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseResultSet.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { SqlResultSet } from '@cloudbeaver/core-sdk'; import type { IDatabaseDataResult } from './IDatabaseDataResult'; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Order.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Order.ts index 28f8f3f942..8c6c86fd0f 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Order.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Order.ts @@ -8,7 +8,7 @@ export enum EOrder { 'asc' = 'asc', - 'desc' = 'desc' + 'desc' = 'desc', } export type Order = EOrder | null; diff --git a/webapp/packages/plugin-data-viewer/src/LocaleService.ts b/webapp/packages/plugin-data-viewer/src/LocaleService.ts index 144237a086..e3649a06b4 100644 --- a/webapp/packages/plugin-data-viewer/src/LocaleService.ts +++ b/webapp/packages/plugin-data-viewer/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/IDataTableActions.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/IDataTableActions.ts index 0fa015575f..eee9050a1c 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/IDataTableActions.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/IDataTableActions.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { ResultDataFormat } from '@cloudbeaver/core-sdk'; import type { IDatabaseDataModel } from '../DatabaseDataModel/IDatabaseDataModel'; diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableError.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableError.tsx index 130e723417..3dcbf6bb7c 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableError.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableError.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable } from 'mobx'; import { observer } from 'mobx-react-lite'; import styled, { css, use } from 'reshadow'; @@ -17,65 +16,66 @@ import { errorOf } from '@cloudbeaver/core-utils'; import type { IDatabaseDataModel } from '../DatabaseDataModel/IDatabaseDataModel'; const style = css` - error { - composes: theme-background-surface theme-text-on-surface from global; - position: absolute; - box-sizing: border-box; - width: 100%; - height: 100%; - padding: 16px; - overflow: auto; + error { + composes: theme-background-surface theme-text-on-surface from global; + position: absolute; + box-sizing: border-box; + width: 100%; + height: 100%; + padding: 16px; + overflow: auto; + pointer-events: none; + bottom: 0; + right: 0; + z-index: 1; + opacity: 0; + transition: opacity 0.3s ease-in-out, width 0.3s ease-in-out, height 0.3s ease-in-out, background 0.3s ease-in-out; + + &[|animated] { + overflow: hidden; + pointer-events: auto; + opacity: 1; + } + &[|collapsed] { + pointer-events: auto; + width: 92px; + height: 72px; + background: transparent !important; + + & IconOrImage { + cursor: pointer; + } + + & error-message, + & controls { + display: none; + } + } + &[|errorHidden] { pointer-events: none; - bottom: 0; - right: 0; - z-index: 1; - opacity: 0; - transition: opacity 0.3s ease-in-out, width 0.3s ease-in-out, height 0.3s ease-in-out, background 0.3s ease-in-out; - - &[|animated] { - overflow: hidden; - pointer-events: auto; - opacity: 1; - } - &[|collapsed] { - pointer-events: auto; - width: 92px; - height: 72px; - background: transparent!important; - - & IconOrImage { - cursor: pointer; - } - - & error-message, & controls { - display: none; - } - } - &[|errorHidden] { - pointer-events: none; - } } - error-body { - display: flex; - gap: 24px; - align-items: center; - margin-bottom: 24px; + } + error-body { + display: flex; + gap: 24px; + align-items: center; + margin-bottom: 24px; + } + error-message { + white-space: pre-wrap; + } + IconOrImage { + width: 40px; + height: 40px; + } + controls { + display: flex; + gap: 16px; + & > Button { + flex-shrink: 0; } - error-message { - white-space: pre-wrap; - } - IconOrImage { - width: 40px; - height: 40px; - } - controls { - display: flex; - gap: 16px; - & > Button { - flex-shrink: 0; - } - } - `; + } +`; interface Props { model: IDatabaseDataModel; @@ -90,24 +90,24 @@ interface ErrorInfo { show: () => void; } -export const TableError = observer(function TableError({ - model, - loading, - className, -}) { +export const TableError = observer(function TableError({ model, loading, className }) { const translate = useTranslate(); - const errorInfo = useObservableRef(() => ({ - error: null, - display: false, - hide() { - this.display = false; + const errorInfo = useObservableRef( + () => ({ + error: null, + display: false, + hide() { + this.display = false; + }, + show() { + this.display = true; + }, + }), + { + display: observable.ref, }, - show() { - this.display = true; - }, - }), { - display: observable.ref, - }, false); + false, + ); if (errorInfo.error !== model.source.error) { errorInfo.error = model.source.error || null; @@ -141,26 +141,22 @@ export const TableError = observer(function TableError({ return styled(style)( - errorInfo.show()} - /> + errorInfo.show()} /> {error.message} - {error.hasDetails && ( - )} - - +
, ); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/AutoRefreshButton.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/AutoRefreshButton.tsx index 47e42f7900..a2ab8b16a6 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/AutoRefreshButton.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/AutoRefreshButton.tsx @@ -5,9 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; -import styled, { css } from 'reshadow'; +import styled, { css } from 'reshadow'; import { Icon, Menu, MenuItem, MenuItemElement, TimerIcon, useTranslate } from '@cloudbeaver/core-blocks'; import { declensionOfNumber } from '@cloudbeaver/core-utils'; @@ -16,50 +15,50 @@ import type { IDatabaseDataModel } from '../../../DatabaseDataModel/IDatabaseDat import { useAutoRefresh } from './useAutoRefresh'; const styles = css` -auto-reload { - composes: theme-text-primary theme-ripple from global; - height: 100%; - display: flex; - cursor: pointer; - align-items: center; - - & icon-box { - position: relative; - padding-left: 8px; - display: flex; - align-items: center; - - & Icon { - width: 16px; - height: 16px; - flex-grow: 0; - flex-shrink: 0; - } - - &:hover > Icon :global(use) { - fill: var(--theme-primary) !important; - } - } - - & arrow-box { - position: relative; + auto-reload { + composes: theme-text-primary theme-ripple from global; height: 100%; display: flex; + cursor: pointer; align-items: center; - padding-right: 8px; - & > Icon { - width: 14px; - height: 14px; - flex-grow: 0; - flex-shrink: 0; + & icon-box { + position: relative; + padding-left: 8px; + display: flex; + align-items: center; + + & Icon { + width: 16px; + height: 16px; + flex-grow: 0; + flex-shrink: 0; + } + + &:hover > Icon :global(use) { + fill: var(--theme-primary) !important; + } } - &:hover > Icon :global(use) { - fill: var(--theme-primary) !important; + & arrow-box { + position: relative; + height: 100%; + display: flex; + align-items: center; + padding-right: 8px; + + & > Icon { + width: 14px; + height: 14px; + flex-grow: 0; + flex-shrink: 0; + } + + &:hover > Icon :global(use) { + fill: var(--theme-primary) !important; + } } } -} `; interface Props { @@ -69,20 +68,13 @@ interface Props { const intervals = [5, 10, 15, 30, 60]; -export const AutoRefreshButton = observer(function AutoRefreshButton({ - model, - disabled, -}) { +export const AutoRefreshButton = observer(function AutoRefreshButton({ model, disabled }) { const translate = useTranslate(); const autoRefresh = useAutoRefresh(model); const interval = autoRefresh.settings.interval; const intervals_messages: string[] = []; - const buttonTitle = translate( - interval === null - ? 'data_viewer_action_refresh' - : 'data_viewer_action_auto_refresh_stop' - ); + const buttonTitle = translate(interval === null ? 'data_viewer_action_refresh' : 'data_viewer_action_auto_refresh_stop'); function handleClick() { if (disabled) { @@ -104,51 +96,31 @@ export const AutoRefreshButton = observer(function AutoRefreshButton({ interval = Math.round(interval / 60); } - intervals_messages.push( - translate(declensionOfNumber(interval, message), undefined, { interval }) - ); + intervals_messages.push(translate(declensionOfNumber(interval, message), undefined, { interval })); } return styled(styles)( - {interval === null ? ( - - ) : ( - - )} + {interval === null ? : } {intervals.map((inte, i) => ( - autoRefresh.setInterval(inte)} - > + autoRefresh.setInterval(inte)}> ))} - + - )} + } disabled={disabled} modal disclosure @@ -157,6 +129,6 @@ export const AutoRefreshButton = observer(function AutoRefreshButton({ - + , ); -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/AutoRefreshSettingsDialog.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/AutoRefreshSettingsDialog.tsx index acb88f9784..a29ebbd4ae 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/AutoRefreshSettingsDialog.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/AutoRefreshSettingsDialog.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useRef } from 'react'; import styled, { css } from 'reshadow'; @@ -13,32 +12,31 @@ import styled, { css } from 'reshadow'; import { BASE_CONTAINERS_STYLES, Button, Container, FieldCheckbox, Group, InputField, SubmittingForm, useTranslate } from '@cloudbeaver/core-blocks'; import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponentProps } from '@cloudbeaver/core-dialogs'; - import type { IAutoRefreshSettings } from './IAutoRefreshSettings'; const styles = css` - footer-container { - display: flex; - width: min-content; - flex: 1; - align-items: center; - justify-content: flex-end; - gap: 24px; - } - buttons { - flex: 1; - display: flex; - gap: 24px; - } - wrapper { - display: flex; - height: 100%; - width: 100%; - overflow: auto; - } - fill { - flex: 1; - } + footer-container { + display: flex; + width: min-content; + flex: 1; + align-items: center; + justify-content: flex-end; + gap: 24px; + } + buttons { + flex: 1; + display: flex; + gap: 24px; + } + wrapper { + display: flex; + height: 100%; + width: 100%; + overflow: auto; + } + fill { + flex: 1; + } `; interface Payload { @@ -63,33 +61,22 @@ export const AutoRefreshSettingsDialog = observer> } } - return styled(styles, BASE_CONTAINERS_STYLES)( - - + return styled( + styles, + BASE_CONTAINERS_STYLES, + )( + + resolve()}> - + {translate('ui_interval')} - + {translate('data_viewer_auto_refresh_settings_stop_on_error')} @@ -98,15 +85,18 @@ export const AutoRefreshSettingsDialog = observer> - - + - + - + , ); -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/IAutoRefreshSettings.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/IAutoRefreshSettings.ts index 7da151318d..2c7e17793d 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/IAutoRefreshSettings.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/IAutoRefreshSettings.ts @@ -9,4 +9,4 @@ export interface IAutoRefreshSettings { interval: number | null; stopOnError: boolean; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/useAutoRefresh.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/useAutoRefresh.ts index 0dbc05a2ed..b382e4ce1e 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/useAutoRefresh.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/AutoRefresh/useAutoRefresh.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable } from 'mobx'; import { useInterval, useObjectRef, useObservableRef } from '@cloudbeaver/core-blocks'; @@ -25,49 +24,60 @@ interface IAutoRefresh { export function useAutoRefresh(model: IDatabaseDataModel) { const commonDialogService = useService(CommonDialogService); - const settings = useObservableRef(() => ({ - interval: null, - stopOnError: true, - }), { - interval: observable, - stopOnError: observable, - }, false); + const settings = useObservableRef( + () => ({ + interval: null, + stopOnError: true, + }), + { + interval: observable, + stopOnError: observable, + }, + false, + ); - useInterval(async () => { - try { - await model.refresh(); - } catch { } + useInterval( + async () => { + try { + await model.refresh(); + } catch {} - if (model.source.error && settings.stopOnError) { - settings.interval = null; - } - }, settings.interval !== null ? settings.interval * 1000 : null); - - return useObjectRef(() => ({ - async configure() { - const settings: IAutoRefreshSettings = observable({ ...this.settings }); - - const result = await commonDialogService.open(AutoRefreshSettingsDialog, { settings }); - - if (result === DialogueStateResult.Resolved) { - let interval = settings.interval; - - if (typeof interval === 'string') { - interval = Number.parseInt(interval); - } - - if (!Number.isInteger(interval)) { - interval = null; - } - - Object.assign(this.settings, { ...settings, interval }); + if (model.source.error && settings.stopOnError) { + settings.interval = null; } }, - setInterval(interval: number) { - this.settings.interval = interval; - }, - stop() { - this.settings.interval = null; - }, - }), { settings }, ['configure', 'setInterval', 'stop']); -} \ No newline at end of file + settings.interval !== null ? settings.interval * 1000 : null, + ); + + return useObjectRef( + () => ({ + async configure() { + const settings: IAutoRefreshSettings = observable({ ...this.settings }); + + const result = await commonDialogService.open(AutoRefreshSettingsDialog, { settings }); + + if (result === DialogueStateResult.Resolved) { + let interval = settings.interval; + + if (typeof interval === 'string') { + interval = Number.parseInt(interval); + } + + if (!Number.isInteger(interval)) { + interval = null; + } + + Object.assign(this.settings, { ...settings, interval }); + } + }, + setInterval(interval: number) { + this.settings.interval = interval; + }, + stop() { + this.settings.interval = null; + }, + }), + { settings }, + ['configure', 'setInterval', 'stop'], + ); +} diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooter.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooter.tsx index c09cb51383..f92ad0c936 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooter.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooter.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback, useEffect, useRef, useState } from 'react'; import styled, { css, use } from 'reshadow'; @@ -20,52 +19,52 @@ import { AutoRefreshButton } from './AutoRefresh/AutoRefreshButton'; import { TableFooterMenu } from './TableFooterMenu/TableFooterMenu'; const tableFooterStyles = css` - ToolsPanel { - align-items: center; - flex: 0 0 auto; - overflow: auto; - gap: 8px; - min-height: 32px; - height: initial; - } - count input, - count placeholder { - height: 26px; - width: 80px; - box-sizing: border-box; - padding: 4px 7px; - font-size: 13px; - line-height: 24px; - } - reload { - composes: theme-text-primary theme-ripple from global; - height: 100%; - display: flex; - cursor: pointer; - align-items: center; - padding: 0 16px; + ToolsPanel { + align-items: center; + flex: 0 0 auto; + overflow: auto; + gap: 8px; + min-height: 32px; + height: initial; + } + count input, + count placeholder { + height: 26px; + width: 80px; + box-sizing: border-box; + padding: 4px 7px; + font-size: 13px; + line-height: 24px; + } + reload { + composes: theme-text-primary theme-ripple from global; + height: 100%; + display: flex; + cursor: pointer; + align-items: center; + padding: 0 16px; - & IconOrImage { - & :global(use) { - fill: var(--theme-primary) !important; - } - width: 24px; - height: 24px; + & IconOrImage { + & :global(use) { + fill: var(--theme-primary) !important; } - } - IconButton { - position: relative; - height: 24px; width: 24px; - display: block; + height: 24px; } - time { - composes: theme-typography--caption from global; - white-space: nowrap; - margin-left: auto; - margin-right: 16px; - } - `; + } + IconButton { + position: relative; + height: 24px; + width: 24px; + display: block; + } + time { + composes: theme-typography--caption from global; + white-space: nowrap; + margin-left: auto; + margin-right: 16px; + } +`; interface Props { resultIndex: number; @@ -74,33 +73,23 @@ interface Props { context?: IDataContext; } -export const TableFooter = observer(function TableFooter({ - resultIndex, - model, - simple, - context, -}) { +export const TableFooter = observer(function TableFooter({ resultIndex, model, simple, context }) { const ref = useRef(null); const [limit, setLimit] = useState(model.countGain + ''); const dataViewerSettingsService = useService(DataViewerSettingsService); - const handleChange = useCallback( - async () => { - if (!ref.current) { - return; - } + const handleChange = useCallback(async () => { + if (!ref.current) { + return; + } - const value = dataViewerSettingsService.getDefaultRowsCount(parseInt(ref.current.value, 10)); + const value = dataViewerSettingsService.getDefaultRowsCount(parseInt(ref.current.value, 10)); - setLimit(value + ''); - if (model.countGain !== value) { - await model - .setCountGain(value) - .reload(); - } - }, - [model] - ); + setLimit(value + ''); + if (model.countGain !== value) { + await model.setCountGain(value).reload(); + } + }, [model]); useEffect(() => { if (limit !== model.countGain + '') { @@ -115,10 +104,7 @@ export const TableFooter = observer(function TableFooter({ {/* model.refresh()}> */} - + (function TableFooter({ {model.source.requestInfo.requestMessage} - {model.source.requestInfo.requestDuration}ms )} - + , ); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/DATA_VIEWER_DATA_MODEL_ACTIONS_MENU.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/DATA_VIEWER_DATA_MODEL_ACTIONS_MENU.ts index 3dcfd3df6c..7847d63c15 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/DATA_VIEWER_DATA_MODEL_ACTIONS_MENU.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/DATA_VIEWER_DATA_MODEL_ACTIONS_MENU.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; export const DATA_VIEWER_DATA_MODEL_ACTIONS_MENU = createMenu('data-viewer-data-model-actions', 'Data viewer data model actions menu'); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/TableFooterMenu.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/TableFooterMenu.tsx index 54cb3205f1..4bd9c6d424 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/TableFooterMenu.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/TableFooterMenu.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -47,13 +46,7 @@ interface Props { className?: string; } -export const TableFooterMenu = observer(function TableFooterMenu({ - resultIndex, - model, - simple, - context, - className, -}) { +export const TableFooterMenu = observer(function TableFooterMenu({ resultIndex, model, simple, context, className }) { const mainMenuService = useService(TableFooterMenuService); const menu = useMenu({ menu: DATA_VIEWER_DATA_MODEL_ACTIONS_MENU, context }); @@ -67,6 +60,6 @@ export const TableFooterMenu = observer(function TableFooterMenu({ ))} - + , ); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/TableFooterMenuItem.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/TableFooterMenuItem.tsx index 7144b5c1e9..d1997593aa 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/TableFooterMenuItem.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/TableFooterMenuItem.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import type { ButtonHTMLAttributes } from 'react'; import styled, { css, use } from 'reshadow'; @@ -18,39 +17,36 @@ type Props = ButtonHTMLAttributes & { }; export const tableFooterMenuStyles = css` - Menu { - composes: theme-text-on-surface from global; - } - MenuTrigger { - composes: theme-ripple from global; - height: 100%; - padding: 0 12px; - display: flex; - align-items: center; - cursor: pointer; - &[|hidden] { - display: none; - } - } - ToolsAction[|hidden] { + Menu { + composes: theme-text-on-surface from global; + } + MenuTrigger { + composes: theme-ripple from global; + height: 100%; + padding: 0 12px; + display: flex; + align-items: center; + cursor: pointer; + &[|hidden] { display: none; } - menu-trigger-icon IconOrImage { - display: block; - width: 16px; - } - menu-trigger-title { - display: block; - } - menu-trigger-icon + menu-trigger-title { - padding-left: 8px; - } - `; + } + ToolsAction[|hidden] { + display: none; + } + menu-trigger-icon IconOrImage { + display: block; + width: 16px; + } + menu-trigger-title { + display: block; + } + menu-trigger-icon + menu-trigger-title { + padding-left: 8px; + } +`; -export const TableFooterMenuItem = observer(function TableFooterMenuItem({ - menuItem, - ...props -}) { +export const TableFooterMenuItem = observer(function TableFooterMenuItem({ menuItem, ...props }) { const translate = useTranslate(); if (!menuItem.panel) { @@ -65,7 +61,7 @@ export const TableFooterMenuItem = observer(function TableFooterMenuItem( onClick={() => menuItem.onClick?.()} > {translate(menuItem.title)} - + , ); } @@ -85,6 +81,6 @@ export const TableFooterMenuItem = observer(function TableFooterMenuItem( )} {menuItem.title && {translate(menuItem.title)}} - + , ); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/TableFooterMenuService.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/TableFooterMenuService.ts index 05be962005..1383711e0c 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/TableFooterMenuService.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableFooter/TableFooterMenu/TableFooterMenuService.ts @@ -5,9 +5,8 @@ * 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 { ContextMenuService, IMenuContext, IContextMenuItem, IMenuItem } from '@cloudbeaver/core-dialogs'; +import { ContextMenuService, IContextMenuItem, IMenuContext, IMenuItem } from '@cloudbeaver/core-dialogs'; import { DatabaseEditAction } from '../../../DatabaseDataModel/Actions/DatabaseEditAction'; import { DatabaseSelectAction } from '../../../DatabaseDataModel/Actions/DatabaseSelectAction'; @@ -25,9 +24,7 @@ export class TableFooterMenuService { static nodeContextType = 'NodeWithParent'; private readonly tableFooterMenuToken = 'tableFooterMenu'; - constructor( - private readonly contextMenuService: ContextMenuService, - ) { + constructor(private readonly contextMenuService: ContextMenuService) { this.contextMenuService.addPanel(this.tableFooterMenuToken); this.registerMenuItem({ @@ -43,34 +40,25 @@ export class TableFooterMenuService { return true; } - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); return !editor?.hasFeature('add'); }, isDisabled(context) { return ( - context.data.model.isLoading() - || context.data.model.isDisabled(context.data.resultIndex) - || !context.data.model.source.hasResult(context.data.resultIndex) + context.data.model.isLoading() || + context.data.model.isDisabled(context.data.resultIndex) || + !context.data.model.source.hasResult(context.data.resultIndex) ); }, onClick(context) { - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); if (!editor) { return; } - const select = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseSelectAction - ); + const select = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseSelectAction); editor.add(select?.getFocusedElement()); }, @@ -88,18 +76,15 @@ export class TableFooterMenuService { return true; } - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); return !editor?.hasFeature('add'); }, isDisabled(context) { if ( - context.data.model.isLoading() - || context.data.model.isDisabled(context.data.resultIndex) - || !context.data.model.source.hasResult(context.data.resultIndex) + context.data.model.isLoading() || + context.data.model.isDisabled(context.data.resultIndex) || + !context.data.model.source.hasResult(context.data.resultIndex) ) { return true; } @@ -109,10 +94,7 @@ export class TableFooterMenuService { return selectedElements.length === 0; }, onClick(context) { - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); if (!editor) { return; @@ -136,26 +118,20 @@ export class TableFooterMenuService { return true; } - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); return !editor?.hasFeature('delete'); }, isDisabled(context) { if ( - context.data.model.isLoading() - || context.data.model.isDisabled(context.data.resultIndex) - || !context.data.model.source.hasResult(context.data.resultIndex) + context.data.model.isLoading() || + context.data.model.isDisabled(context.data.resultIndex) || + !context.data.model.source.hasResult(context.data.resultIndex) ) { return true; } - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); if (!editor) { return true; @@ -170,10 +146,7 @@ export class TableFooterMenuService { return !selectedElements.some(key => editor.getElementState(key) !== DatabaseEditChangeType.delete); }, onClick(context) { - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); const selectedElements = getActiveElements(context.data.model, context.data.resultIndex); @@ -193,33 +166,27 @@ export class TableFooterMenuService { return true; } - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); return !editor; }, isDisabled(context) { if ( - context.data.model.isLoading() - || context.data.model.isDisabled(context.data.resultIndex) - || !context.data.model.source.hasResult(context.data.resultIndex) + context.data.model.isLoading() || + context.data.model.isDisabled(context.data.resultIndex) || + !context.data.model.source.hasResult(context.data.resultIndex) ) { return true; } - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); const selectedElements = getActiveElements(context.data.model, context.data.resultIndex); return ( - !editor - || selectedElements.length === 0 - || !selectedElements.some(key => { + !editor || + selectedElements.length === 0 || + !selectedElements.some(key => { const state = editor.getElementState(key); if (state === DatabaseEditChangeType.add) { @@ -231,10 +198,7 @@ export class TableFooterMenuService { ); }, onClick(context) { - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); const selectedElements = getActiveElements(context.data.model, context.data.resultIndex); @@ -254,17 +218,14 @@ export class TableFooterMenuService { }, isDisabled(context) { if ( - context.data.model.isLoading() - || context.data.model.isDisabled(context.data.resultIndex) - || !context.data.model.source.hasResult(context.data.resultIndex) + context.data.model.isLoading() || + context.data.model.isDisabled(context.data.resultIndex) || + !context.data.model.source.hasResult(context.data.resultIndex) ) { return true; } - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); return !editor?.isEdited(); }, @@ -285,25 +246,19 @@ export class TableFooterMenuService { }, isDisabled(context) { if ( - context.data.model.isLoading() - || context.data.model.isDisabled(context.data.resultIndex) - || !context.data.model.source.hasResult(context.data.resultIndex) + context.data.model.isLoading() || + context.data.model.isDisabled(context.data.resultIndex) || + !context.data.model.source.hasResult(context.data.resultIndex) ) { return true; } - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); return !editor?.isEdited(); }, onClick: context => { - const editor = context.data.model.source.getActionImplementation( - context.data.resultIndex, - DatabaseEditAction - ); + const editor = context.data.model.source.getActionImplementation(context.data.resultIndex, DatabaseEditAction); editor?.clear(); }, }); @@ -325,10 +280,7 @@ export class TableFooterMenuService { } function getActiveElements(model: IDatabaseDataModel, resultIndex: number): unknown[] { - const select = model.source.getActionImplementation( - resultIndex, - DatabaseSelectAction - ); + const select = model.source.getActionImplementation(resultIndex, DatabaseSelectAction); return select?.getActiveElements() ?? []; } diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableGrid.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableGrid.tsx index 079aad24f3..a0a8684f62 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableGrid.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableGrid.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -33,18 +32,8 @@ const styles = css` } `; -export const TableGrid = observer(function TableGrid({ - model, - actions, - dataFormat, - presentation, - resultIndex, - simple, -}) { - if ( - (presentation.dataFormat !== undefined && dataFormat !== presentation.dataFormat) - || !model.source.hasResult(resultIndex) - ) { +export const TableGrid = observer(function TableGrid({ model, actions, dataFormat, presentation, resultIndex, simple }) { + if ((presentation.dataFormat !== undefined && dataFormat !== presentation.dataFormat) || !model.source.hasResult(resultIndex)) { if (model.isLoading()) { return null; } @@ -61,7 +50,5 @@ export const TableGrid = observer(function TableGrid({ return ; } - return styled(styles)( - - ); + return styled(styles)(); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/DATA_CONTEXT_DATA_VIEWER_SIMPLE.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/DATA_CONTEXT_DATA_VIEWER_SIMPLE.ts index a08677bb8d..86de5ecb3e 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/DATA_CONTEXT_DATA_VIEWER_SIMPLE.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/DATA_CONTEXT_DATA_VIEWER_SIMPLE.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createDataContext } from '@cloudbeaver/core-view'; export const DATA_CONTEXT_DATA_VIEWER_SIMPLE = createDataContext('data-viewer-database-simple'); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/DATA_VIEWER_DATA_MODEL_TOOLS_MENU.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/DATA_VIEWER_DATA_MODEL_TOOLS_MENU.ts index 541a5791bc..07a1fb85f5 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/DATA_VIEWER_DATA_MODEL_TOOLS_MENU.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/DATA_VIEWER_DATA_MODEL_TOOLS_MENU.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; export const DATA_VIEWER_DATA_MODEL_TOOLS_MENU = createMenu('data-viewer-data-model-tools', 'Data viewer data model tools menu'); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableHeader.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableHeader.tsx index 0ba60c4a7e..44c8d8c43c 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableHeader.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableHeader.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -34,17 +33,12 @@ interface Props { className?: string; } -export const TableHeader = observer(function TableHeader({ - model, - resultIndex, - simple, - className, -}) { +export const TableHeader = observer(function TableHeader({ model, resultIndex, simple, className }) { const service = useService(TableHeaderService); return styled(styles)( - + , ); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableHeaderMenu.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableHeaderMenu.tsx index 6e148e8eb2..ad452c9c20 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableHeaderMenu.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableHeaderMenu.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { css } from 'reshadow'; @@ -20,74 +19,70 @@ import { DATA_VIEWER_DATA_MODEL_TOOLS_MENU } from './DATA_VIEWER_DATA_MODEL_TOOL import type { ITableHeaderPlaceholderProps } from './TableHeaderService'; const TABLE_HEADER_MENU_BAR_STYLES = css` - menu-bar { - composes: theme-border-color-background theme-background-surface theme-text-on-surface theme-typography--body2 from global; - display: flex; - margin-left: 8px; - box-sizing: border-box; - border: 1px solid; - height: 24px; + menu-bar { + composes: theme-border-color-background theme-background-surface theme-text-on-surface theme-typography--body2 from global; + display: flex; + margin-left: 8px; + box-sizing: border-box; + border: 1px solid; + height: 24px; + } + + menu-bar-item { + composes: theme-ripple from global; + padding: 4px; + display: flex; + align-items: center; + cursor: pointer; + background: transparent; + outline: none; + color: inherit; + + &[use|hidden] { + display: none; } - menu-bar-item { - composes: theme-ripple from global; - padding: 4px; - display: flex; - align-items: center; - cursor: pointer; - background: transparent; - outline: none; - color: inherit; - - &[use|hidden] { - display: none; - } - - & IconOrImage { - display: block; - width: 16px; - } - - & Loader { - width: 16px; - } - - & menu-bar-item-label { - display: block; - text-transform: uppercase; - font-weight: 700; - } - - & IconOrImage + menu-bar-item-label, & Loader + menu-bar-item-label { - padding-left: 8px - } + & IconOrImage { + display: block; + width: 16px; } - - MenuSeparator { - composes: theme-border-color-background from global; - height: 100%; - margin: 0; - border: 0 !important; - border-right: 1px solid !important; - &:first-child, &:last-child { - display: none; - } + & Loader { + width: 16px; } - `; -export const TableHeaderMenu: PlaceholderComponent = observer(function TableHeaderMenu({ - model, - simple, - resultIndex, -}) { + & menu-bar-item-label { + display: block; + text-transform: uppercase; + font-weight: 700; + } + + & IconOrImage + menu-bar-item-label, + & Loader + menu-bar-item-label { + padding-left: 8px; + } + } + + MenuSeparator { + composes: theme-border-color-background from global; + height: 100%; + margin: 0; + border: 0 !important; + border-right: 1px solid !important; + + &:first-child, + &:last-child { + display: none; + } + } +`; + +export const TableHeaderMenu: PlaceholderComponent = observer(function TableHeaderMenu({ model, simple, resultIndex }) { const menu = useMenu({ menu: DATA_VIEWER_DATA_MODEL_TOOLS_MENU }); menu.context.set(DATA_CONTEXT_DV_DDM, model); menu.context.set(DATA_CONTEXT_DV_DDM_RESULT_INDEX, resultIndex); menu.context.set(DATA_CONTEXT_DATA_VIEWER_SIMPLE, simple); - return ( - - ); + return ; }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableHeaderService.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableHeaderService.ts index 26e129b420..db37b5c963 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableHeaderService.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableHeaderService.ts @@ -5,12 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; import { PlaceholderContainer } from '@cloudbeaver/core-blocks'; -import { injectable, Bootstrap } from '@cloudbeaver/core-di'; -import { MenuService, ActionService, DATA_CONTEXT_MENU } from '@cloudbeaver/core-view'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; +import { ActionService, DATA_CONTEXT_MENU, MenuService } from '@cloudbeaver/core-view'; import { DATA_VIEWER_CONSTRAINTS_DELETE_ACTION } from '../../DatabaseDataModel/Actions/ResultSet/Actions/DATA_VIEWER_CONSTRAINTS_DELETE_ACTION'; import { ResultSetConstraintAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetConstraintAction'; @@ -38,10 +37,7 @@ export interface ITableHeaderPlaceholderProps { export class TableHeaderService extends Bootstrap { readonly tableHeaderPlaceholder = new PlaceholderContainer(); - constructor( - private readonly menuService: MenuService, - private readonly actionService: ActionService - ) { + constructor(private readonly menuService: MenuService, private readonly actionService: ActionService) { super(); } @@ -109,15 +105,10 @@ export class TableHeaderService extends Bootstrap { }); this.menuService.addCreator({ - isApplicable: context => ( - context.get(DATA_CONTEXT_MENU) === DATA_VIEWER_DATA_MODEL_TOOLS_MENU - ), - getItems: (context, items) => [ - ...items, - DATA_VIEWER_CONSTRAINTS_DELETE_ACTION, - ], + isApplicable: context => context.get(DATA_CONTEXT_MENU) === DATA_VIEWER_DATA_MODEL_TOOLS_MENU, + getItems: (context, items) => [...items, DATA_VIEWER_CONSTRAINTS_DELETE_ACTION], }); } - load(): void | Promise { } + load(): void | Promise {} } diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableWhereFilter.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableWhereFilter.tsx index 777cca3834..a9cb264328 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableWhereFilter.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableWhereFilter.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -16,17 +15,14 @@ import type { ITableHeaderPlaceholderProps } from './TableHeaderService'; import { useWhereFilter } from './useWhereFilter'; const styles = css` - InlineEditor { - composes: theme-background-surface theme-text-on-surface from global; - flex: 1; - height: 24px; - } - `; + InlineEditor { + composes: theme-background-surface theme-text-on-surface from global; + flex: 1; + height: 24px; + } +`; -export const TableWhereFilter: PlaceholderComponent = observer(function TableWhereFilter({ - model, - resultIndex, -}) { +export const TableWhereFilter: PlaceholderComponent = observer(function TableWhereFilter({ model, resultIndex }) { const translate = useTranslate(); const state = useWhereFilter(model, resultIndex); @@ -35,13 +31,13 @@ export const TableWhereFilter: PlaceholderComponent + />, ); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/useWhereFilter.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/useWhereFilter.ts index ec5d3d022e..4aea107f4b 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/useWhereFilter.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/useWhereFilter.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, computed } from 'mobx'; import { useObservableRef } from '@cloudbeaver/core-blocks'; @@ -25,56 +24,57 @@ interface IState { apply: () => Promise; } -export function useWhereFilter( - model: IDatabaseDataModel, - resultIndex: number -): Readonly { - return useObservableRef(() => ({ - get filter() { - if (this.constraints?.filterConstraints.length && this.model.source.requestInfo.requestFilter) { - return this.model.requestInfo.requestFilter; - } +export function useWhereFilter(model: IDatabaseDataModel, resultIndex: number): Readonly { + return useObservableRef( + () => ({ + get filter() { + if (this.constraints?.filterConstraints.length && this.model.source.requestInfo.requestFilter) { + return this.model.requestInfo.requestFilter; + } - return this.model.source.options?.whereFilter ?? ''; - }, - get constraints() { - if (!this.model.source.hasResult(this.resultIndex)) { - return null; - } + return this.model.source.options?.whereFilter ?? ''; + }, + get constraints() { + if (!this.model.source.hasResult(this.resultIndex)) { + return null; + } - return this.model.source.tryGetAction(this.resultIndex, ResultSetConstraintAction) ?? null; - }, - get disabled() { - const supported = this.constraints?.supported ?? false; - return !supported || this.model.isLoading() || this.model.isDisabled(resultIndex); - }, - get applicableFilter() { - return this.model.source.prevOptions?.whereFilter !== this.model.source.options?.whereFilter - || this.model.source.options?.whereFilter !== this.model.source.requestInfo.requestFilter; - }, - set(value: string) { - if (!this.constraints) { - return; - } + return this.model.source.tryGetAction(this.resultIndex, ResultSetConstraintAction) ?? null; + }, + get disabled() { + const supported = this.constraints?.supported ?? false; + return !supported || this.model.isLoading() || this.model.isDisabled(resultIndex); + }, + get applicableFilter() { + return ( + this.model.source.prevOptions?.whereFilter !== this.model.source.options?.whereFilter || + this.model.source.options?.whereFilter !== this.model.source.requestInfo.requestFilter + ); + }, + set(value: string) { + if (!this.constraints) { + return; + } - this.constraints.deleteFilters(); - this.constraints.setWhereFilter(value); - }, - async apply() { - if (!this.applicableFilter || this.model.isLoading() || this.model.isDisabled(this.resultIndex)) { - return; - } + this.constraints.deleteFilters(); + this.constraints.setWhereFilter(value); + }, + async apply() { + if (!this.applicableFilter || this.model.isLoading() || this.model.isDisabled(this.resultIndex)) { + return; + } - await this.model.request(); + await this.model.request(); + }, + }), + { + filter: computed, + constraints: computed, + disabled: computed, + applicableFilter: computed, + set: action.bound, + apply: action.bound, }, - }), - { - filter: computed, - constraints: computed, - disabled: computed, - applicableFilter: computed, - set: action.bound, - apply: action.bound, - }, - { model, resultIndex }); + { model, resultIndex }, + ); } diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TablePresentationBar/PresentationTab.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TablePresentationBar/PresentationTab.tsx index c9cc2d100b..ffb041bcdf 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TablePresentationBar/PresentationTab.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TablePresentationBar/PresentationTab.tsx @@ -5,14 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; - -import { useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { useStyles, useTranslate } from '@cloudbeaver/core-blocks'; import type { ComponentStyle } from '@cloudbeaver/core-theming'; -import { VERTICAL_ROTATED_TAB_STYLES, Tab, TabIcon, TabTitle, BASE_TAB_STYLES } from '@cloudbeaver/core-ui'; +import { BASE_TAB_STYLES, Tab, TabIcon, TabTitle, VERTICAL_ROTATED_TAB_STYLES } from '@cloudbeaver/core-ui'; import type { IDatabaseDataModel } from '../../DatabaseDataModel/IDatabaseDataModel'; import type { IDataPresentationOptions } from '../../DataPresentationService'; @@ -26,13 +24,7 @@ interface Props { onClick: (tabId: string) => void; } -export const PresentationTab = observer(function PresentationTab({ - model, - presentation, - className, - style, - onClick, -}) { +export const PresentationTab = observer(function PresentationTab({ model, presentation, className, style, onClick }) { const translate = useTranslate(); const styles = useStyles(BASE_TAB_STYLES, VERTICAL_ROTATED_TAB_STYLES, style); @@ -53,14 +45,9 @@ export const PresentationTab = observer(function PresentationTab({ } return styled(styles)( - + {presentation.icon && } {presentation.title && {translate(presentation.title)}} - + , ); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TablePresentationBar/TablePresentationBar.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TablePresentationBar/TablePresentationBar.tsx index cde8766928..49938ddf70 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TablePresentationBar/TablePresentationBar.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TablePresentationBar/TablePresentationBar.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css, use } from 'reshadow'; @@ -19,25 +18,25 @@ import { DataPresentationService, DataPresentationType } from '../../DataPresent import { PresentationTab } from './PresentationTab'; const styles = css` - table-left-bar { - display: flex; - } - Tab { - composes: theme-ripple theme-background-background theme-text-text-primary-on-light theme-typography--body2 from global; - text-transform: uppercase; - font-weight: normal; + table-left-bar { + display: flex; + } + Tab { + composes: theme-ripple theme-background-background theme-text-text-primary-on-light theme-typography--body2 from global; + text-transform: uppercase; + font-weight: normal; - &:global([aria-selected=true]) { - font-weight: normal !important; - } + &:global([aria-selected='true']) { + font-weight: normal !important; } - TabList { - composes: theme-background-secondary theme-text-on-secondary from global; - } - TabList[|flexible] tab-outer:only-child { - display: none; - } - `; + } + TabList { + composes: theme-background-secondary theme-text-on-secondary from global; + } + TabList[|flexible] tab-outer:only-child { + display: none; + } +`; interface Props { type: DataPresentationType; @@ -64,13 +63,7 @@ export const TablePresentationBar = observer(function TablePresentationBa }) { const style = useStyles(styles, BASE_TAB_STYLES, VERTICAL_ROTATED_TAB_STYLES, BASE_CONTAINERS_STYLES); const dataPresentationService = useService(DataPresentationService); - const presentations = dataPresentationService.getSupportedList( - type, - supportedDataFormat, - dataFormat, - model, - resultIndex - ); + const presentations = dataPresentationService.getSupportedList(type, supportedDataFormat, dataFormat, model, resultIndex); const Tab = PresentationTab; // alias for styles matching const handleClick = (tabId: string) => { if (tabId === presentationId) { @@ -89,19 +82,12 @@ export const TablePresentationBar = observer(function TablePresentationBa return styled(style)( - + {presentations.map(presentation => ( - + ))} - + , ); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableStatistics.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableStatistics.tsx index dd6b7c60b3..ad748ff3ac 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableStatistics.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableStatistics.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -29,21 +28,21 @@ const styles = css` } `; -export const TableStatistics = observer(function TableStatistics({ - model, - resultIndex, -}) { +export const TableStatistics = observer(function TableStatistics({ model, resultIndex }) { const translate = useTranslate(); const source = model.source; const result = model.getResult(resultIndex); return styled(styles)( - {translate('data_viewer_statistics_status')} {source.requestInfo.requestMessage}
- {translate('data_viewer_statistics_duration')} {source.requestInfo.requestDuration} ms
- {translate('data_viewer_statistics_updated_rows')} {result?.updateRowCount || 0}
+ {translate('data_viewer_statistics_status')} {source.requestInfo.requestMessage} +
+ {translate('data_viewer_statistics_duration')} {source.requestInfo.requestDuration} ms +
+ {translate('data_viewer_statistics_updated_rows')} {result?.updateRowCount || 0} +

{source.requestInfo.source}
-
+ , ); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableToolsPanel.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableToolsPanel.tsx index 95f24af3c6..f58af5d320 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableToolsPanel.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableToolsPanel.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -32,14 +31,7 @@ const styles = css` } `; -export const TableToolsPanel = observer(function TableToolsPanel({ - model, - actions, - dataFormat, - presentation, - resultIndex, - simple, -}) { +export const TableToolsPanel = observer(function TableToolsPanel({ model, actions, dataFormat, presentation, resultIndex, simple }) { const translate = useTranslate(); const result = model.getResult(resultIndex); @@ -59,7 +51,5 @@ export const TableToolsPanel = observer(function TableToolsPanel({ return {translate('data_viewer_nodata_message')}; } - return styled(styles)( - - ); + return styled(styles)(); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewer.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewer.tsx index 062b6e580a..6e4347d504 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewer.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewer.tsx @@ -5,13 +5,23 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable } from 'mobx'; import { observer } from 'mobx-react-lite'; -import { useEffect, forwardRef } from 'react'; +import { forwardRef, useEffect } from 'react'; import styled, { css, use } from 'reshadow'; -import { getComputed, Loader, Pane, ResizerControls, Split, splitStyles, TextPlaceholder, useObjectRef, useObservableRef, useSplitUserState } from '@cloudbeaver/core-blocks'; +import { + getComputed, + Loader, + Pane, + ResizerControls, + Split, + splitStyles, + TextPlaceholder, + useObjectRef, + useObservableRef, + useSplitUserState, +} from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { ResultDataFormat } from '@cloudbeaver/core-sdk'; import type { IDataContext } from '@cloudbeaver/core-view'; @@ -28,59 +38,61 @@ import { TableToolsPanel } from './TableToolsPanel'; import { TableViewerStorageService } from './TableViewerStorageService'; const viewerStyles = css` - pane-content { - composes: theme-background-surface theme-text-on-surface from global; + pane-content { + composes: theme-background-surface theme-text-on-surface from global; - &[|grid] { - border-radius: var(--theme-group-element-radius); - } + &[|grid] { + border-radius: var(--theme-group-element-radius); } - table-viewer { - composes: theme-background-secondary theme-text-on-secondary from global; + } + table-viewer { + composes: theme-background-secondary theme-text-on-secondary from global; + position: relative; + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; + } + table-content { + display: flex; + flex: 1; + overflow: hidden; + } + table-data { + gap: 8px; + } + table-data, + Pane, + pane-content { + position: relative; + display: flex; + flex: 1; + flex-direction: column; + overflow: hidden; + } + Split:not([disable]) { + gap: 8px; + } + Pane { + &:first-child { position: relative; - flex: 1; - display: flex; - flex-direction: column; - overflow: hidden; } - table-content { - display: flex; - flex: 1; - overflow: hidden; + } + TablePresentationBar { + margin-top: 32px; + &:first-child { + margin-right: 4px; } - table-data { - gap: 8px; + &:last-child { + margin-left: 4px; } - table-data, Pane, pane-content { - position: relative; - display: flex; - flex: 1; - flex-direction: column; - overflow: hidden; - } - Split:not([disable]) { - gap: 8px; - } - Pane { - &:first-child { - position: relative; - } - } - TablePresentationBar { - margin-top: 32px; - &:first-child { - margin-right: 4px; - } - &:last-child { - margin-left: 4px; - } - } - Loader { - position: absolute; - width: 100%; - height: 100%; - } - `; + } + Loader { + position: absolute; + width: 100%; + height: 100%; + } +`; interface Props { tableId: string; @@ -94,244 +106,227 @@ interface Props { onValuePresentationChange: (id: string | null) => void; } -export const TableViewer = observer(forwardRef(function TableViewer({ - tableId, - resultIndex = 0, - presentationId, - valuePresentationId, - simple = false, - context, - className, - onPresentationChange, - onValuePresentationChange, -}, ref) { - const dataPresentationService = useService(DataPresentationService); - const tableViewerStorageService = useService(TableViewerStorageService); - const dataModel = tableViewerStorageService.get(tableId); - const result = dataModel?.getResult(resultIndex); - const loading = dataModel?.isLoading() ?? true; - const dataFormat = result?.dataFormat || ResultDataFormat.Resultset; - const splitState = useSplitUserState('table-viewer'); - - const localActions = useObjectRef({ - clearConstraints() { - const constraints = dataModel?.source.tryGetAction(resultIndex, ResultSetConstraintAction); - - if (constraints) { - constraints.deleteAll(); - } - }, - }); - - const dataTableActions = useObservableRef(() => ({ - setPresentation(id: string) { - const presentation = dataPresentationService.get(id); - - if (presentation) { - if ( - presentation.dataFormat !== undefined - && presentation.dataFormat !== this.dataModel?.source.dataFormat - ) { - localActions.clearConstraints(); - this.dataModel?.setDataFormat(presentation.dataFormat).reload(); - } - - this.onPresentationChange(id); - } - }, - - setValuePresentation(id: string | null) { - if (id === this.valuePresentationId) { - return; - } - - if (id === null) { - this.onValuePresentationChange(null); - return; - } - - let presentation = dataPresentationService.get(id); - - if (!presentation && this.dataModel) { - presentation = dataPresentationService.getSupported( - DataPresentationType.toolsPanel, - this.dataFormat, - undefined, - this.dataModel, - this.resultIndex - ) ?? undefined; - } - - if (presentation) { - this.onValuePresentationChange(presentation.id); - } - }, - switchValuePresentation(id: string | null) { - if (id === this.valuePresentationId) { - this.onValuePresentationChange(null); - return; - } - - this.setValuePresentation(id); - }, - closeValuePresentation() { - this.onValuePresentationChange(null); - }, - }), { - presentationId: observable, - valuePresentationId: observable, - dataFormat: observable, - resultIndex: observable, - dataModel: observable.ref, - }, { - presentationId, - valuePresentationId, - dataModel, - resultIndex, - dataFormat, - onPresentationChange, - onValuePresentationChange, - }, ['setPresentation', 'setValuePresentation', 'switchValuePresentation', 'closeValuePresentation']); - - const needRefresh = getComputed(() => ( - dataModel?.source.error === null - && dataModel.source.results.length === 0 - && dataModel.source.outdated - && dataModel.source.isLoadable() - )); - - useEffect(() => { - if (needRefresh) { - dataModel?.request(); - } - }, [needRefresh]); - - // TODO: seems this code is not working because of setting dataFormat in presentation change - // useEffect(() => { - // if (!presentationId || !dataModel) { - // return; - // } - - // const presentation = dataPresentationService.get(presentationId); - - // if (presentation?.dataFormat && !dataModel.supportedDataFormats.includes(presentation.dataFormat)) { - // // localActions.clearConstraints(); - // onPresentationChange(dataFormat); - // } - // }, [dataFormat]); - - if (!dataModel) { - return ; - } - - const presentation = dataPresentationService.getSupported( - DataPresentationType.main, - dataFormat, - presentationId, - dataModel, - resultIndex - ); - - if (!presentation) { - return There are no available presentation for data format: {dataFormat}; - } - - const valuePresentation = valuePresentationId - ? dataPresentationService.getSupported( - DataPresentationType.toolsPanel, - dataFormat, +export const TableViewer = observer( + forwardRef(function TableViewer( + { + tableId, + resultIndex = 0, + presentationId, valuePresentationId, - dataModel, - resultIndex - ) - : null; + simple = false, + context, + className, + onPresentationChange, + onValuePresentationChange, + }, + ref, + ) { + const dataPresentationService = useService(DataPresentationService); + const tableViewerStorageService = useService(TableViewerStorageService); + const dataModel = tableViewerStorageService.get(tableId); + const result = dataModel?.getResult(resultIndex); + const loading = dataModel?.isLoading() ?? true; + const dataFormat = result?.dataFormat || ResultDataFormat.Resultset; + const splitState = useSplitUserState('table-viewer'); - const resultExist = dataModel.source.hasResult(resultIndex); - const overlay = dataModel.source.results.length > 0 && presentation.dataFormat === dataFormat; - const valuePanelDisplayed = ( - valuePresentation - && (valuePresentation.dataFormat === undefined - || valuePresentation.dataFormat === dataFormat) - && overlay - && resultExist - && !simple - ); + const localActions = useObjectRef({ + clearConstraints() { + const constraints = dataModel?.source.tryGetAction(resultIndex, ResultSetConstraintAction); - return styled(viewerStyles, splitStyles)( - - - - - - - - - - - - - dataModel.source.cancel()} - /> - - - - - - - {resultExist && ( - ( + () => ({ + setPresentation(id: string) { + const presentation = dataPresentationService.get(id); + + if (presentation) { + if (presentation.dataFormat !== undefined && presentation.dataFormat !== this.dataModel?.source.dataFormat) { + localActions.clearConstraints(); + this.dataModel?.setDataFormat(presentation.dataFormat).reload(); + } + + this.onPresentationChange(id); + } + }, + + setValuePresentation(id: string | null) { + if (id === this.valuePresentationId) { + return; + } + + if (id === null) { + this.onValuePresentationChange(null); + return; + } + + let presentation = dataPresentationService.get(id); + + if (!presentation && this.dataModel) { + presentation = + dataPresentationService.getSupported(DataPresentationType.toolsPanel, this.dataFormat, undefined, this.dataModel, this.resultIndex) ?? + undefined; + } + + if (presentation) { + this.onValuePresentationChange(presentation.id); + } + }, + switchValuePresentation(id: string | null) { + if (id === this.valuePresentationId) { + this.onValuePresentationChange(null); + return; + } + + this.setValuePresentation(id); + }, + closeValuePresentation() { + this.onValuePresentationChange(null); + }, + }), + { + presentationId: observable, + valuePresentationId: observable, + dataFormat: observable, + resultIndex: observable, + dataModel: observable.ref, + }, + { + presentationId, + valuePresentationId, + dataModel, + resultIndex, + dataFormat, + onPresentationChange, + onValuePresentationChange, + }, + ['setPresentation', 'setValuePresentation', 'switchValuePresentation', 'closeValuePresentation'], + ); + + const needRefresh = getComputed( + () => dataModel?.source.error === null && dataModel.source.results.length === 0 && dataModel.source.outdated && dataModel.source.isLoadable(), + ); + + useEffect(() => { + if (needRefresh) { + dataModel?.request(); + } + }, [needRefresh]); + + // TODO: seems this code is not working because of setting dataFormat in presentation change + // useEffect(() => { + // if (!presentationId || !dataModel) { + // return; + // } + + // const presentation = dataPresentationService.get(presentationId); + + // if (presentation?.dataFormat && !dataModel.supportedDataFormats.includes(presentation.dataFormat)) { + // // localActions.clearConstraints(); + // onPresentationChange(dataFormat); + // } + // }, [dataFormat]); + + if (!dataModel) { + return ; + } + + const presentation = dataPresentationService.getSupported(DataPresentationType.main, dataFormat, presentationId, dataModel, resultIndex); + + if (!presentation) { + return There are no available presentation for data format: {dataFormat}; + } + + const valuePresentation = valuePresentationId + ? dataPresentationService.getSupported(DataPresentationType.toolsPanel, dataFormat, valuePresentationId, dataModel, resultIndex) + : null; + + const resultExist = dataModel.source.hasResult(resultIndex); + const overlay = dataModel.source.results.length > 0 && presentation.dataFormat === dataFormat; + const valuePanelDisplayed = + valuePresentation && + (valuePresentation.dataFormat === undefined || valuePresentation.dataFormat === dataFormat) && + overlay && + resultExist && + !simple; + + return styled( + viewerStyles, + splitStyles, + )( + + + + + + + + + + - )} + + + dataModel.source.cancel()} + /> - - - - - {!simple && ( - - )} - - - - ); -})); + + + + + + {resultExist && ( + + )} + + + + + + {!simple && ( + + )} + + + , + ); + }), +); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewerLoader.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewerLoader.ts index f429ee7ec9..82492390ee 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewerLoader.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewerLoader.ts @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; export const TableViewerLoader = React.lazy(async () => { const { TableViewer } = await import('./TableViewer'); return { default: TableViewer }; -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewerStorageService.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewerStorageService.ts index 3911003f6f..66a773c7ac 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewerStorageService.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewerStorageService.ts @@ -5,8 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import { observable, makeObservable, computed } from 'mobx'; +import { computed, makeObservable, observable } from 'mobx'; import { injectable } from '@cloudbeaver/core-di'; import { ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor'; @@ -45,9 +44,7 @@ export class TableViewerStorageService { return this.tableModelMap.get(tableId) as any; } - add( - model: IDatabaseDataModel - ): IDatabaseDataModel { + add(model: IDatabaseDataModel): IDatabaseDataModel { if (this.tableModelMap.has(model.id)) { return model; } diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/ValuePanel/DataValuePanelBootstrap.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/ValuePanel/DataValuePanelBootstrap.ts index 4e0d826ee8..4d56bcbfa8 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/ValuePanel/DataValuePanelBootstrap.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/ValuePanel/DataValuePanelBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React from 'react'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; @@ -21,10 +20,7 @@ export const ValuePanel = React.lazy(async () => { @injectable() export class DataValuePanelBootstrap extends Bootstrap { - constructor( - private readonly dataPresentationService: DataPresentationService, - private readonly dataValuePanelService: DataValuePanelService - ) { + constructor(private readonly dataPresentationService: DataPresentationService, private readonly dataValuePanelService: DataValuePanelService) { super(); } @@ -34,22 +30,17 @@ export class DataValuePanelBootstrap extends Bootstrap { type: DataPresentationType.toolsPanel, title: 'data_viewer_presentation_value_title', icon: 'value-panel', - hidden: ( - dataFormat, - model, - resultIndex - ) => { + hidden: (dataFormat, model, resultIndex) => { if (!model.source.hasResult(resultIndex)) { return true; } const data = model.source.tryGetAction(resultIndex, ResultSetDataAction); - return data?.empty - || this.dataValuePanelService.getDisplayed({ model, resultIndex, dataFormat }).length === 0; + return data?.empty || this.dataValuePanelService.getDisplayed({ model, resultIndex, dataFormat }).length === 0; }, getPresentationComponent: () => ValuePanel, }); } - load(): void { } + load(): void {} } diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/ValuePanel/DataValuePanelService.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/ValuePanel/DataValuePanelService.ts index 7fd1f28cea..87ea12ad2c 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/ValuePanel/DataValuePanelService.ts +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/ValuePanel/DataValuePanelService.ts @@ -5,7 +5,6 @@ * 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 type { ResultDataFormat } from '@cloudbeaver/core-sdk'; import { ITabInfo, ITabInfoOptions, TabsContainer } from '@cloudbeaver/core-ui'; @@ -37,11 +36,9 @@ export class DataValuePanelService { getDisplayed(props?: IDataValuePanelProps): Array, IDataValuePanelOptions>> { return this.tabs.tabInfoList.filter( - info => ( - ((props?.dataFormat === undefined || props.dataFormat === null) - || info.options?.dataFormat.includes(props.dataFormat)) - && !info.isHidden?.(info.key, props) - ) + info => + (props?.dataFormat === undefined || props.dataFormat === null || info.options?.dataFormat.includes(props.dataFormat)) && + !info.isHidden?.(info.key, props), ); } diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/ValuePanel/ValuePanel.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/ValuePanel/ValuePanel.tsx index 2e09893b1c..f9a6e6a40c 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/ValuePanel/ValuePanel.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/ValuePanel/ValuePanel.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useRef, useState } from 'react'; import styled, { css } from 'reshadow'; @@ -18,47 +17,44 @@ import type { DataPresentationComponent } from '../../DataPresentationService'; import { DataValuePanelService } from './DataValuePanelService'; const styles = css` - table-left-bar { - display: flex; - } - Tab { - composes: theme-ripple from theme-typography--body2 from global; - text-transform: uppercase; - font-weight: normal; + table-left-bar { + display: flex; + } + Tab { + composes: theme-ripple from theme-typography--body2 from global; + text-transform: uppercase; + font-weight: normal; - &:global([aria-selected=true]) { - font-weight: normal !important; - } + &:global([aria-selected='true']) { + font-weight: normal !important; } - TabList { - composes: theme-border-color-background from global; - position: relative; - - &:before { - content: ''; - position: absolute; - bottom: 0; - width: 100%; - border-bottom: solid 2px; - border-color: inherit; - } - } - TabList tab-outer:only-child { - display: none; - } - TabPanel { - padding-top: 8px; - } - TabList, TabPanel { - composes: theme-background-secondary theme-text-on-secondary from global; - } - `; + } + TabList { + composes: theme-border-color-background from global; + position: relative; -export const ValuePanel: DataPresentationComponent = observer(function ValuePanel({ - dataFormat, - model, - resultIndex, -}) { + &:before { + content: ''; + position: absolute; + bottom: 0; + width: 100%; + border-bottom: solid 2px; + border-color: inherit; + } + } + TabList tab-outer:only-child { + display: none; + } + TabPanel { + padding-top: 8px; + } + TabList, + TabPanel { + composes: theme-background-secondary theme-text-on-secondary from global; + } +`; + +export const ValuePanel: DataPresentationComponent = observer(function ValuePanel({ dataFormat, model, resultIndex }) { const service = useService(DataValuePanelService); const [currentTabId, setCurrentTabId] = useState(''); const lastTabId = useRef(''); @@ -73,7 +69,11 @@ export const ValuePanel: DataPresentationComponent = ob } } - return styled(BASE_TAB_STYLES, styles, UNDERLINE_TAB_STYLES)( + return styled( + BASE_TAB_STYLES, + styles, + UNDERLINE_TAB_STYLES, + )( = ob > - + , ); }); diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/BooleanValue/BooleanValuePresentation.tsx b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/BooleanValue/BooleanValuePresentation.tsx index a7e53bb36e..6a4d9cdf8c 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/BooleanValue/BooleanValuePresentation.tsx +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/BooleanValue/BooleanValuePresentation.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -30,75 +29,54 @@ const styles = css` } `; -export const BooleanValuePresentation: TabContainerPanelComponent> = observer(function BooleanValuePresentation({ - model, - resultIndex, -}) { - const translate = useTranslate(); - const selection = model.source.getAction(resultIndex, ResultSetSelectAction); - const focusCell = selection.getFocusedElement(); +export const BooleanValuePresentation: TabContainerPanelComponent> = observer( + function BooleanValuePresentation({ model, resultIndex }) { + const translate = useTranslate(); + const selection = model.source.getAction(resultIndex, ResultSetSelectAction); + const focusCell = selection.getFocusedElement(); - if (!selection.elements.length && !focusCell) { - return null; - } + if (!selection.elements.length && !focusCell) { + return null; + } - let value: boolean | null | undefined; + let value: boolean | null | undefined; - const view = model.source.getAction(resultIndex, ResultSetViewAction); - const editor = model.source.getAction(resultIndex, ResultSetEditAction); + const view = model.source.getAction(resultIndex, ResultSetViewAction); + const editor = model.source.getAction(resultIndex, ResultSetEditAction); - const firstSelectedCell = selection.elements[0] || focusCell; - const cellValue = view.getCellValue(firstSelectedCell); + const firstSelectedCell = selection.elements[0] || focusCell; + const cellValue = view.getCellValue(firstSelectedCell); - if (typeof cellValue === 'string' && isStringifiedBoolean(cellValue)) { - value = cellValue.toLowerCase() === 'true'; - } else if (typeof cellValue === 'boolean' || cellValue === null) { - value = cellValue; - } + if (typeof cellValue === 'string' && isStringifiedBoolean(cellValue)) { + value = cellValue.toLowerCase() === 'true'; + } else if (typeof cellValue === 'boolean' || cellValue === null) { + value = cellValue; + } - if (value === undefined) { - return {translate('data_viewer_presentation_value_boolean_placeholder')}; - } + if (value === undefined) { + return {translate('data_viewer_presentation_value_boolean_placeholder')}; + } - const format = model.source.getAction(resultIndex, ResultSetFormatAction); + const format = model.source.getAction(resultIndex, ResultSetFormatAction); - const column = view.getColumn(firstSelectedCell.column); - const nullable = column?.required === false; - const readonly = model.isReadonly(resultIndex) - || model.isDisabled(resultIndex) - || format.isReadOnly(firstSelectedCell); + const column = view.getColumn(firstSelectedCell.column); + const nullable = column?.required === false; + const readonly = model.isReadonly(resultIndex) || model.isDisabled(resultIndex) || format.isReadOnly(firstSelectedCell); - return styled(styles)( - - editor.set(firstSelectedCell, true)} - > - TRUE - - editor.set(firstSelectedCell, false)} - > - FALSE - - {nullable && ( - editor.set(firstSelectedCell, null)} - > - NULL + return styled(styles)( + + editor.set(firstSelectedCell, true)}> + TRUE - )} - - ); -}); + editor.set(firstSelectedCell, false)}> + FALSE + + {nullable && ( + editor.set(firstSelectedCell, null)}> + NULL + + )} + , + ); + }, +); diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/BooleanValue/BooleanValuePresentationBootstrap.ts b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/BooleanValue/BooleanValuePresentationBootstrap.ts index 05db58938c..5901e98157 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/BooleanValue/BooleanValuePresentationBootstrap.ts +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/BooleanValue/BooleanValuePresentationBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { ResultDataFormat } from '@cloudbeaver/core-sdk'; @@ -57,5 +56,5 @@ export class BooleanValuePresentationBootstrap extends Bootstrap { }); } - load(): void { } + load(): void {} } diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/BooleanValue/isBooleanValuePresentationAvailable.ts b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/BooleanValue/isBooleanValuePresentationAvailable.ts index 61eb8fedf6..c54ff41941 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/BooleanValue/isBooleanValuePresentationAvailable.ts +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/BooleanValue/isBooleanValuePresentationAvailable.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { SqlResultColumn } from '@cloudbeaver/core-sdk'; import type { IResultSetValue } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetFormatAction'; @@ -15,10 +14,8 @@ export function isStringifiedBoolean(value: string): boolean { } export function isBooleanValuePresentationAvailable(cellValue: IResultSetValue, column: SqlResultColumn): boolean { - return column.dataKind?.toLowerCase() === 'boolean' - && ( - typeof cellValue === 'boolean' - || cellValue === null - || (typeof cellValue === 'string' && isStringifiedBoolean(cellValue)) - ); + return ( + column.dataKind?.toLowerCase() === 'boolean' && + (typeof cellValue === 'boolean' || cellValue === null || (typeof cellValue === 'string' && isStringifiedBoolean(cellValue))) + ); } diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/ImageValuePresentation.tsx b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/ImageValuePresentation.tsx index 8802cf70f9..3b652df219 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/ImageValuePresentation.tsx +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/ImageValuePresentation.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react-lite'; import styled, { css, use } from 'reshadow'; @@ -46,7 +45,7 @@ const styles = css` flex: 1; flex-direction: column; } - + image { flex: 1; display: flex; @@ -73,150 +72,142 @@ const Tools = observer(function Tools({ loading, stretch, onToggleS )} {onToggleStretch && ( - - + + - + )} - + , ); }); -export const ImageValuePresentation: TabContainerPanelComponent> = observer(function ImageValuePresentation({ - model, - resultIndex, -}) { - const translate = useTranslate(); - const notificationService = useService(NotificationService); - const quotasService = useService(QuotasService); - const style = useStyles(styles); +export const ImageValuePresentation: TabContainerPanelComponent> = observer( + function ImageValuePresentation({ model, resultIndex }) { + const translate = useTranslate(); + const notificationService = useService(NotificationService); + const quotasService = useService(QuotasService); + const style = useStyles(styles); - const content = model.source.getAction(resultIndex, ResultSetDataContentAction); + const content = model.source.getAction(resultIndex, ResultSetDataContentAction); - const state = useObservableRef(() => ({ - get selectedCell() { - const selection = this.model.source.getAction(this.resultIndex, ResultSetSelectAction); - const focusCell = selection.getFocusedElement(); + const state = useObservableRef( + () => ({ + get selectedCell() { + const selection = this.model.source.getAction(this.resultIndex, ResultSetSelectAction); + const focusCell = selection.getFocusedElement(); - return selection.elements[0] || focusCell; - }, - get cellValue() { - const view = this.model.source.getAction(this.resultIndex, ResultSetViewAction); - const cellValue = view.getCellValue(this.selectedCell); + return selection.elements[0] || focusCell; + }, + get cellValue() { + const view = this.model.source.getAction(this.resultIndex, ResultSetViewAction); + const cellValue = view.getCellValue(this.selectedCell); - return cellValue; - }, - get src() { - if (this.savedSrc) { - return this.savedSrc; - } + return cellValue; + }, + get src() { + if (this.savedSrc) { + return this.savedSrc; + } - if (isResultSetContentValue(this.cellValue) && this.cellValue.binary) { - return `data:${getMIME(this.cellValue.binary)};base64,${this.cellValue.binary}`; - } else if (typeof this.cellValue === 'string' && isValidUrl(this.cellValue) && isImageFormat(this.cellValue)) { - return this.cellValue; - } + if (isResultSetContentValue(this.cellValue) && this.cellValue.binary) { + return `data:${getMIME(this.cellValue.binary)};base64,${this.cellValue.binary}`; + } else if (typeof this.cellValue === 'string' && isValidUrl(this.cellValue) && isImageFormat(this.cellValue)) { + return this.cellValue; + } - return ''; - }, - get savedSrc() { - return content.retrieveFileDataUrlFromCache(this.selectedCell); - }, - get canSave() { - if (this.truncated) { - return content.isDownloadable(this.selectedCell); - } + return ''; + }, + get savedSrc() { + return content.retrieveFileDataUrlFromCache(this.selectedCell); + }, + get canSave() { + if (this.truncated) { + return content.isDownloadable(this.selectedCell); + } - return !!this.src; - }, - get truncated() { - return isResultSetContentValue(this.cellValue) && content.isContentTruncated(this.cellValue); - }, - stretch: false, - toggleStretch() { - this.stretch = !this.stretch; - }, - async save() { - try { - if (this.truncated) { - await content.downloadFileData(this.selectedCell); - } else { - download(this.src, '', true); + return !!this.src; + }, + get truncated() { + return isResultSetContentValue(this.cellValue) && content.isContentTruncated(this.cellValue); + }, + stretch: false, + toggleStretch() { + this.stretch = !this.stretch; + }, + async save() { + try { + if (this.truncated) { + await content.downloadFileData(this.selectedCell); + } else { + download(this.src, '', true); + } + } catch (exception: any) { + this.notificationService.logException(exception, 'data_viewer_presentation_value_content_download_error'); + } + }, + }), + { + selectedCell: computed, + cellValue: computed, + src: computed, + savedSrc: computed, + canSave: computed, + truncated: computed, + stretch: observable.ref, + toggleStretch: action.bound, + save: action.bound, + }, + { model, resultIndex, notificationService }, + ); + + const save = state.canSave ? state.save : undefined; + const loading = model.isLoading(); + + if (state.truncated && !state.savedSrc) { + const limit = bytesToSize(quotasService.getQuota('sqlBinaryPreviewMaxLength')); + const valueSize = bytesToSize((state.cellValue as unknown as IResultSetContentValue).contentLength ?? 0); + + const load = async () => { + try { + await content.resolveFileDataUrl(state.selectedCell); + } catch (exception: any) { + notificationService.logException(exception, 'data_viewer_presentation_value_content_download_error'); } - } catch (exception: any) { - this.notificationService.logException(exception, 'data_viewer_presentation_value_content_download_error'); - } - }, - }), { - selectedCell: computed, - cellValue: computed, - src: computed, - savedSrc: computed, - canSave: computed, - truncated: computed, - stretch: observable.ref, - toggleStretch: action.bound, - save: action.bound, - }, { model, resultIndex, notificationService }); + }; - const save = state.canSave ? state.save : undefined; - const loading = model.isLoading(); - - if (state.truncated && !state.savedSrc) { - const limit = bytesToSize(quotasService.getQuota('sqlBinaryPreviewMaxLength')); - const valueSize = bytesToSize((state.cellValue as unknown as IResultSetContentValue).contentLength ?? 0); - - const load = async () => { - try { - await content.resolveFileDataUrl(state.selectedCell); - } catch (exception: any) { - notificationService.logException(exception, 'data_viewer_presentation_value_content_download_error'); - } - }; + return styled(style)( + + + {content.isDownloadable(state.selectedCell) && ( + + )} + + + , + ); + } return styled(style)( - - {content.isDownloadable(state.selectedCell) && ( - - )} - - - + + + + + , ); - } - - return styled(style)( - - - - - - - ); -}); \ No newline at end of file + }, +); diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/ImageValuePresentationBootstrap.ts b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/ImageValuePresentationBootstrap.ts index 2a10cbd8d6..eccdc1a70d 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/ImageValuePresentationBootstrap.ts +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/ImageValuePresentationBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { ResultDataFormat } from '@cloudbeaver/core-sdk'; import { getMIME, isImageFormat, isValidUrl } from '@cloudbeaver/core-utils'; @@ -47,10 +46,7 @@ export class ImageValuePresentationBootstrap extends Bootstrap { const cellValue = view.getCellValue(firstSelectedCell); - return !( - this.isImageUrl(cellValue) - || (isResultSetContentValue(cellValue) && this.isImage(cellValue)) - ); + return !(this.isImageUrl(cellValue) || (isResultSetContentValue(cellValue) && this.isImage(cellValue))); } return true; @@ -58,7 +54,7 @@ export class ImageValuePresentationBootstrap extends Bootstrap { }); } - load(): void { } + load(): void {} private isImage(value: IResultSetContentValue | null) { if (value !== null && 'binary' in value) { diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/QuotaPlaceholder.tsx b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/QuotaPlaceholder.tsx index 736e0221c8..b8349351bd 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/QuotaPlaceholder.tsx +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/QuotaPlaceholder.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -40,12 +39,7 @@ const style = css` } `; -export const QuotaPlaceholder: React.FC> = observer(function QuotaPlaceholder({ - limit, - size, - className, - children, -}) { +export const QuotaPlaceholder: React.FC> = observer(function QuotaPlaceholder({ limit, size, className, children }) { const translate = useTranslate(); const admin = usePermission(EAdminPermission.admin); @@ -57,10 +51,12 @@ export const QuotaPlaceholder: React.FC> = observ {translate('data_viewer_presentation_value_content_truncated_placeholder') + ' '} {admin ? ( - + {translate('ui_limit')} - ) : translate('ui_limit')} + ) : ( + translate('ui_limit') + )} {limit && `${translate('ui_limit')}: ${limit}`} @@ -68,6 +64,6 @@ export const QuotaPlaceholder: React.FC> = observ {size && `${translate('data_viewer_presentation_value_content_value_size')}: ${size}`}

{children} - + , ); -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentation.tsx b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentation.tsx index 73b32628d4..2d0ccc900b 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentation.tsx +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentation.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observable } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useMemo } from 'react'; @@ -65,146 +64,149 @@ const styles = css` & Tab { border-bottom: 0; - &:global([aria-selected="false"]) { + &:global([aria-selected='false']) { border-bottom: 0 !important; } } } `; -export const TextValuePresentation: TabContainerPanelComponent> = observer(function TextValuePresentation({ - model, - resultIndex, -}) { - const translate = useTranslate(); - const notificationService = useService(NotificationService); - const quotasService = useService(QuotasService); - const textValuePresentationService = useService(TextValuePresentationService); - const style = useStyles(styles, BASE_CONTAINERS_STYLES, UNDERLINE_TAB_STYLES, VALUE_PANEL_TOOLS_STYLES); +export const TextValuePresentation: TabContainerPanelComponent> = observer( + function TextValuePresentation({ model, resultIndex }) { + const translate = useTranslate(); + const notificationService = useService(NotificationService); + const quotasService = useService(QuotasService); + const textValuePresentationService = useService(TextValuePresentationService); + const style = useStyles(styles, BASE_CONTAINERS_STYLES, UNDERLINE_TAB_STYLES, VALUE_PANEL_TOOLS_STYLES); - const state = useObservableRef(() => ({ - currentContentType: 'text/plain', - lastContentType: 'text/plain', + const state = useObservableRef( + () => ({ + currentContentType: 'text/plain', + lastContentType: 'text/plain', - setContentType(type: string) { - this.currentContentType = type; - }, - setDefaultContentType(type: string) { - this.currentContentType = type; - this.lastContentType = type; - }, - }), { - currentContentType: observable.ref, - lastContentType: observable.ref, - }, false, ['setContentType', 'setDefaultContentType']); + setContentType(type: string) { + this.currentContentType = type; + }, + setDefaultContentType(type: string) { + this.currentContentType = type; + this.lastContentType = type; + }, + }), + { + currentContentType: observable.ref, + lastContentType: observable.ref, + }, + false, + ['setContentType', 'setDefaultContentType'], + ); - const selection = model.source.getAction(resultIndex, ResultSetSelectAction); - const editor = model.source.getAction(resultIndex, ResultSetEditAction); - const content = model.source.getAction(resultIndex, ResultSetDataContentAction); + const selection = model.source.getAction(resultIndex, ResultSetSelectAction); + const editor = model.source.getAction(resultIndex, ResultSetEditAction); + const content = model.source.getAction(resultIndex, ResultSetDataContentAction); - const focusCell = selection.getFocusedElement(); + const focusCell = selection.getFocusedElement(); - let stringValue = ''; - let contentType = 'text/plain'; - let firstSelectedCell: IResultSetElementKey | undefined; - let readonly = true; - let valueTruncated = false; - let limit: string | undefined; - let valueSize: string | undefined; + let stringValue = ''; + let contentType = 'text/plain'; + let firstSelectedCell: IResultSetElementKey | undefined; + let readonly = true; + let valueTruncated = false; + let limit: string | undefined; + let valueSize: string | undefined; - if (selection.elements.length > 0 || focusCell) { - const view = model.source.getAction(resultIndex, ResultSetViewAction); - const format = model.source.getAction(resultIndex, ResultSetFormatAction); + if (selection.elements.length > 0 || focusCell) { + const view = model.source.getAction(resultIndex, ResultSetViewAction); + const format = model.source.getAction(resultIndex, ResultSetFormatAction); - firstSelectedCell = selection.elements[0] || focusCell; + firstSelectedCell = selection.elements[0] || focusCell; - const value = view.getCellValue(firstSelectedCell) ?? ''; + const value = view.getCellValue(firstSelectedCell) ?? ''; - stringValue = format.getText(value) ?? ''; - readonly = format.isReadOnly(firstSelectedCell); + stringValue = format.getText(value) ?? ''; + readonly = format.isReadOnly(firstSelectedCell); + if (isResultSetContentValue(value)) { + valueTruncated = content.isContentTruncated(value); - if (isResultSetContentValue(value)) { - valueTruncated = content.isContentTruncated(value); - - if (valueTruncated) { - limit = bytesToSize(quotasService.getQuota('sqlBinaryPreviewMaxLength')); - valueSize = bytesToSize(value.contentLength ?? 0); - } - - if (value.contentType) { - contentType = value.contentType; - - if (contentType === 'text/json') { - contentType = 'application/json'; + if (valueTruncated) { + limit = bytesToSize(quotasService.getQuota('sqlBinaryPreviewMaxLength')); + valueSize = bytesToSize(value.contentLength ?? 0); } - if (!textValuePresentationService.tabs.has(contentType)) { - contentType = 'text/plain'; + if (value.contentType) { + contentType = value.contentType; + + if (contentType === 'text/json') { + contentType = 'application/json'; + } + + if (!textValuePresentationService.tabs.has(contentType)) { + contentType = 'text/plain'; + } } } } - } - readonly = model.isReadonly(resultIndex) || model.isDisabled(resultIndex) || readonly; + readonly = model.isReadonly(resultIndex) || model.isDisabled(resultIndex) || readonly; - if (contentType !== state.lastContentType) { - state.setDefaultContentType(contentType); - } - - const formatter = useAutoFormat(); - - function handleChange(newValue: string) { - if (firstSelectedCell && !readonly) { - editor.set(firstSelectedCell, newValue); - } - } - - async function save() { - if (!firstSelectedCell) { - return; + if (contentType !== state.lastContentType) { + state.setDefaultContentType(contentType); } - try { - await content.downloadFileData(firstSelectedCell); - } catch (exception) { - notificationService.logException(exception as any, 'data_viewer_presentation_value_content_download_error'); + const formatter = useAutoFormat(); + + function handleChange(newValue: string) { + if (firstSelectedCell && !readonly) { + editor.set(firstSelectedCell, newValue); + } } - } - const autoFormat = !!firstSelectedCell && !editor.isElementEdited(firstSelectedCell); - const canSave = !!firstSelectedCell && content.isDownloadable(firstSelectedCell); - const typeExtension = useMemo(() => getTypeExtension(state.currentContentType) ?? [], [state.currentContentType]); + async function save() { + if (!firstSelectedCell) { + return; + } - const value = autoFormat ? formatter.format(state.currentContentType, stringValue) : stringValue; + try { + await content.downloadFileData(firstSelectedCell); + } catch (exception) { + notificationService.logException(exception as any, 'data_viewer_presentation_value_content_download_error'); + } + } - return styled(style)( - - - state.setContentType(tab.tabId)} - > - - - - handleChange(value)} - /> - {valueTruncated && } - {canSave && ( - - - - )} - - ); -}); + const autoFormat = !!firstSelectedCell && !editor.isElementEdited(firstSelectedCell); + const canSave = !!firstSelectedCell && content.isDownloadable(firstSelectedCell); + const typeExtension = useMemo(() => getTypeExtension(state.currentContentType) ?? [], [state.currentContentType]); + + const value = autoFormat ? formatter.format(state.currentContentType, stringValue) : stringValue; + + return styled(style)( + + + state.setContentType(tab.tabId)} + > + + + + handleChange(value)} + /> + {valueTruncated && } + {canSave && ( + + + + )} + , + ); + }, +); diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentationBootstrap.ts b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentationBootstrap.ts index 9ecd3685aa..a3faaf8720 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentationBootstrap.ts +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentationBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import React, { lazy } from 'react'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; @@ -23,7 +22,7 @@ const TextValuePresentation = lazy(async () => { export class TextValuePresentationBootstrap extends Bootstrap { constructor( private readonly textValuePresentationService: TextValuePresentationService, - private readonly dataValuePanelService: DataValuePanelService + private readonly dataValuePanelService: DataValuePanelService, ) { super(); } @@ -63,5 +62,5 @@ export class TextValuePresentationBootstrap extends Bootstrap { }); } - load(): void { } + load(): void {} } diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentationService.ts b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentationService.ts index b83b9f2482..5d08269de2 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentationService.ts +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentationService.ts @@ -5,7 +5,6 @@ * 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 { ITabInfo, ITabInfoOptions, TabsContainer } from '@cloudbeaver/core-ui'; diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/getTypeExtension.ts b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/getTypeExtension.ts index c09e335c32..69fddfa9ab 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/getTypeExtension.ts +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/getTypeExtension.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { HTML_EDITOR, JSON_EDITOR, XML_EDITOR } from '@cloudbeaver/plugin-codemirror6'; // @TODO These imports are quite heavy @@ -20,4 +19,4 @@ export function getTypeExtension(type: string) { default: return; } -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/useAutoFormat.ts b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/useAutoFormat.ts index da2b1a3771..80a7f8b711 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/useAutoFormat.ts +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/useAutoFormat.ts @@ -5,25 +5,27 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { useObjectRef } from '@cloudbeaver/core-blocks'; export function useAutoFormat() { - return useObjectRef(() => ({ - format(type: string, value: string) { - try { - switch (type) { - case 'application/json': - return JSON.stringify(JSON.parse(value), null, 2); - case 'text/xml': - case 'text/html': - return value; - default: - return value; + return useObjectRef( + () => ({ + format(type: string, value: string) { + try { + switch (type) { + case 'application/json': + return JSON.stringify(JSON.parse(value), null, 2); + case 'text/xml': + case 'text/html': + return value; + default: + return value; + } + } catch { + return value; } - } catch { - return value; - } - }, - }), false); + }, + }), + false, + ); } diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ValuePanelTools/VALUE_PANEL_TOOLS_STYLES.ts b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ValuePanelTools/VALUE_PANEL_TOOLS_STYLES.ts index 20a0276987..1a446d8ec9 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ValuePanelTools/VALUE_PANEL_TOOLS_STYLES.ts +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ValuePanelTools/VALUE_PANEL_TOOLS_STYLES.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { css } from 'reshadow'; export const VALUE_PANEL_TOOLS_STYLES = css` @@ -33,4 +32,4 @@ export const VALUE_PANEL_TOOLS_STYLES = css` width: 100%; height: 100%; } -`; \ No newline at end of file +`; diff --git a/webapp/packages/plugin-data-viewer/src/index.ts b/webapp/packages/plugin-data-viewer/src/index.ts index eb5509a2a9..d67774cee5 100644 --- a/webapp/packages/plugin-data-viewer/src/index.ts +++ b/webapp/packages/plugin-data-viewer/src/index.ts @@ -59,4 +59,4 @@ export * from './DataPresentationService'; export * from './DataViewerDataChangeConfirmationService'; export * from './useDataModel'; export * from './ValuePanelPresentation/BooleanValue/isBooleanValuePresentationAvailable'; -export * from './DataViewerSettingsService'; \ No newline at end of file +export * from './DataViewerSettingsService'; diff --git a/webapp/packages/plugin-data-viewer/src/manifest.ts b/webapp/packages/plugin-data-viewer/src/manifest.ts index 8e3bcc2c27..07f2004bbf 100644 --- a/webapp/packages/plugin-data-viewer/src/manifest.ts +++ b/webapp/packages/plugin-data-viewer/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { DataPresentationService } from './DataPresentationService'; diff --git a/webapp/packages/plugin-data-viewer/src/useDataModel.ts b/webapp/packages/plugin-data-viewer/src/useDataModel.ts index 6dd6b5d675..a2a2e450eb 100644 --- a/webapp/packages/plugin-data-viewer/src/useDataModel.ts +++ b/webapp/packages/plugin-data-viewer/src/useDataModel.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { useService } from '@cloudbeaver/core-di'; import type { IDatabaseDataModel } from './DatabaseDataModel/IDatabaseDataModel'; diff --git a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSchemaManagerBootstrap.ts b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSchemaManagerBootstrap.ts index 635053c03b..359304a574 100644 --- a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSchemaManagerBootstrap.ts +++ b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSchemaManagerBootstrap.ts @@ -5,14 +5,28 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { AppAuthService } from '@cloudbeaver/core-authentication'; -import { compareConnectionsInfo, ConnectionInfoResource, ConnectionsManagerService, ConnectionsSettingsService, ContainerResource, createConnectionParam, serializeConnectionParam } from '@cloudbeaver/core-connections'; +import { + compareConnectionsInfo, + ConnectionInfoResource, + ConnectionsManagerService, + ConnectionsSettingsService, + ContainerResource, + createConnectionParam, + serializeConnectionParam, +} from '@cloudbeaver/core-connections'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { EObjectFeature, NodeManagerUtils } from '@cloudbeaver/core-navigation-tree'; import { getCachedMapResourceLoaderState } from '@cloudbeaver/core-sdk'; import { OptionsPanelService } from '@cloudbeaver/core-ui'; -import { DATA_CONTEXT_LOADABLE_STATE, DATA_CONTEXT_MENU, MenuBaseItem, menuExtractItems, MenuSeparatorItem, MenuService } from '@cloudbeaver/core-view'; +import { + DATA_CONTEXT_LOADABLE_STATE, + DATA_CONTEXT_MENU, + MenuBaseItem, + menuExtractItems, + MenuSeparatorItem, + MenuService, +} from '@cloudbeaver/core-view'; import { MENU_APP_ACTIONS } from '@cloudbeaver/plugin-top-app-bar'; import { ConnectionSchemaManagerService } from './ConnectionSchemaManagerService'; @@ -21,14 +35,10 @@ import type { IConnectionSelectorExtraProps } from './ConnectionSelector/IConnec import { MENU_CONNECTION_DATA_CONTAINER_SELECTOR } from './MENU_CONNECTION_DATA_CONTAINER_SELECTOR'; import { MENU_CONNECTION_SELECTOR } from './MENU_CONNECTION_SELECTOR'; - @injectable() export class ConnectionSchemaManagerBootstrap extends Bootstrap { get connectionSelectorLoading(): boolean { - return ( - this.connectionSchemaManagerService.isChangingConnection - || this.connectionsManagerService.containerContainers.isLoading() - ); + return this.connectionSchemaManagerService.isChangingConnection || this.connectionsManagerService.containerContainers.isLoading(); } constructor( @@ -47,20 +57,20 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap { register(): void { this.addTopAppMenuItems(); - this.connectionInfoResource.onDataUpdate - .addHandler(this.connectionSchemaManagerService.onConnectionUpdate.bind(this.connectionSchemaManagerService)); + this.connectionInfoResource.onDataUpdate.addHandler( + this.connectionSchemaManagerService.onConnectionUpdate.bind(this.connectionSchemaManagerService), + ); this.menuService.setHandler({ id: 'connection-selector-base', isApplicable: context => context.hasValue(DATA_CONTEXT_MENU, MENU_CONNECTION_SELECTOR), isLoading: () => this.connectionSelectorLoading, isHidden: () => this.isHidden() || !this.appAuthService.authenticated, - isDisabled: () => ( - !this.connectionSchemaManagerService.isConnectionChangeable - || this.connectionSelectorLoading - || !this.connectionsManagerService.hasAnyConnection() - || this.connectionSchemaManagerService.isChangingConnectionContainer - ), + isDisabled: () => + !this.connectionSchemaManagerService.isConnectionChangeable || + this.connectionSelectorLoading || + !this.connectionsManagerService.hasAnyConnection() || + this.connectionSchemaManagerService.isChangingConnectionContainer, getInfo: (context, menu) => { const connection = this.connectionSchemaManagerService.currentConnection; const label = connection?.name || 'plugin_datasource_context_switch_select_connection'; @@ -80,39 +90,37 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap { const state = context.get(DATA_CONTEXT_LOADABLE_STATE); - return state.getState( - menu.id, - () => { - if (!this.connectionSchemaManagerService.activeConnectionKey) { - return this.appAuthService.loaders; - } - return [ - ...this.appAuthService.loaders, - getCachedMapResourceLoaderState(this.containerResource, { + return state.getState(menu.id, () => { + if (!this.connectionSchemaManagerService.activeConnectionKey) { + return this.appAuthService.loaders; + } + return [ + ...this.appAuthService.loaders, + getCachedMapResourceLoaderState( + this.containerResource, + { ...this.connectionSchemaManagerService.activeConnectionKey, catalogId: this.connectionSchemaManagerService.activeObjectCatalogId, - }, undefined), - ]; - } - ); + }, + undefined, + ), + ]; + }); }, }); this.menuService.addCreator({ menus: [MENU_CONNECTION_SELECTOR], - isApplicable: () => ( - this.connectionsManagerService.hasAnyConnection() - && this.connectionSchemaManagerService.isConnectionChangeable - ), + isApplicable: () => this.connectionsManagerService.hasAnyConnection() && this.connectionSchemaManagerService.isConnectionChangeable, getItems: (context, items) => { items = [...items]; const connections = this.connectionsManagerService.projectConnections .filter(connection => { if ( - !this.connectionSchemaManagerService.isProjectChangeable - && this.connectionSchemaManagerService.activeProjectId - && connection.projectId !== this.connectionSchemaManagerService.activeProjectId + !this.connectionSchemaManagerService.isProjectChangeable && + this.connectionSchemaManagerService.activeProjectId && + connection.projectId !== this.connectionSchemaManagerService.activeProjectId ) { return false; } @@ -127,34 +135,31 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap { return Number(b.connected) - Number(a.connected); }); - for (const connection of connections) { const connectionKey = createConnectionParam(connection); - items.push(new MenuBaseItem( - { - id: serializeConnectionParam(connectionKey), - label: connection.name, - tooltip: connection.description, - }, - { - onSelect: () => { - this.connectionSchemaManagerService.selectConnection(connectionKey); + items.push( + new MenuBaseItem( + { + id: serializeConnectionParam(connectionKey), + label: connection.name, + tooltip: connection.description, }, - }, - { - iconComponent: () => ConnectionIcon, - isDisabled: () => ( - this.connectionSchemaManagerService.currentConnectionKey !== null - && this.connectionSchemaManagerService.currentConnectionKey !== undefined - && this.connectionInfoResource.isKeyEqual( - this.connectionSchemaManagerService.currentConnectionKey, - connectionKey - ) - ), - getExtraProps: () => ({ connectionKey }), - } - )); + { + onSelect: () => { + this.connectionSchemaManagerService.selectConnection(connectionKey); + }, + }, + { + iconComponent: () => ConnectionIcon, + isDisabled: () => + this.connectionSchemaManagerService.currentConnectionKey !== null && + this.connectionSchemaManagerService.currentConnectionKey !== undefined && + this.connectionInfoResource.isKeyEqual(this.connectionSchemaManagerService.currentConnectionKey, connectionKey), + getExtraProps: () => ({ connectionKey }), + }, + ), + ); } return items; @@ -164,34 +169,22 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap { this.menuService.setHandler({ id: 'connection-data-container-selector-base', isApplicable: context => context.hasValue(DATA_CONTEXT_MENU, MENU_CONNECTION_DATA_CONTAINER_SELECTOR), - isDisabled: () => ( - !this.connectionSchemaManagerService.currentConnection?.connected - || this.connectionSelectorLoading - || this.connectionSchemaManagerService.isChangingConnectionContainer - || ( - !this.connectionSchemaManagerService.isObjectCatalogChangeable - && !this.connectionSchemaManagerService.isObjectSchemaChangeable - ) - ), - isLoading: () => ( - !this.connectionSelectorLoading - && this.connectionSchemaManagerService.isChangingConnectionContainer - ), - isHidden: () => ( - this.isHidden() - || !this.appAuthService.authenticated - || !this.connectionSchemaManagerService.objectContainerList - || ( - this.connectionSchemaManagerService.currentObjectSchemaId === undefined - && this.connectionSchemaManagerService.currentObjectCatalogId === undefined - && !this.connectionSchemaManagerService.isObjectCatalogChangeable - && !this.connectionSchemaManagerService.isObjectSchemaChangeable - ) - || ( - this.connectionSchemaManagerService.objectContainerList.schemaList.length === 0 - && this.connectionSchemaManagerService.objectContainerList.catalogList.length === 0 - ) - ), + isDisabled: () => + !this.connectionSchemaManagerService.currentConnection?.connected || + this.connectionSelectorLoading || + this.connectionSchemaManagerService.isChangingConnectionContainer || + (!this.connectionSchemaManagerService.isObjectCatalogChangeable && !this.connectionSchemaManagerService.isObjectSchemaChangeable), + isLoading: () => !this.connectionSelectorLoading && this.connectionSchemaManagerService.isChangingConnectionContainer, + isHidden: () => + this.isHidden() || + !this.appAuthService.authenticated || + !this.connectionSchemaManagerService.objectContainerList || + (this.connectionSchemaManagerService.currentObjectSchemaId === undefined && + this.connectionSchemaManagerService.currentObjectCatalogId === undefined && + !this.connectionSchemaManagerService.isObjectCatalogChangeable && + !this.connectionSchemaManagerService.isObjectSchemaChangeable) || + (this.connectionSchemaManagerService.objectContainerList.schemaList.length === 0 && + this.connectionSchemaManagerService.objectContainerList.catalogList.length === 0), getLoader: (context, menu) => { if (this.isHidden()) { return []; @@ -199,10 +192,7 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap { const state = context.get(DATA_CONTEXT_LOADABLE_STATE); - return state.getState( - menu.id, - () => this.appAuthService.loaders - ); + return state.getState(menu.id, () => this.appAuthService.loaders); }, hideIfEmpty: () => false, getInfo: (context, menu) => { @@ -212,30 +202,22 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap { let label = NodeManagerUtils.concatSchemaAndCatalog( connectionSchemaManagerService.currentObjectCatalogId, - connectionSchemaManagerService.currentObjectSchemaId + connectionSchemaManagerService.currentObjectSchemaId, ); if (!label) { label = 'plugin_datasource_context_switch_select_container'; } - if ( - !connectionSchemaManagerService.currentObjectSchema - && !connectionSchemaManagerService.currentObjectCatalog - ) { + if (!connectionSchemaManagerService.currentObjectSchema && !connectionSchemaManagerService.currentObjectCatalog) { icon = undefined; - } else if ( - connectionSchemaManagerService.currentObjectSchema?.object?.features?.includes(EObjectFeature.schema) - ) { + } else if (connectionSchemaManagerService.currentObjectSchema?.object?.features?.includes(EObjectFeature.schema)) { // TODO move such kind of icon paths to a set of constants icon = '/icons/plugin_datasource_context_switch_schema_m.svg'; - } else if ( - connectionSchemaManagerService.currentObjectCatalog?.object?.features?.includes(EObjectFeature.catalog) - ) { + } else if (connectionSchemaManagerService.currentObjectCatalog?.object?.features?.includes(EObjectFeature.catalog)) { icon = '/icons/plugin_datasource_context_switch_database_m.svg'; } - return { ...menu, icon, @@ -246,10 +228,7 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap { this.menuService.addCreator({ menus: [MENU_CONNECTION_DATA_CONTAINER_SELECTOR], - isApplicable: () => ( - this.connectionSchemaManagerService.isObjectCatalogChangeable - && !!this.connectionSchemaManagerService.objectContainerList - ), + isApplicable: () => this.connectionSchemaManagerService.isObjectCatalogChangeable && !!this.connectionSchemaManagerService.objectContainerList, getItems: (context, items) => { items = [...items]; @@ -257,41 +236,37 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap { return []; } - const schemaList = this.connectionSchemaManagerService.objectContainerList.schemaList - .slice() - .sort((a, b) => { - if (a.name === b.name) { - return 0; - } - - if (a.name === this.connectionSchemaManagerService.currentObjectSchemaId) { - return -1; - } - - if (b.name === this.connectionSchemaManagerService.currentObjectSchemaId) { - return 1; - } - + const schemaList = this.connectionSchemaManagerService.objectContainerList.schemaList.slice().sort((a, b) => { + if (a.name === b.name) { return 0; - }); + } - const catalogList = this.connectionSchemaManagerService.objectContainerList.catalogList - .slice() - .sort((a, b) => { - if (a.catalog.name === b.catalog.name) { - return 0; - } + if (a.name === this.connectionSchemaManagerService.currentObjectSchemaId) { + return -1; + } - if (a.catalog.name === this.connectionSchemaManagerService.currentObjectCatalogId) { - return -1; - } + if (b.name === this.connectionSchemaManagerService.currentObjectSchemaId) { + return 1; + } - if (b.catalog.name === this.connectionSchemaManagerService.currentObjectCatalogId) { - return 1; - } + return 0; + }); + const catalogList = this.connectionSchemaManagerService.objectContainerList.catalogList.slice().sort((a, b) => { + if (a.catalog.name === b.catalog.name) { return 0; - }); + } + + if (a.catalog.name === this.connectionSchemaManagerService.currentObjectCatalogId) { + return -1; + } + + if (b.catalog.name === this.connectionSchemaManagerService.currentObjectCatalogId) { + return 1; + } + + return 0; + }); let previousSelected: boolean | null = null; @@ -309,22 +284,24 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap { previousSelected = selected; - items.push(new MenuBaseItem( - { - id: title, - label: title, - tooltip: title, - icon: '/icons/plugin_datasource_context_switch_schema_sm.svg', - }, - { - onSelect: async () => { - await this.connectionSchemaManagerService.selectSchema(title); + items.push( + new MenuBaseItem( + { + id: title, + label: title, + tooltip: title, + icon: '/icons/plugin_datasource_context_switch_schema_sm.svg', }, - }, - { - isDisabled: () => this.connectionSchemaManagerService.currentObjectSchemaId === title, - } - )); + { + onSelect: async () => { + await this.connectionSchemaManagerService.selectSchema(title); + }, + }, + { + isDisabled: () => this.connectionSchemaManagerService.currentObjectSchemaId === title, + }, + ), + ); } for (const catalogData of catalogList) { @@ -342,22 +319,24 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap { previousSelected = selected; if (catalogData.schemaList.length === 0) { - items.push(new MenuBaseItem( - { - id: catalog.name, - label: catalog.name, - tooltip: catalog.name, - icon: '/icons/plugin_datasource_context_switch_database_sm.svg', - }, - { - onSelect: async () => { - await this.connectionSchemaManagerService.selectCatalog(catalog.name!); + items.push( + new MenuBaseItem( + { + id: catalog.name, + label: catalog.name, + tooltip: catalog.name, + icon: '/icons/plugin_datasource_context_switch_database_sm.svg', }, - }, - { - isDisabled: () => this.connectionSchemaManagerService.currentObjectCatalogId === catalog.name, - } - )); + { + onSelect: async () => { + await this.connectionSchemaManagerService.selectCatalog(catalog.name!); + }, + }, + { + isDisabled: () => this.connectionSchemaManagerService.currentObjectCatalogId === catalog.name, + }, + ), + ); } for (const schema of catalogData.schemaList) { @@ -365,30 +344,28 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap { continue; } - const title = NodeManagerUtils.concatSchemaAndCatalog( - catalog.name, - schema.name - ); + const title = NodeManagerUtils.concatSchemaAndCatalog(catalog.name, schema.name); - items.push(new MenuBaseItem( - { - id: title, - label: title, - tooltip: title, - icon: '/icons/plugin_datasource_context_switch_schema_sm.svg', - }, - { - onSelect: async () => { - await this.connectionSchemaManagerService.selectSchema(schema.name!, catalog.name!); + items.push( + new MenuBaseItem( + { + id: title, + label: title, + tooltip: title, + icon: '/icons/plugin_datasource_context_switch_schema_sm.svg', }, - }, - { - isDisabled: () => ( - this.connectionSchemaManagerService.currentObjectSchemaId === schema.name - && this.connectionSchemaManagerService.currentObjectCatalogId === catalog.name - ), - } - )); + { + onSelect: async () => { + await this.connectionSchemaManagerService.selectSchema(schema.name!, catalog.name!); + }, + }, + { + isDisabled: () => + this.connectionSchemaManagerService.currentObjectSchemaId === schema.name && + this.connectionSchemaManagerService.currentObjectCatalogId === catalog.name, + }, + ), + ); } } @@ -397,27 +374,20 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap { }); } - load(): void { } + load(): void {} private isHidden(): boolean { return ( - this.connectionsSettingsService.settings.getValue('disabled') - || this.optionsPanelService.active - || ( - !this.connectionSchemaManagerService.isConnectionChangeable - && !this.connectionSchemaManagerService.currentConnectionKey - ) + this.connectionsSettingsService.settings.getValue('disabled') || + this.optionsPanelService.active || + (!this.connectionSchemaManagerService.isConnectionChangeable && !this.connectionSchemaManagerService.currentConnectionKey) ); } private addTopAppMenuItems() { this.menuService.addCreator({ menus: [MENU_APP_ACTIONS], - getItems: (context, items) => [ - ...items, - MENU_CONNECTION_SELECTOR, - MENU_CONNECTION_DATA_CONTAINER_SELECTOR, - ], + getItems: (context, items) => [...items, MENU_CONNECTION_SELECTOR, MENU_CONNECTION_DATA_CONTAINER_SELECTOR], orderItems: (context, items) => { const extracted = menuExtractItems(items, [MENU_CONNECTION_SELECTOR, MENU_CONNECTION_DATA_CONTAINER_SELECTOR]); diff --git a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSchemaManagerService.ts b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSchemaManagerService.ts index 95825805c6..b44ac7f382 100644 --- a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSchemaManagerService.ts +++ b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSchemaManagerService.ts @@ -5,19 +5,45 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; -import { computed, observable, makeObservable, action, runInAction } from 'mobx'; - -import { ConnectionInfoResource, ConnectionsManagerService, ObjectContainer, DBDriverResource, isConnectionProvider, IConnectionProvider, isConnectionSetter, IConnectionSetter, IStructContainers, Connection, IConnectionInfoParams, serializeConnectionParam, IObjectCatalogProvider, IObjectCatalogSetter, IObjectSchemaProvider, IObjectSchemaSetter, isObjectCatalogProvider, isObjectCatalogSetter, isObjectSchemaProvider, isObjectSchemaSetter } from '@cloudbeaver/core-connections'; +import { + Connection, + ConnectionInfoResource, + ConnectionsManagerService, + DBDriverResource, + IConnectionInfoParams, + IConnectionProvider, + IConnectionSetter, + IObjectCatalogProvider, + IObjectCatalogSetter, + IObjectSchemaProvider, + IObjectSchemaSetter, + isConnectionProvider, + isConnectionSetter, + isObjectCatalogProvider, + isObjectCatalogSetter, + isObjectSchemaProvider, + isObjectSchemaSetter, + IStructContainers, + ObjectContainer, + serializeConnectionParam, +} from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; import { ExtensionUtils, IExtension } from '@cloudbeaver/core-extensions'; -import { type IObjectNavNodeProvider, type IDataContextActiveNode, isObjectNavNodeProvider } from '@cloudbeaver/core-navigation-tree'; -import { IProjectProvider, IProjectSetter, IProjectSetterState, isProjectProvider, isProjectSetter, isProjectSetterState } from '@cloudbeaver/core-projects'; +import { type IDataContextActiveNode, type IObjectNavNodeProvider, isObjectNavNodeProvider } from '@cloudbeaver/core-navigation-tree'; +import { + IProjectProvider, + IProjectSetter, + IProjectSetterState, + isProjectProvider, + isProjectSetter, + isProjectSetterState, +} from '@cloudbeaver/core-projects'; import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; import { ITab, NavigationTabsService } from '@cloudbeaver/plugin-navigation-tabs'; - export interface IConnectionInfo { name?: string; driverIcon?: string; @@ -41,7 +67,6 @@ interface IActiveItem { @injectable() export class ConnectionSchemaManagerService { get activeNavNode(): IDataContextActiveNode | null | undefined { - if (!this.activeItem?.getCurrentNavNode) { return null; } @@ -50,7 +75,6 @@ export class ConnectionSchemaManagerService { } get activeProjectId(): string | null | undefined { - if (!this.activeItem?.getCurrentProjectId) { return null; } @@ -59,7 +83,6 @@ export class ConnectionSchemaManagerService { } get activeConnectionKey(): IConnectionInfoParams | null | undefined { - if (!this.activeItem?.getCurrentConnectionId) { return null; } @@ -123,10 +146,7 @@ export class ConnectionSchemaManagerService { return; } - return this.connectionsManagerService.getObjectContainerById( - this.currentConnectionKey, - this.currentObjectCatalogId - ); + return this.connectionsManagerService.getObjectContainerById(this.currentConnectionKey, this.currentObjectCatalogId); } get currentObjectSchema(): ObjectContainer | undefined { @@ -134,11 +154,7 @@ export class ConnectionSchemaManagerService { return; } - return this.connectionsManagerService.getObjectContainerById( - this.currentConnectionKey, - this.currentObjectCatalogId, - this.currentObjectSchemaId - ); + return this.connectionsManagerService.getObjectContainerById(this.currentConnectionKey, this.currentObjectCatalogId, this.currentObjectSchemaId); } get objectContainerList(): IStructContainers | undefined { @@ -161,17 +177,11 @@ export class ConnectionSchemaManagerService { } get isObjectCatalogChangeable(): boolean { - return ( - !!this.activeItem?.changeCatalogId - && !!this.objectContainerList?.supportsCatalogChange - ); + return !!this.activeItem?.changeCatalogId && !!this.objectContainerList?.supportsCatalogChange; } get isObjectSchemaChangeable(): boolean { - return ( - !!this.activeItem?.changeSchemaId - && !!this.objectContainerList?.supportsSchemaChange - ); + return !!this.activeItem?.changeSchemaId && !!this.objectContainerList?.supportsSchemaChange; } get isChangingProject(): boolean { @@ -220,7 +230,7 @@ export class ConnectionSchemaManagerService { private readonly connectionInfo: ConnectionInfoResource, private readonly connectionsManagerService: ConnectionsManagerService, private readonly dbDriverResource: DBDriverResource, - private readonly notificationService: NotificationService + private readonly notificationService: NotificationService, ) { this.changingProjectId = false; this.changingConnection = false; @@ -231,16 +241,16 @@ export class ConnectionSchemaManagerService { this.pendingSchemaId = null; makeObservable< - ConnectionSchemaManagerService, - 'activeItem' - | 'changingProjectId' - | 'changingConnection' - | 'changingConnectionContainer' - | 'pendingProjectId' - | 'pendingConnectionKey' - | 'pendingCatalogId' - | 'pendingSchemaId' - | 'setExtensions' + ConnectionSchemaManagerService, + | 'activeItem' + | 'changingProjectId' + | 'changingConnection' + | 'changingConnectionContainer' + | 'pendingProjectId' + | 'pendingConnectionKey' + | 'pendingCatalogId' + | 'pendingSchemaId' + | 'setExtensions' >(this, { currentObjectCatalog: computed, currentObjectSchema: computed, @@ -326,7 +336,6 @@ export class ConnectionSchemaManagerService { } try { - runInAction(() => { this.changingConnectionContainer = true; this.pendingCatalogId = catalogId; @@ -399,7 +408,7 @@ export class ConnectionSchemaManagerService { try { await this.dbDriverResource.load(CachedMapAllKey); } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t load database drivers', '', true); + this.notificationService.logException(exception, "Can't load database drivers", '', true); } if (!connection.connected) { @@ -409,27 +418,42 @@ export class ConnectionSchemaManagerService { try { await this.connectionsManagerService.loadObjectContainer(key, catalogId); } catch (exception: any) { - this.notificationService.logException( - exception, - `Can't load objectContainers for ${serializeConnectionParam(key)}@${catalogId}`, - '', - true - ); + this.notificationService.logException(exception, `Can't load objectContainers for ${serializeConnectionParam(key)}@${catalogId}`, '', true); } } private setExtensions(item: IActiveItem, extensions: Array>) { ExtensionUtils.from(extensions) - .on(isObjectNavNodeProvider, extension => { item.getCurrentNavNode = extension; }) - .on(isProjectSetterState, extension => { item.getProjectSetterState = extension; }) - .on(isProjectProvider, extension => { item.getCurrentProjectId = extension; }) - .on(isConnectionProvider, extension => { item.getCurrentConnectionId = extension; }) - .on(isObjectCatalogProvider, extension => { item.getCurrentCatalogId = extension; }) - .on(isObjectSchemaProvider, extension => { item.getCurrentSchemaId = extension; }) + .on(isObjectNavNodeProvider, extension => { + item.getCurrentNavNode = extension; + }) + .on(isProjectSetterState, extension => { + item.getProjectSetterState = extension; + }) + .on(isProjectProvider, extension => { + item.getCurrentProjectId = extension; + }) + .on(isConnectionProvider, extension => { + item.getCurrentConnectionId = extension; + }) + .on(isObjectCatalogProvider, extension => { + item.getCurrentCatalogId = extension; + }) + .on(isObjectSchemaProvider, extension => { + item.getCurrentSchemaId = extension; + }) - .on(isProjectSetter, extension => { item.changeProjectId = extension; }) - .on(isConnectionSetter, extension => { item.changeConnectionId = extension; }) - .on(isObjectCatalogSetter, extension => { item.changeCatalogId = extension; }) - .on(isObjectSchemaSetter, extension => { item.changeSchemaId = extension; }); + .on(isProjectSetter, extension => { + item.changeProjectId = extension; + }) + .on(isConnectionSetter, extension => { + item.changeConnectionId = extension; + }) + .on(isObjectCatalogSetter, extension => { + item.changeCatalogId = extension; + }) + .on(isObjectSchemaSetter, extension => { + item.changeSchemaId = extension; + }); } } diff --git a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSelector/ConnectionIcon.tsx b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSelector/ConnectionIcon.tsx index 51c9a22e55..97f9c78694 100644 --- a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSelector/ConnectionIcon.tsx +++ b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSelector/ConnectionIcon.tsx @@ -5,12 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css, use } from 'reshadow'; import { ConnectionImageWithMask, useResource, useStyles } from '@cloudbeaver/core-blocks'; -import { DBDriverResource, ConnectionInfoResource } from '@cloudbeaver/core-connections'; +import { ConnectionInfoResource, DBDriverResource } from '@cloudbeaver/core-connections'; import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; import type { ComponentStyle } from '@cloudbeaver/core-theming'; @@ -38,19 +37,10 @@ interface Props extends IConnectionSelectorExtraProps { className?: string; } -export const ConnectionIcon: React.FC = observer(function ConnectionIcon({ - connectionKey, - small = true, - style, - className, -}) { +export const ConnectionIcon: React.FC = observer(function ConnectionIcon({ connectionKey, small = true, style, className }) { const styles = useStyles(style, connectionIconStyle); - const connection = useResource( - ConnectionIcon, - ConnectionInfoResource, - connectionKey ?? null - ); + const connection = useResource(ConnectionIcon, ConnectionInfoResource, connectionKey ?? null); const drivers = useResource(ConnectionIcon, DBDriverResource, CachedMapAllKey); @@ -66,7 +56,14 @@ export const ConnectionIcon: React.FC = observer(function ConnectionIcon( return styled(styles)( - - + +
, ); -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSelector/IConnectionSelectorExtraProps.ts b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSelector/IConnectionSelectorExtraProps.ts index 1506ac802f..307694acb7 100644 --- a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSelector/IConnectionSelectorExtraProps.ts +++ b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSelector/IConnectionSelectorExtraProps.ts @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IConnectionInfoParams } from '@cloudbeaver/core-connections'; export interface IConnectionSelectorExtraProps { connectionKey?: IConnectionInfoParams | null; small?: boolean; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/MENU_CONNECTION_DATA_CONTAINER_SELECTOR.ts b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/MENU_CONNECTION_DATA_CONTAINER_SELECTOR.ts index 00b4728984..e6275028c6 100644 --- a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/MENU_CONNECTION_DATA_CONTAINER_SELECTOR.ts +++ b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/MENU_CONNECTION_DATA_CONTAINER_SELECTOR.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; export const MENU_CONNECTION_DATA_CONTAINER_SELECTOR = createMenu('connection-data-container-selector', 'Connection data container selector'); diff --git a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/MENU_CONNECTION_SELECTOR.ts b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/MENU_CONNECTION_SELECTOR.ts index 447bec007c..e7a6479ca5 100644 --- a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/MENU_CONNECTION_SELECTOR.ts +++ b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/MENU_CONNECTION_SELECTOR.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; export const MENU_CONNECTION_SELECTOR = createMenu('connection-selector', 'Connection selector'); diff --git a/webapp/packages/plugin-datasource-context-switch/src/LocaleService.ts b/webapp/packages/plugin-datasource-context-switch/src/LocaleService.ts index 144237a086..e3649a06b4 100644 --- a/webapp/packages/plugin-datasource-context-switch/src/LocaleService.ts +++ b/webapp/packages/plugin-datasource-context-switch/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-datasource-context-switch/src/PluginBootstrap.ts b/webapp/packages/plugin-datasource-context-switch/src/PluginBootstrap.ts index 58ab8b4d15..5cb98d6fdd 100644 --- a/webapp/packages/plugin-datasource-context-switch/src/PluginBootstrap.ts +++ b/webapp/packages/plugin-datasource-context-switch/src/PluginBootstrap.ts @@ -5,17 +5,15 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; - @injectable() export class PluginBootstrap extends Bootstrap { constructor() { super(); } - register(): void | Promise { } + register(): void | Promise {} - load(): void | Promise { } -} \ No newline at end of file + load(): void | Promise {} +} diff --git a/webapp/packages/plugin-datasource-context-switch/src/index.ts b/webapp/packages/plugin-datasource-context-switch/src/index.ts index e82d8d4f6d..b013c543a9 100644 --- a/webapp/packages/plugin-datasource-context-switch/src/index.ts +++ b/webapp/packages/plugin-datasource-context-switch/src/index.ts @@ -1,5 +1,6 @@ -export * from './ConnectionSchemaManager/ConnectionSchemaManagerBootstrap'; -export * from './ConnectionSchemaManager/ConnectionSchemaManagerService'; import { datasourceContextSwitchPluginManifest } from './manifest'; +export * from './ConnectionSchemaManager/ConnectionSchemaManagerBootstrap'; +export * from './ConnectionSchemaManager/ConnectionSchemaManagerService'; + export default datasourceContextSwitchPluginManifest; diff --git a/webapp/packages/plugin-datasource-context-switch/src/manifest.ts b/webapp/packages/plugin-datasource-context-switch/src/manifest.ts index e6f14c5d4f..9ce76d9ff2 100644 --- a/webapp/packages/plugin-datasource-context-switch/src/manifest.ts +++ b/webapp/packages/plugin-datasource-context-switch/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { ConnectionSchemaManagerBootstrap } from './ConnectionSchemaManager/ConnectionSchemaManagerBootstrap'; @@ -13,16 +12,10 @@ import { ConnectionSchemaManagerService } from './ConnectionSchemaManager/Connec import { LocaleService } from './LocaleService'; import { PluginBootstrap } from './PluginBootstrap'; - export const datasourceContextSwitchPluginManifest: PluginManifest = { info: { name: 'Datasource context switch plugin', }, - providers: [ - PluginBootstrap, - ConnectionSchemaManagerService, - ConnectionSchemaManagerBootstrap, - LocaleService, - ], + providers: [PluginBootstrap, ConnectionSchemaManagerService, ConnectionSchemaManagerBootstrap, LocaleService], }; diff --git a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DATA_CONTEXT_DDL_VIEWER_NODE.ts b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DATA_CONTEXT_DDL_VIEWER_NODE.ts index 5d1a1dcceb..c6e5724c41 100644 --- a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DATA_CONTEXT_DDL_VIEWER_NODE.ts +++ b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DATA_CONTEXT_DDL_VIEWER_NODE.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createDataContext } from '@cloudbeaver/core-view'; export const DATA_CONTEXT_DDL_VIEWER_NODE = createDataContext('ddl-node'); diff --git a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DATA_CONTEXT_DDL_VIEWER_VALUE.ts b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DATA_CONTEXT_DDL_VIEWER_VALUE.ts index 762c3104c9..b9fa3043e1 100644 --- a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DATA_CONTEXT_DDL_VIEWER_VALUE.ts +++ b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DATA_CONTEXT_DDL_VIEWER_VALUE.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createDataContext } from '@cloudbeaver/core-view'; export const DATA_CONTEXT_DDL_VIEWER_VALUE = createDataContext('ddl-value'); diff --git a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DDLViewerFooterService.ts b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DDLViewerFooterService.ts index d875c3b3c1..ced80f0a16 100644 --- a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DDLViewerFooterService.ts +++ b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DDLViewerFooterService.ts @@ -5,12 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { ConnectionInfoResource, createConnectionParam } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { NavNodeManagerService } from '@cloudbeaver/core-navigation-tree'; import { download, generateFileName } from '@cloudbeaver/core-utils'; -import { ActionService, ACTION_SAVE, DATA_CONTEXT_MENU, MenuService } from '@cloudbeaver/core-view'; +import { ACTION_SAVE, ActionService, DATA_CONTEXT_MENU, MenuService } from '@cloudbeaver/core-view'; import { LocalStorageSqlDataSource } from '@cloudbeaver/plugin-sql-editor'; import { ACTION_SQL_EDITOR_OPEN, SqlEditorNavigatorService } from '@cloudbeaver/plugin-sql-editor-navigation-tab'; @@ -25,8 +24,8 @@ export class DDLViewerFooterService { private readonly actionsService: ActionService, private readonly menuService: MenuService, private readonly sqlEditorNavigatorService: SqlEditorNavigatorService, - private readonly connectionInfoResource: ConnectionInfoResource - ) { } + private readonly connectionInfoResource: ConnectionInfoResource, + ) {} register(): void { this.actionsService.addHandler({ @@ -103,11 +102,7 @@ export class DDLViewerFooterService { this.menuService.addCreator({ isApplicable: context => context.get(DATA_CONTEXT_MENU) === MENU_DDL_VIEWER_FOOTER, - getItems: (context, items) => [ - ...items, - ACTION_SAVE, - ACTION_SQL_EDITOR_OPEN, - ], + getItems: (context, items) => [...items, ACTION_SAVE, ACTION_SQL_EDITOR_OPEN], }); } } diff --git a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DDLViewerTab.tsx b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DDLViewerTab.tsx index 0dd5c9fe3c..3a623fcc08 100644 --- a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DDLViewerTab.tsx +++ b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DDLViewerTab.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; @@ -15,16 +14,13 @@ import type { NavNodeTransformViewComponent } from '@cloudbeaver/plugin-navigati import { NAV_NODE_DDL_ID } from '../NAV_NODE_DDL_ID'; -export const DDLViewerTab: NavNodeTransformViewComponent = observer(function DDLViewerTab({ - folderId, - style, -}) { +export const DDLViewerTab: NavNodeTransformViewComponent = observer(function DDLViewerTab({ folderId, style }) { const title = folderId.startsWith(NAV_NODE_DDL_ID) ? 'DDL' : 'Body'; return styled(useStyles(style))( {title} - + , ); }); diff --git a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DDLViewerTabPanel.tsx b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DDLViewerTabPanel.tsx index 2ff66a6834..d483bc033e 100644 --- a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DDLViewerTabPanel.tsx +++ b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DDLViewerTabPanel.tsx @@ -5,13 +5,17 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; import { useResource, useStyles } from '@cloudbeaver/core-blocks'; -import { ConnectionDialectResource, ConnectionInfoActiveProjectKey, ConnectionInfoResource, createConnectionParam } from '@cloudbeaver/core-connections'; -import { MenuBar, MENU_BAR_DEFAULT_STYLES } from '@cloudbeaver/core-ui'; +import { + ConnectionDialectResource, + ConnectionInfoActiveProjectKey, + ConnectionInfoResource, + createConnectionParam, +} from '@cloudbeaver/core-connections'; +import { MENU_BAR_DEFAULT_STYLES, MenuBar } from '@cloudbeaver/core-ui'; import { useMenu } from '@cloudbeaver/core-view'; import type { NavNodeTransformViewComponent } from '@cloudbeaver/plugin-navigation-tree'; import { SQLCodeEditorLoader, useSqlDialectExtension } from '@cloudbeaver/plugin-sql-editor-new'; @@ -39,12 +43,8 @@ export const DDLViewerTabPanel: NavNodeTransformViewComponent = observer(functio return styled(style)( - + - + , ); }); diff --git a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DdlResource.ts b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DdlResource.ts index d9f5a08ff9..a4cb20baae 100644 --- a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DdlResource.ts +++ b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/DdlResource.ts @@ -5,17 +5,13 @@ * 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 { NavNodeInfoResource } from '@cloudbeaver/core-navigation-tree'; -import { CachedMapResource, ResourceKey, ResourceKeyUtils, isResourceAlias, GraphQLService } from '@cloudbeaver/core-sdk'; +import { CachedMapResource, GraphQLService, isResourceAlias, ResourceKey, ResourceKeyUtils } from '@cloudbeaver/core-sdk'; @injectable() export class DdlResource extends CachedMapResource { - constructor( - private readonly graphQLService: GraphQLService, - private readonly navNodeInfoResource: NavNodeInfoResource, - ) { + constructor(private readonly graphQLService: GraphQLService, private readonly navNodeInfoResource: NavNodeInfoResource) { super(); this.navNodeInfoResource.outdateResource(this); diff --git a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/MENU_DDL_VIEWER_FOOTER.ts b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/MENU_DDL_VIEWER_FOOTER.ts index 1839e6ef9d..4a3100bd3b 100644 --- a/webapp/packages/plugin-ddl-viewer/src/DdlViewer/MENU_DDL_VIEWER_FOOTER.ts +++ b/webapp/packages/plugin-ddl-viewer/src/DdlViewer/MENU_DDL_VIEWER_FOOTER.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; export const MENU_DDL_VIEWER_FOOTER = createMenu('ddl-viewer-footer', 'DDL viewer footer menu'); diff --git a/webapp/packages/plugin-ddl-viewer/src/DdlViewerBootstrap.ts b/webapp/packages/plugin-ddl-viewer/src/DdlViewerBootstrap.ts index 5e54521125..3308dd09e3 100644 --- a/webapp/packages/plugin-ddl-viewer/src/DdlViewerBootstrap.ts +++ b/webapp/packages/plugin-ddl-viewer/src/DdlViewerBootstrap.ts @@ -5,9 +5,8 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; -import { NavNodeInfoResource, EObjectFeature } from '@cloudbeaver/core-navigation-tree'; +import { EObjectFeature, NavNodeInfoResource } from '@cloudbeaver/core-navigation-tree'; import { NavNodeViewService } from '@cloudbeaver/plugin-navigation-tree'; import { DDLViewerFooterService } from './DdlViewer/DDLViewerFooterService'; @@ -22,7 +21,7 @@ export class DdlViewerBootstrap extends Bootstrap { constructor( private readonly navNodeViewService: NavNodeViewService, private readonly navNodeInfoResource: NavNodeInfoResource, - private readonly ddlViewerFooterService: DDLViewerFooterService + private readonly ddlViewerFooterService: DDLViewerFooterService, ) { super(); } @@ -59,12 +58,12 @@ export class DdlViewerBootstrap extends Bootstrap { ids.push(NAV_NODE_EXTENDED_DDL_ID); } - return [...children || [], ...ids]; + return [...(children || []), ...ids]; }, }); this.ddlViewerFooterService.register(); } - load(): void { } + load(): void {} } diff --git a/webapp/packages/plugin-ddl-viewer/src/ExtendedDDLViewer/ExtendedDDLResource.ts b/webapp/packages/plugin-ddl-viewer/src/ExtendedDDLViewer/ExtendedDDLResource.ts index 67b63af20b..aec7f9b57e 100644 --- a/webapp/packages/plugin-ddl-viewer/src/ExtendedDDLViewer/ExtendedDDLResource.ts +++ b/webapp/packages/plugin-ddl-viewer/src/ExtendedDDLViewer/ExtendedDDLResource.ts @@ -5,17 +5,13 @@ * 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 { NavNodeInfoResource } from '@cloudbeaver/core-navigation-tree'; -import { GraphQLService, CachedMapResource, ResourceKey, ResourceKeyUtils, isResourceAlias } from '@cloudbeaver/core-sdk'; +import { CachedMapResource, GraphQLService, isResourceAlias, ResourceKey, ResourceKeyUtils } from '@cloudbeaver/core-sdk'; @injectable() export class ExtendedDDLResource extends CachedMapResource { - constructor( - private readonly graphQLService: GraphQLService, - private readonly navNodeInfoResource: NavNodeInfoResource - ) { + constructor(private readonly graphQLService: GraphQLService, private readonly navNodeInfoResource: NavNodeInfoResource) { super(); this.navNodeInfoResource.outdateResource(this); diff --git a/webapp/packages/plugin-ddl-viewer/src/ExtendedDDLViewer/ExtendedDDLViewerTabPanel.tsx b/webapp/packages/plugin-ddl-viewer/src/ExtendedDDLViewer/ExtendedDDLViewerTabPanel.tsx index 951966f8c6..191561d84c 100644 --- a/webapp/packages/plugin-ddl-viewer/src/ExtendedDDLViewer/ExtendedDDLViewerTabPanel.tsx +++ b/webapp/packages/plugin-ddl-viewer/src/ExtendedDDLViewer/ExtendedDDLViewerTabPanel.tsx @@ -5,13 +5,17 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; import { useResource, useStyles } from '@cloudbeaver/core-blocks'; -import { ConnectionDialectResource, ConnectionInfoActiveProjectKey, ConnectionInfoResource, createConnectionParam } from '@cloudbeaver/core-connections'; -import { MenuBar, MENU_BAR_DEFAULT_STYLES } from '@cloudbeaver/core-ui'; +import { + ConnectionDialectResource, + ConnectionInfoActiveProjectKey, + ConnectionInfoResource, + createConnectionParam, +} from '@cloudbeaver/core-connections'; +import { MENU_BAR_DEFAULT_STYLES, MenuBar } from '@cloudbeaver/core-ui'; import { useMenu } from '@cloudbeaver/core-view'; import type { NavNodeTransformViewComponent } from '@cloudbeaver/plugin-navigation-tree'; import { SQLCodeEditorLoader, useSqlDialectExtension } from '@cloudbeaver/plugin-sql-editor-new'; @@ -22,19 +26,13 @@ import { MENU_DDL_VIEWER_FOOTER } from '../DdlViewer/MENU_DDL_VIEWER_FOOTER'; import { TAB_PANEL_STYLES } from '../TAB_PANEL_STYLES'; import { ExtendedDDLResource } from './ExtendedDDLResource'; -export const ExtendedDDLViewerTabPanel: NavNodeTransformViewComponent = observer(function ExtendedDDLViewerTabPanel({ - nodeId, folderId, -}) { +export const ExtendedDDLViewerTabPanel: NavNodeTransformViewComponent = observer(function ExtendedDDLViewerTabPanel({ nodeId, folderId }) { const style = useStyles(TAB_PANEL_STYLES); const menu = useMenu({ menu: MENU_DDL_VIEWER_FOOTER }); const extendedDDLResource = useResource(ExtendedDDLViewerTabPanel, ExtendedDDLResource, nodeId); - const connectionInfoResource = useResource( - ExtendedDDLViewerTabPanel, - ConnectionInfoResource, - ConnectionInfoActiveProjectKey - ); + const connectionInfoResource = useResource(ExtendedDDLViewerTabPanel, ConnectionInfoResource, ConnectionInfoActiveProjectKey); const connection = connectionInfoResource.resource.getConnectionForNode(nodeId); const connectionParam = connection ? createConnectionParam(connection) : null; const connectionDialectResource = useResource(ExtendedDDLViewerTabPanel, ConnectionDialectResource, connectionParam); @@ -45,12 +43,8 @@ export const ExtendedDDLViewerTabPanel: NavNodeTransformViewComponent = observer return styled(style)( - + - + , ); }); diff --git a/webapp/packages/plugin-ddl-viewer/src/NAV_NODE_DDL_ID.ts b/webapp/packages/plugin-ddl-viewer/src/NAV_NODE_DDL_ID.ts index c3ac54b1d4..9aa910ef9c 100644 --- a/webapp/packages/plugin-ddl-viewer/src/NAV_NODE_DDL_ID.ts +++ b/webapp/packages/plugin-ddl-viewer/src/NAV_NODE_DDL_ID.ts @@ -6,4 +6,4 @@ * you may not use this file except in compliance with the License. */ -export const NAV_NODE_DDL_ID = 'object-viewer://ddl'; \ No newline at end of file +export const NAV_NODE_DDL_ID = 'object-viewer://ddl'; diff --git a/webapp/packages/plugin-ddl-viewer/src/NAV_NODE_EXTENDED_DDL_ID.ts b/webapp/packages/plugin-ddl-viewer/src/NAV_NODE_EXTENDED_DDL_ID.ts index d1ef7c23fa..911f01d731 100644 --- a/webapp/packages/plugin-ddl-viewer/src/NAV_NODE_EXTENDED_DDL_ID.ts +++ b/webapp/packages/plugin-ddl-viewer/src/NAV_NODE_EXTENDED_DDL_ID.ts @@ -6,4 +6,4 @@ * you may not use this file except in compliance with the License. */ -export const NAV_NODE_EXTENDED_DDL_ID = 'object-viewer://extended-ddl'; \ No newline at end of file +export const NAV_NODE_EXTENDED_DDL_ID = 'object-viewer://extended-ddl'; diff --git a/webapp/packages/plugin-ddl-viewer/src/TAB_PANEL_STYLES.ts b/webapp/packages/plugin-ddl-viewer/src/TAB_PANEL_STYLES.ts index 4d08641afb..c376211ae2 100644 --- a/webapp/packages/plugin-ddl-viewer/src/TAB_PANEL_STYLES.ts +++ b/webapp/packages/plugin-ddl-viewer/src/TAB_PANEL_STYLES.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { css } from 'reshadow'; export const TAB_PANEL_STYLES = css` diff --git a/webapp/packages/plugin-ddl-viewer/src/manifest.ts b/webapp/packages/plugin-ddl-viewer/src/manifest.ts index 1c63ed9fc7..9ed9f2be61 100644 --- a/webapp/packages/plugin-ddl-viewer/src/manifest.ts +++ b/webapp/packages/plugin-ddl-viewer/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { DdlResource } from './DdlViewer/DdlResource'; @@ -18,10 +17,5 @@ export const manifest: PluginManifest = { name: 'DDL Viewer Plugin', }, - providers: [ - DdlViewerBootstrap, - DDLViewerFooterService, - ExtendedDDLResource, - DdlResource, - ], + providers: [DdlViewerBootstrap, DDLViewerFooterService, ExtendedDDLResource, DdlResource], }; diff --git a/webapp/packages/plugin-devtools/src/ContextMenu/DATA_CONTEXT_MENU_SEARCH.ts b/webapp/packages/plugin-devtools/src/ContextMenu/DATA_CONTEXT_MENU_SEARCH.ts index 4ce283230f..f85befec58 100644 --- a/webapp/packages/plugin-devtools/src/ContextMenu/DATA_CONTEXT_MENU_SEARCH.ts +++ b/webapp/packages/plugin-devtools/src/ContextMenu/DATA_CONTEXT_MENU_SEARCH.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createDataContext } from '@cloudbeaver/core-view'; export const DATA_CONTEXT_MENU_SEARCH = createDataContext('menu-local', () => ''); diff --git a/webapp/packages/plugin-devtools/src/ContextMenu/SearchResourceMenuItem.ts b/webapp/packages/plugin-devtools/src/ContextMenu/SearchResourceMenuItem.ts index 1d2bf706ee..c16c751b71 100644 --- a/webapp/packages/plugin-devtools/src/ContextMenu/SearchResourceMenuItem.ts +++ b/webapp/packages/plugin-devtools/src/ContextMenu/SearchResourceMenuItem.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IContextMenuItemProps } from '@cloudbeaver/core-ui'; import { MenuCustomItem } from '@cloudbeaver/core-view'; @@ -18,4 +17,4 @@ export class SearchResourceMenuItem extends MenuCustomItem SearchResourceMenuItemComponent, }); } -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-devtools/src/ContextMenu/SearchResourceMenuItemComponent.tsx b/webapp/packages/plugin-devtools/src/ContextMenu/SearchResourceMenuItemComponent.tsx index bf3af89f65..d2518955ad 100644 --- a/webapp/packages/plugin-devtools/src/ContextMenu/SearchResourceMenuItemComponent.tsx +++ b/webapp/packages/plugin-devtools/src/ContextMenu/SearchResourceMenuItemComponent.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; @@ -37,12 +36,12 @@ export const SearchResourceMenuItemComponent: ICustomMenuItemComponent handleChange(event.target.value)} /> - + , ); -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-devtools/src/DevToolsService.ts b/webapp/packages/plugin-devtools/src/DevToolsService.ts index ca7b94ff97..9d0f33e5cf 100644 --- a/webapp/packages/plugin-devtools/src/DevToolsService.ts +++ b/webapp/packages/plugin-devtools/src/DevToolsService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { makeObservable, observable } from 'mobx'; import { injectable } from '@cloudbeaver/core-di'; @@ -31,10 +30,7 @@ export class DevToolsService { private readonly settings: IDevToolsSettings; - constructor( - private readonly serverConfigResource: ServerConfigResource, - private readonly autoSaveService: LocalStorageSaveService, - ) { + constructor(private readonly serverConfigResource: ServerConfigResource, private readonly autoSaveService: LocalStorageSaveService) { this.settings = getDefaultDevToolsSettings(); makeObservable(this, { @@ -68,4 +64,4 @@ function getDefaultDevToolsSettings(): IDevToolsSettings { enabled: false, distributed: false, }; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-devtools/src/PluginBootstrap.ts b/webapp/packages/plugin-devtools/src/PluginBootstrap.ts index 0767c0f444..c0fd979d96 100644 --- a/webapp/packages/plugin-devtools/src/PluginBootstrap.ts +++ b/webapp/packages/plugin-devtools/src/PluginBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { EAdminPermission } from '@cloudbeaver/core-authentication'; import { App, Bootstrap, DIService, injectable, IServiceConstructor } from '@cloudbeaver/core-di'; import { PermissionsService } from '@cloudbeaver/core-root'; @@ -35,7 +34,7 @@ export class PluginBootstrap extends Bootstrap { private readonly menuService: MenuService, private readonly actionService: ActionService, private readonly devToolsService: DevToolsService, - private readonly permissionsService: PermissionsService + private readonly permissionsService: PermissionsService, ) { super(); } @@ -48,13 +47,9 @@ export class PluginBootstrap extends Bootstrap { } return context.get(DATA_CONTEXT_MENU) === TOP_NAV_BAR_SETTINGS_MENU; }, - getItems: (context, items) => [ - ACTION_DEVTOOLS, - ...items, - ], + getItems: (context, items) => [ACTION_DEVTOOLS, ...items], }); - // this.actionService.addHandler({ // id: 'devtools', // isActionApplicable: (context, action) => [ @@ -87,10 +82,7 @@ export class PluginBootstrap extends Bootstrap { } return context.get(DATA_CONTEXT_MENU) === MENU_USER_PROFILE; }, - getItems: (context, items) => [ - MENU_DEVTOOLS, - ...items, - ], + getItems: (context, items) => [MENU_DEVTOOLS, ...items], }); this.menuService.addCreator({ @@ -99,21 +91,13 @@ export class PluginBootstrap extends Bootstrap { const search = context.tryGet(DATA_CONTEXT_MENU_SEARCH); if (search) { - return [ new SearchResourceMenuItem(), - ...this.getResources(this.app - .getServices() - .filter(service => service.name.toLocaleLowerCase().includes(search.toLocaleLowerCase()))), + ...this.getResources(this.app.getServices().filter(service => service.name.toLocaleLowerCase().includes(search.toLocaleLowerCase()))), ]; } - return [ - new SearchResourceMenuItem(), - ACTION_DEVTOOLS_MODE_DISTRIBUTED, - MENU_PLUGINS, - ...items, - ]; + return [new SearchResourceMenuItem(), ACTION_DEVTOOLS_MODE_DISTRIBUTED, MENU_PLUGINS, ...items]; }, }); @@ -150,17 +134,11 @@ export class PluginBootstrap extends Bootstrap { return false; }, - getItems: (_, items) => [ - MENU_RESOURCES, - ...items, - ], + getItems: (_, items) => [MENU_RESOURCES, ...items], }); this.menuService.addCreator({ - isApplicable: context => ( - context.get(DATA_CONTEXT_MENU) === MENU_RESOURCES - && context.has(DATA_CONTEXT_SUBMENU_ITEM) - ), + isApplicable: context => context.get(DATA_CONTEXT_MENU) === MENU_RESOURCES && context.has(DATA_CONTEXT_SUBMENU_ITEM), getItems: (context, items) => { const item = context.find(DATA_CONTEXT_SUBMENU_ITEM, item => item instanceof PluginSubMenuItem); @@ -168,26 +146,19 @@ export class PluginBootstrap extends Bootstrap { return items; } - const plugin = this.app - .getPlugins() - .find(plugin => plugin.info.name === item.id); + const plugin = this.app.getPlugins().find(plugin => plugin.info.name === item.id); if (!plugin) { return items; } - return [ - ...this.getResources(plugin.providers), - ...items, - ]; + return [...this.getResources(plugin.providers), ...items]; }, }); this.menuService.addCreator({ - isApplicable: context => ( - context.get(DATA_CONTEXT_MENU) === MENU_RESOURCE - && context.get(DATA_CONTEXT_SUBMENU_ITEM) instanceof ResourceSubMenuItem - ), + isApplicable: context => + context.get(DATA_CONTEXT_MENU) === MENU_RESOURCE && context.get(DATA_CONTEXT_SUBMENU_ITEM) instanceof ResourceSubMenuItem, getItems: (context, items) => { const item = context.get(DATA_CONTEXT_SUBMENU_ITEM) as ResourceSubMenuItem; @@ -200,13 +171,10 @@ export class PluginBootstrap extends Bootstrap { }, { onSelect: () => { - const instance = this.diService.serviceInjector - .getServiceByClass>( - item.resource - ); + const instance = this.diService.serviceInjector.getServiceByClass>(item.resource); instance.markOutdated(undefined); }, - } + }, ), ...items, ]; @@ -214,8 +182,7 @@ export class PluginBootstrap extends Bootstrap { }); } - load(): void | Promise { - } + load(): void | Promise {} private getResources(providers: IServiceConstructor[]): ResourceSubMenuItem[] { return providers @@ -223,4 +190,4 @@ export class PluginBootstrap extends Bootstrap { .sort((a, b) => a.name.localeCompare(b.name)) .map(resource => new ResourceSubMenuItem(resource)); } -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-devtools/src/actions/ACTION_DEVTOOLS.ts b/webapp/packages/plugin-devtools/src/actions/ACTION_DEVTOOLS.ts index 63a724b219..59ed47c79a 100644 --- a/webapp/packages/plugin-devtools/src/actions/ACTION_DEVTOOLS.ts +++ b/webapp/packages/plugin-devtools/src/actions/ACTION_DEVTOOLS.ts @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; export const ACTION_DEVTOOLS = createAction('devtools', { type: 'checkbox', label: 'DevTools', tooltip: 'Show DevTools menu', -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-devtools/src/actions/ACTION_DEVTOOLS_MODE_DISTRIBUTED.ts b/webapp/packages/plugin-devtools/src/actions/ACTION_DEVTOOLS_MODE_DISTRIBUTED.ts index ddd4317c8c..d8083d44e7 100644 --- a/webapp/packages/plugin-devtools/src/actions/ACTION_DEVTOOLS_MODE_DISTRIBUTED.ts +++ b/webapp/packages/plugin-devtools/src/actions/ACTION_DEVTOOLS_MODE_DISTRIBUTED.ts @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; export const ACTION_DEVTOOLS_MODE_DISTRIBUTED = createAction('devtools-mode-distributed', { type: 'checkbox', label: 'Distributed mode', tooltip: 'Enable distributed mode', -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-devtools/src/index.ts b/webapp/packages/plugin-devtools/src/index.ts index 6326667c9f..fd325378da 100644 --- a/webapp/packages/plugin-devtools/src/index.ts +++ b/webapp/packages/plugin-devtools/src/index.ts @@ -3,4 +3,4 @@ import { devToolsPlugin } from './manifest'; export { devToolsPlugin }; export default devToolsPlugin; -export * from './DevToolsService'; \ No newline at end of file +export * from './DevToolsService'; diff --git a/webapp/packages/plugin-devtools/src/manifest.ts b/webapp/packages/plugin-devtools/src/manifest.ts index 29733b2da1..8c8f433ec1 100644 --- a/webapp/packages/plugin-devtools/src/manifest.ts +++ b/webapp/packages/plugin-devtools/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { DevToolsService } from './DevToolsService'; @@ -15,8 +14,5 @@ export const devToolsPlugin: PluginManifest = { info: { name: 'DevTools plugin', }, - providers: [ - PluginBootstrap, - DevToolsService, - ], -}; \ No newline at end of file + providers: [PluginBootstrap, DevToolsService], +}; diff --git a/webapp/packages/plugin-devtools/src/menu/MENU_DEVTOOLS.ts b/webapp/packages/plugin-devtools/src/menu/MENU_DEVTOOLS.ts index 9a30d3c18a..d933a40386 100644 --- a/webapp/packages/plugin-devtools/src/menu/MENU_DEVTOOLS.ts +++ b/webapp/packages/plugin-devtools/src/menu/MENU_DEVTOOLS.ts @@ -5,10 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; -export const MENU_DEVTOOLS = createMenu( - 'devtools', - 'DevTools' -); +export const MENU_DEVTOOLS = createMenu('devtools', 'DevTools'); diff --git a/webapp/packages/plugin-devtools/src/menu/MENU_PLUGIN.ts b/webapp/packages/plugin-devtools/src/menu/MENU_PLUGIN.ts index 8e97d766d1..9014e075ca 100644 --- a/webapp/packages/plugin-devtools/src/menu/MENU_PLUGIN.ts +++ b/webapp/packages/plugin-devtools/src/menu/MENU_PLUGIN.ts @@ -5,10 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; -export const MENU_PLUGIN = createMenu( - 'plugin', - 'Plugin' -); +export const MENU_PLUGIN = createMenu('plugin', 'Plugin'); diff --git a/webapp/packages/plugin-devtools/src/menu/MENU_PLUGINS.ts b/webapp/packages/plugin-devtools/src/menu/MENU_PLUGINS.ts index 5799b2ed94..ed63a4c876 100644 --- a/webapp/packages/plugin-devtools/src/menu/MENU_PLUGINS.ts +++ b/webapp/packages/plugin-devtools/src/menu/MENU_PLUGINS.ts @@ -5,10 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; -export const MENU_PLUGINS = createMenu( - 'plugins', - 'Plugins' -); +export const MENU_PLUGINS = createMenu('plugins', 'Plugins'); diff --git a/webapp/packages/plugin-devtools/src/menu/MENU_RESOURCE.ts b/webapp/packages/plugin-devtools/src/menu/MENU_RESOURCE.ts index 368ad30a43..4a95db6cde 100644 --- a/webapp/packages/plugin-devtools/src/menu/MENU_RESOURCE.ts +++ b/webapp/packages/plugin-devtools/src/menu/MENU_RESOURCE.ts @@ -5,12 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; -export const MENU_RESOURCE = createMenu( - 'resource', - 'Resource', - undefined, - 'Resource actions' -); +export const MENU_RESOURCE = createMenu('resource', 'Resource', undefined, 'Resource actions'); diff --git a/webapp/packages/plugin-devtools/src/menu/MENU_RESOURCES.ts b/webapp/packages/plugin-devtools/src/menu/MENU_RESOURCES.ts index 864540dbcf..5dba7c317d 100644 --- a/webapp/packages/plugin-devtools/src/menu/MENU_RESOURCES.ts +++ b/webapp/packages/plugin-devtools/src/menu/MENU_RESOURCES.ts @@ -5,12 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; -export const MENU_RESOURCES = createMenu( - 'resources-list', - 'Resources', - undefined, - 'List of registered resources' -); +export const MENU_RESOURCES = createMenu('resources-list', 'Resources', undefined, 'List of registered resources'); diff --git a/webapp/packages/plugin-devtools/src/menu/PluginSubMenuItem.ts b/webapp/packages/plugin-devtools/src/menu/PluginSubMenuItem.ts index c9c391e096..5027ff9bb7 100644 --- a/webapp/packages/plugin-devtools/src/menu/PluginSubMenuItem.ts +++ b/webapp/packages/plugin-devtools/src/menu/PluginSubMenuItem.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { MenuSubMenuItem } from '@cloudbeaver/core-view'; @@ -23,4 +22,4 @@ export class PluginSubMenuItem extends MenuSubMenuItem { id: plugin.info.name, }); } -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-devtools/src/menu/ResourceSubMenuItem.ts b/webapp/packages/plugin-devtools/src/menu/ResourceSubMenuItem.ts index c71fdf4f17..44f7b6482a 100644 --- a/webapp/packages/plugin-devtools/src/menu/ResourceSubMenuItem.ts +++ b/webapp/packages/plugin-devtools/src/menu/ResourceSubMenuItem.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { IServiceConstructor } from '@cloudbeaver/core-di'; import { MenuSubMenuItem } from '@cloudbeaver/core-view'; @@ -23,4 +22,4 @@ export class ResourceSubMenuItem extends MenuSubMenuItem { id: resource.name, }); } -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-gis-viewer/src/CrsInput.tsx b/webapp/packages/plugin-gis-viewer/src/CrsInput.tsx index d3e4836764..9ea822cff5 100644 --- a/webapp/packages/plugin-gis-viewer/src/CrsInput.tsx +++ b/webapp/packages/plugin-gis-viewer/src/CrsInput.tsx @@ -28,23 +28,13 @@ interface Props { onChange: (value: CrsKey) => void; } -const items: CrsKey[] = [ - 'Simple', - 'EPSG3395', - 'EPSG3857', - 'EPSG4326', - 'EPSG900913', -]; +const items: CrsKey[] = ['Simple', 'EPSG3395', 'EPSG3857', 'EPSG4326', 'EPSG900913']; export function CrsInput(props: Props) { return styled(styles)( - - + + , ); -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-gis-viewer/src/GISValuePresentation.tsx b/webapp/packages/plugin-gis-viewer/src/GISValuePresentation.tsx index 9d70a408be..fb9528ff4b 100644 --- a/webapp/packages/plugin-gis-viewer/src/GISValuePresentation.tsx +++ b/webapp/packages/plugin-gis-viewer/src/GISValuePresentation.tsx @@ -11,10 +11,17 @@ import styled, { css } from 'reshadow'; import wellknown from 'wellknown'; import { TextPlaceholder, useTranslate } from '@cloudbeaver/core-blocks'; -import { IDatabaseResultSet, ResultSetSelectAction, IResultSetElementKey, IDatabaseDataModel, ResultSetViewAction, ResultSetDataKeysUtils } from '@cloudbeaver/plugin-data-viewer'; +import { + IDatabaseDataModel, + IDatabaseResultSet, + IResultSetElementKey, + ResultSetDataKeysUtils, + ResultSetSelectAction, + ResultSetViewAction, +} from '@cloudbeaver/plugin-data-viewer'; import { CrsInput } from './CrsInput'; -import { IGeoJSONFeature, IAssociatedValue, LeafletMap, CrsKey } from './LeafletMap'; +import { CrsKey, IAssociatedValue, IGeoJSONFeature, LeafletMap } from './LeafletMap'; import { ResultSetGISAction } from './ResultSetGISAction'; function getCrsKey(feature?: IGeoJSONFeature): CrsKey { @@ -56,10 +63,7 @@ interface Props { resultIndex: number; } -export const GISValuePresentation = observer(function GISValuePresentation({ - model, - resultIndex, -}) { +export const GISValuePresentation = observer(function GISValuePresentation({ model, resultIndex }) { const translate = useTranslate(); const selection = model.source.getAction(resultIndex, ResultSetSelectAction); @@ -99,28 +103,30 @@ export const GISValuePresentation = observer(function GISValuePresentatio return result; }, [selectedCells, gis]); - const getAssociatedValues = useCallback((cell: IResultSetElementKey): IAssociatedValue[] => { - const values: IAssociatedValue[] = []; + const getAssociatedValues = useCallback( + (cell: IResultSetElementKey): IAssociatedValue[] => { + const values: IAssociatedValue[] = []; - for (const column of view.columnKeys) { - if (ResultSetDataKeysUtils.isEqual(column, cell.column)) { - continue; + for (const column of view.columnKeys) { + if (ResultSetDataKeysUtils.isEqual(column, cell.column)) { + continue; + } + + const value = view.getCellValue({ ...cell, column }); + const columnInfo = view.getColumn(column); + + if (value && columnInfo?.name) { + values.push({ + key: columnInfo.name, + value, + }); + } } - const value = view.getCellValue({ ...cell, column }); - const columnInfo = view.getColumn(column); - - if (value && columnInfo?.name) { - values.push({ - key: columnInfo.name, - value, - }); - } - } - - return values; - }, [view]); - + return values; + }, + [view], + ); const defaultCrsKey = getCrsKey(parsedGISData[0]); const [crsKey, setCrsKey] = useState(defaultCrsKey); @@ -135,11 +141,8 @@ export const GISValuePresentation = observer(function GISValuePresentatio - + - + , ); }); diff --git a/webapp/packages/plugin-gis-viewer/src/GISViewer.tsx b/webapp/packages/plugin-gis-viewer/src/GISViewer.tsx index 243627080c..31c4e9f3f3 100644 --- a/webapp/packages/plugin-gis-viewer/src/GISViewer.tsx +++ b/webapp/packages/plugin-gis-viewer/src/GISViewer.tsx @@ -5,14 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { TabContainerPanelComponent } from '@cloudbeaver/core-ui'; -import type { IDataValuePanelProps, IDatabaseResultSet } from '@cloudbeaver/plugin-data-viewer'; +import type { IDatabaseResultSet, IDataValuePanelProps } from '@cloudbeaver/plugin-data-viewer'; import { GISValuePresentation } from './GISValuePresentation'; export const GISViewer: TabContainerPanelComponent> = function GISViewer({ model, resultIndex }) { - return ( - - ); + return ; }; diff --git a/webapp/packages/plugin-gis-viewer/src/GISViewerBootstrap.ts b/webapp/packages/plugin-gis-viewer/src/GISViewerBootstrap.ts index 4af0c3e4f7..f67bdf60d2 100644 --- a/webapp/packages/plugin-gis-viewer/src/GISViewerBootstrap.ts +++ b/webapp/packages/plugin-gis-viewer/src/GISViewerBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { lazy } from 'react'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; @@ -55,5 +54,5 @@ export class GISViewerBootstrap extends Bootstrap { }); } - load(): void { } + load(): void {} } diff --git a/webapp/packages/plugin-gis-viewer/src/IDatabaseDataGISAction.ts b/webapp/packages/plugin-gis-viewer/src/IDatabaseDataGISAction.ts index 83261f5c8f..a7cd711f43 100644 --- a/webapp/packages/plugin-gis-viewer/src/IDatabaseDataGISAction.ts +++ b/webapp/packages/plugin-gis-viewer/src/IDatabaseDataGISAction.ts @@ -5,13 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - -import type { IDatabaseDataResult, IDatabaseDataAction, IResultSetElementKey } from '@cloudbeaver/plugin-data-viewer'; +import type { IDatabaseDataAction, IDatabaseDataResult, IResultSetElementKey } from '@cloudbeaver/plugin-data-viewer'; import type { IGISType } from './ResultSetGISAction'; -export interface IDatabaseDataGISAction - extends IDatabaseDataAction { +export interface IDatabaseDataGISAction extends IDatabaseDataAction { getGISDataFor: (selectedCells: IResultSetElementKey[]) => IResultSetElementKey[]; getCellValue: (cell: IResultSetElementKey) => IGISType | undefined; isGISFormat: (cell: IResultSetElementKey) => boolean; diff --git a/webapp/packages/plugin-gis-viewer/src/LeafletMap.tsx b/webapp/packages/plugin-gis-viewer/src/LeafletMap.tsx index 2286ed3fe4..38fd93e9c9 100644 --- a/webapp/packages/plugin-gis-viewer/src/LeafletMap.tsx +++ b/webapp/packages/plugin-gis-viewer/src/LeafletMap.tsx @@ -5,14 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - // eslint-disable-next-line @typescript-eslint/triple-slash-reference /// - import type geojson from 'geojson'; import leaflet from 'leaflet'; import { useCallback, useEffect, useState } from 'react'; -import { MapContainer, GeoJSON, LayersControl, TileLayer } from 'react-leaflet'; +import { GeoJSON, LayersControl, MapContainer, TileLayer } from 'react-leaflet'; import type { TileLayerProps } from 'react-leaflet'; import styled, { css } from 'reshadow'; @@ -60,9 +58,10 @@ const baseTiles: Record<'street' | 'topography', IBaseTile> = { }, topography: { name: 'gis_presentation_base_tile_topography_name', - attribution: '© OpenStreetMap,' - + ' © SRTM,' - + ' © OpenTopoMap', + attribution: + '© OpenStreetMap,' + + ' © SRTM,' + + ' © OpenTopoMap', url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', maxZoom: 17, }, @@ -122,25 +121,28 @@ export const LeafletMap: React.FC = function LeafletMap({ geoJSON, crsKey const crs = getCRS(crsKey); - const onEachFeature = useCallback((feature: IGeoJSONFeature, layer: leaflet.Layer) => { - const associatedValues = getAssociatedValues(feature.properties.associatedCell); - if (associatedValues.length > 0) { - let popupContent = ''; + const onEachFeature = useCallback( + (feature: IGeoJSONFeature, layer: leaflet.Layer) => { + const associatedValues = getAssociatedValues(feature.properties.associatedCell); + if (associatedValues.length > 0) { + let popupContent = ''; - popupContent += ''; - for (let i = 0; i < associatedValues.length; i++) { - const { key, value } = associatedValues[i]; + popupContent += '
'; + for (let i = 0; i < associatedValues.length; i++) { + const { key, value } = associatedValues[i]; - if (value === undefined || typeof value === 'object') { - continue; + if (value === undefined || typeof value === 'object') { + continue; + } + + popupContent += ''; } - - popupContent += ''; + popupContent += '
' + key + '' + value + '
' + key + '' + value + '
'; + layer.bindPopup(popupContent, popupOption); } - popupContent += ''; - layer.bindPopup(popupContent, popupOption); - } - }, [getAssociatedValues]); + }, + [getAssociatedValues], + ); useEffect(() => { if (geoJSONLayerRef && mapRef) { @@ -182,7 +184,10 @@ export const LeafletMap: React.FC = function LeafletMap({ geoJSON, crsKey } }, [split.state.isResizing, split.state.mode, crs, mapRef]); - return styled(styles, baseStyles)( + return styled( + styles, + baseStyles, + )( = function LeafletMap({ geoJSON, crsKey /> {crs !== leaflet.CRS.Simple && ( - + = function LeafletMap({ geoJSON, crsKey id={baseTiles.street.id} /> - + = function LeafletMap({ geoJSON, crsKey )} - + , ); -}; \ No newline at end of file +}; diff --git a/webapp/packages/plugin-gis-viewer/src/LocaleService.ts b/webapp/packages/plugin-gis-viewer/src/LocaleService.ts index 144237a086..e3649a06b4 100644 --- a/webapp/packages/plugin-gis-viewer/src/LocaleService.ts +++ b/webapp/packages/plugin-gis-viewer/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-gis-viewer/src/ResultSetGISAction.ts b/webapp/packages/plugin-gis-viewer/src/ResultSetGISAction.ts index 71b9f700a0..2618ae2a5b 100644 --- a/webapp/packages/plugin-gis-viewer/src/ResultSetGISAction.ts +++ b/webapp/packages/plugin-gis-viewer/src/ResultSetGISAction.ts @@ -5,9 +5,15 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { ResultDataFormat } from '@cloudbeaver/core-sdk'; -import { databaseDataAction, IResultSetElementKey, type IDatabaseResultSet, DatabaseDataAction, type IDatabaseDataSource, ResultSetViewAction } from '@cloudbeaver/plugin-data-viewer'; +import { + databaseDataAction, + DatabaseDataAction, + type IDatabaseDataSource, + type IDatabaseResultSet, + IResultSetElementKey, + ResultSetViewAction, +} from '@cloudbeaver/plugin-data-viewer'; import type { IDatabaseDataGISAction } from './IDatabaseDataGISAction'; @@ -19,8 +25,10 @@ export interface IGISType { properties: Record | null; } @databaseDataAction() -export class ResultSetGISAction extends DatabaseDataAction - implements IDatabaseDataGISAction { +export class ResultSetGISAction + extends DatabaseDataAction + implements IDatabaseDataGISAction +{ private readonly GISValueType = 'geometry'; static dataFormat = [ResultDataFormat.Resultset]; @@ -35,11 +43,7 @@ export class ResultSetGISAction extends DatabaseDataAction { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-help/src/PluginBootstrap.ts b/webapp/packages/plugin-help/src/PluginBootstrap.ts index 6f1ebdfcee..3aaa838b30 100644 --- a/webapp/packages/plugin-help/src/PluginBootstrap.ts +++ b/webapp/packages/plugin-help/src/PluginBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { AppScreenService } from '@cloudbeaver/core-app'; import { ActionSnackbar } from '@cloudbeaver/core-blocks'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; @@ -34,7 +33,7 @@ export class PluginBootstrap extends Bootstrap { this.errorNotification = null; } - async load(): Promise { } + async load(): Promise {} register(): void { this.addTopAppMenuItems(); @@ -46,24 +45,25 @@ export class PluginBootstrap extends Bootstrap { if (this.errorNotification) { return; } - if ( - this.screenService.isActive(AppScreenService.screenName) - && this.localStorageSaveService.storage === 'session' - ) { - this.errorNotification = this.notificationService.customNotification(() => ActionSnackbar, { - actionText: 'plugin_help_multi_tab_support_load_settings', - onAction: () => { - this.localStorageSaveService.updateStorage('local'); - this.errorNotification?.close(false); + if (this.screenService.isActive(AppScreenService.screenName) && this.localStorageSaveService.storage === 'session') { + this.errorNotification = this.notificationService.customNotification( + () => ActionSnackbar, + { + actionText: 'plugin_help_multi_tab_support_load_settings', + onAction: () => { + this.localStorageSaveService.updateStorage('local'); + this.errorNotification?.close(false); + }, }, - }, { - type: ENotificationType.Error, - title: 'plugin_help_multi_tab_support_title', - message: 'plugin_help_multi_tab_support_description', - onClose: () => { - this.errorNotification = null; + { + type: ENotificationType.Error, + title: 'plugin_help_multi_tab_support_title', + message: 'plugin_help_multi_tab_support_description', + onClose: () => { + this.errorNotification = null; + }, }, - }); + ); } }; this.localStorageSaveService.onStorageChange.addHandler(displayErrorMessage); @@ -74,10 +74,7 @@ export class PluginBootstrap extends Bootstrap { private addTopAppMenuItems() { this.menuService.addCreator({ menus: [MENU_APP_STATE], - getItems: (context, items) => [ - ...items, - ACTION_APP_HELP, - ], + getItems: (context, items) => [...items, ACTION_APP_HELP], orderItems: (context, items) => { const extracted = menuExtractItems(items, [ACTION_APP_HELP]); @@ -89,9 +86,7 @@ export class PluginBootstrap extends Bootstrap { this.actionService.addHandler({ id: 'app-help', - isActionApplicable: (context, action) => [ - ACTION_APP_HELP, - ].includes(action), + isActionApplicable: (context, action) => [ACTION_APP_HELP].includes(action), handler: async (context, action) => { switch (action) { case ACTION_APP_HELP: { diff --git a/webapp/packages/plugin-help/src/Shortcuts/IShortcut.ts b/webapp/packages/plugin-help/src/Shortcuts/IShortcut.ts index 9a9d1b9033..64d2f4b2b2 100644 --- a/webapp/packages/plugin-help/src/Shortcuts/IShortcut.ts +++ b/webapp/packages/plugin-help/src/Shortcuts/IShortcut.ts @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { TLocalizationToken } from '@cloudbeaver/core-localization'; export interface IShortcut { label: TLocalizationToken; code: string[]; -} \ No newline at end of file +} diff --git a/webapp/packages/plugin-help/src/Shortcuts/SHORTCUTS_DATA.ts b/webapp/packages/plugin-help/src/Shortcuts/SHORTCUTS_DATA.ts index bd04ff8741..495b601fa2 100644 --- a/webapp/packages/plugin-help/src/Shortcuts/SHORTCUTS_DATA.ts +++ b/webapp/packages/plugin-help/src/Shortcuts/SHORTCUTS_DATA.ts @@ -5,10 +5,15 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { KEY_BINDING_OPEN_IN_TAB, KEY_BINDING_REDO, KEY_BINDING_UNDO } from '@cloudbeaver/core-view'; -import { KEY_BINDING_ENABLE_FILTER, KEY_BINDING_COLLAPSE_ALL, KEY_BINDING_LINK_OBJECT } from '@cloudbeaver/plugin-navigation-tree'; -import { KEY_BINDING_SQL_EDITOR_EXECUTE, KEY_BINDING_SQL_EDITOR_EXECUTE_NEW, KEY_BINDING_SQL_EDITOR_EXECUTE_SCRIPT, KEY_BINDING_SQL_EDITOR_FORMAT, KEY_BINDING_SQL_EDITOR_SHOW_EXECUTION_PLAN } from '@cloudbeaver/plugin-sql-editor'; +import { KEY_BINDING_COLLAPSE_ALL, KEY_BINDING_ENABLE_FILTER, KEY_BINDING_LINK_OBJECT } from '@cloudbeaver/plugin-navigation-tree'; +import { + KEY_BINDING_SQL_EDITOR_EXECUTE, + KEY_BINDING_SQL_EDITOR_EXECUTE_NEW, + KEY_BINDING_SQL_EDITOR_EXECUTE_SCRIPT, + KEY_BINDING_SQL_EDITOR_FORMAT, + KEY_BINDING_SQL_EDITOR_SHOW_EXECUTION_PLAN, +} from '@cloudbeaver/plugin-sql-editor'; import type { IShortcut } from './IShortcut'; @@ -98,5 +103,5 @@ function transformKeys(keys: string | string[]): string[] { keys = [keys]; } - return keys.map(key => key.toLocaleUpperCase().replace(/\+/ig, ' + ')); -} \ No newline at end of file + return keys.map(key => key.toLocaleUpperCase().replace(/\+/gi, ' + ')); +} diff --git a/webapp/packages/plugin-help/src/Shortcuts/Shortcut.tsx b/webapp/packages/plugin-help/src/Shortcuts/Shortcut.tsx index d97b41a8ed..3ef3a7691d 100644 --- a/webapp/packages/plugin-help/src/Shortcuts/Shortcut.tsx +++ b/webapp/packages/plugin-help/src/Shortcuts/Shortcut.tsx @@ -5,10 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled, { css } from 'reshadow'; -import { useTranslate, useStyles } from '@cloudbeaver/core-blocks'; +import { useStyles, useTranslate } from '@cloudbeaver/core-blocks'; import type { IShortcut } from './IShortcut'; @@ -17,31 +16,31 @@ interface Props { } const style = css` - shortcut-container { - display: flex; - align-items: center; - justify-content: space-between; - } - shortcut-label { - margin-right: 8px; - } - shortcut-content { - display: flex; - align-items: center; - gap: 4px; - } - shortcut-code { - composes: theme-form-element-radius theme-background-secondary theme-text-on-secondary from global; - flex-shrink: 0; - font-family: monospace; - font-weight: bold; - width: max-content; - padding: 4px 8px; - } - span { - white-space: nowrap; - text-transform: lowercase; - } + shortcut-container { + display: flex; + align-items: center; + justify-content: space-between; + } + shortcut-label { + margin-right: 8px; + } + shortcut-content { + display: flex; + align-items: center; + gap: 4px; + } + shortcut-code { + composes: theme-form-element-radius theme-background-secondary theme-text-on-secondary from global; + flex-shrink: 0; + font-family: monospace; + font-weight: bold; + width: max-content; + padding: 4px 8px; + } + span { + white-space: nowrap; + text-transform: lowercase; + } `; export const Shortcut: React.FC = function Shortcut({ shortcut }) { @@ -49,19 +48,15 @@ export const Shortcut: React.FC = function Shortcut({ shortcut }) { return styled(style)( - - {translate(shortcut.label)} - + {translate(shortcut.label)} {shortcut.code.map((code, index) => ( <> {index > 0 && {translate('ui_or')}} - - {code} - + {code} ))} - + , ); -}; \ No newline at end of file +}; diff --git a/webapp/packages/plugin-help/src/Shortcuts/ShortcutsDialog.tsx b/webapp/packages/plugin-help/src/Shortcuts/ShortcutsDialog.tsx index 7dfb8cb040..1693d080b3 100644 --- a/webapp/packages/plugin-help/src/Shortcuts/ShortcutsDialog.tsx +++ b/webapp/packages/plugin-help/src/Shortcuts/ShortcutsDialog.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import styled, { css } from 'reshadow'; import { BASE_CONTAINERS_STYLES, Button, Container, Group, GroupTitle, Link, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; @@ -14,7 +13,6 @@ import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogW import { Shortcut } from './Shortcut'; import { DATA_VIEWER_SHORTCUTS, NAVIGATION_TREE_SHORTCUTS, SQL_EDITOR_SHORTCUTS } from './SHORTCUTS_DATA'; - const style = css` Button { margin-left: auto; @@ -26,7 +24,8 @@ const style = css` Group { gap: 16px; } - GroupTitle, Group { + GroupTitle, + Group { padding: 0 !important; } GroupTitle { @@ -34,51 +33,52 @@ const style = css` } `; -export const ShortcutsDialog: DialogComponent = function ShortcutsDialog({ - rejectDialog, -}) { +export const ShortcutsDialog: DialogComponent = function ShortcutsDialog({ rejectDialog }) { const translate = useTranslate(); const styles = useStyles(BASE_CONTAINERS_STYLES, style); return styled(styles)( - - + + - - Data Viewer + + Data Viewer - {DATA_VIEWER_SHORTCUTS.map(shortcut => )} + {DATA_VIEWER_SHORTCUTS.map(shortcut => ( + + ))} - - SQL Editor + + SQL Editor - {SQL_EDITOR_SHORTCUTS.map(shortcut => )} + {SQL_EDITOR_SHORTCUTS.map(shortcut => ( + + ))} - - Navigation Tree + + Navigation Tree - {NAVIGATION_TREE_SHORTCUTS.map(shortcut => )} + {NAVIGATION_TREE_SHORTCUTS.map(shortcut => ( + + ))} - - + , ); -}; \ No newline at end of file +}; diff --git a/webapp/packages/plugin-help/src/actions/ACTION_APP_HELP.ts b/webapp/packages/plugin-help/src/actions/ACTION_APP_HELP.ts index 7c275283f2..fecc5ed07d 100644 --- a/webapp/packages/plugin-help/src/actions/ACTION_APP_HELP.ts +++ b/webapp/packages/plugin-help/src/actions/ACTION_APP_HELP.ts @@ -5,11 +5,10 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; export const ACTION_APP_HELP = createAction('app-help', { label: 'shortcuts_title', tooltip: 'shortcuts_title', icon: '/icons/plugin_help_m.svg', -}); \ No newline at end of file +}); diff --git a/webapp/packages/plugin-help/src/index.ts b/webapp/packages/plugin-help/src/index.ts index 15bc2512af..e2e38fb300 100644 --- a/webapp/packages/plugin-help/src/index.ts +++ b/webapp/packages/plugin-help/src/index.ts @@ -1,3 +1,3 @@ import { manifest } from './manifest'; -export default manifest; \ No newline at end of file +export default manifest; diff --git a/webapp/packages/plugin-help/src/locales/en.ts b/webapp/packages/plugin-help/src/locales/en.ts index 49ebb1253b..8ccebf6fcc 100644 --- a/webapp/packages/plugin-help/src/locales/en.ts +++ b/webapp/packages/plugin-help/src/locales/en.ts @@ -21,9 +21,12 @@ export default [ ['navigation_tree_shortcut_enable_filter', 'Enable filtering'], ['plugin_help_multi_tab_support_title', 'Multi-tab is not supported'], - ['plugin_help_multi_tab_support_description', `The data is not connected to other browser tabs. + [ + 'plugin_help_multi_tab_support_description', + `The data is not connected to other browser tabs. Any opened application tabs will not be saved and will most likely be lost after the tab is closed. Your local application settings will be lost after the browser tab is closed. - You can load tabs and settings for this tab`], + You can load tabs and settings for this tab`, + ], ['plugin_help_multi_tab_support_load_settings', 'Load tabs ans settings'], ]; diff --git a/webapp/packages/plugin-help/src/manifest.ts b/webapp/packages/plugin-help/src/manifest.ts index 9f06b53f3a..f1f6e586ac 100644 --- a/webapp/packages/plugin-help/src/manifest.ts +++ b/webapp/packages/plugin-help/src/manifest.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { LocaleService } from './LocaleService'; @@ -16,8 +15,5 @@ export const manifest: PluginManifest = { name: 'Help plugin', }, - providers: [ - PluginBootstrap, - LocaleService, - ], + providers: [PluginBootstrap, LocaleService], }; diff --git a/webapp/packages/plugin-localization/src/LOCALIZATION_MENU.ts b/webapp/packages/plugin-localization/src/LOCALIZATION_MENU.ts index f1f06dba8d..08435b100c 100644 --- a/webapp/packages/plugin-localization/src/LOCALIZATION_MENU.ts +++ b/webapp/packages/plugin-localization/src/LOCALIZATION_MENU.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createMenu } from '@cloudbeaver/core-view'; export const LOCALIZATION_MENU = createMenu('localization-menu', 'app_shared_settingsMenu_lang'); diff --git a/webapp/packages/plugin-localization/src/PluginBootstrap.ts b/webapp/packages/plugin-localization/src/PluginBootstrap.ts index 947ae89888..d973802f3a 100644 --- a/webapp/packages/plugin-localization/src/PluginBootstrap.ts +++ b/webapp/packages/plugin-localization/src/PluginBootstrap.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; import { ServerConfigResource } from '@cloudbeaver/core-root'; @@ -19,7 +18,7 @@ export class PluginBootstrap extends Bootstrap { constructor( private readonly localizationService: LocalizationService, private readonly menuService: MenuService, - private readonly serverConfigResource: ServerConfigResource + private readonly serverConfigResource: ServerConfigResource, ) { super(); } @@ -33,15 +32,10 @@ export class PluginBootstrap extends Bootstrap { }); this.menuService.addCreator({ - isApplicable: context => ( - context.get(DATA_CONTEXT_MENU) === TOP_NAV_BAR_SETTINGS_MENU - && !!this.serverConfigResource.data?.supportedLanguages.length - ), + isApplicable: context => + context.get(DATA_CONTEXT_MENU) === TOP_NAV_BAR_SETTINGS_MENU && !!this.serverConfigResource.data?.supportedLanguages.length, getItems(context, items) { - return [ - ...items, - LOCALIZATION_MENU, - ]; + return [...items, LOCALIZATION_MENU]; }, }); @@ -64,17 +58,14 @@ export class PluginBootstrap extends Bootstrap { tooltip: label, }, { onSelect: () => this.localizationService.changeLocaleAsync(lang.isoCode) }, - { isDisabled: () => this.localizationService.currentLanguage === lang.isoCode } + { isDisabled: () => this.localizationService.currentLanguage === lang.isoCode }, ); }); - return [ - ...items, - ...languages, - ]; + return [...items, ...languages]; }, }); } - load(): void | Promise { } -} \ No newline at end of file + load(): void | Promise {} +} diff --git a/webapp/packages/plugin-localization/src/index.ts b/webapp/packages/plugin-localization/src/index.ts index e327083077..0151f07209 100644 --- a/webapp/packages/plugin-localization/src/index.ts +++ b/webapp/packages/plugin-localization/src/index.ts @@ -2,4 +2,4 @@ import { localizationPlugin } from './manifest'; export default localizationPlugin; -export * from './LOCALIZATION_MENU'; \ No newline at end of file +export * from './LOCALIZATION_MENU'; diff --git a/webapp/packages/plugin-localization/src/manifest.ts b/webapp/packages/plugin-localization/src/manifest.ts index 030184c049..19196ab410 100644 --- a/webapp/packages/plugin-localization/src/manifest.ts +++ b/webapp/packages/plugin-localization/src/manifest.ts @@ -5,14 +5,11 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { PluginManifest } from '@cloudbeaver/core-di'; import { PluginBootstrap } from './PluginBootstrap'; export const localizationPlugin: PluginManifest = { info: { name: 'Localization plugin' }, - providers: [ - PluginBootstrap, - ], -}; \ No newline at end of file + providers: [PluginBootstrap], +}; diff --git a/webapp/packages/plugin-log-viewer/src/Actions/ACTION_LOG_VIEWER_ENABLE.ts b/webapp/packages/plugin-log-viewer/src/Actions/ACTION_LOG_VIEWER_ENABLE.ts index 7c3dd02bb1..e535b4e43c 100644 --- a/webapp/packages/plugin-log-viewer/src/Actions/ACTION_LOG_VIEWER_ENABLE.ts +++ b/webapp/packages/plugin-log-viewer/src/Actions/ACTION_LOG_VIEWER_ENABLE.ts @@ -5,13 +5,9 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { createAction } from '@cloudbeaver/core-view'; -export const ACTION_LOG_VIEWER_ENABLE = createAction( - 'log-viewer-enable', - { - label: 'plugin_log_viewer_action_enable_label', - type: 'checkbox', - } -); +export const ACTION_LOG_VIEWER_ENABLE = createAction('log-viewer-enable', { + label: 'plugin_log_viewer_action_enable_label', + type: 'checkbox', +}); diff --git a/webapp/packages/plugin-log-viewer/src/LocaleService.ts b/webapp/packages/plugin-log-viewer/src/LocaleService.ts index 144237a086..e3649a06b4 100644 --- a/webapp/packages/plugin-log-viewer/src/LocaleService.ts +++ b/webapp/packages/plugin-log-viewer/src/LocaleService.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { LocalizationService } from '@cloudbeaver/core-localization'; @@ -19,7 +18,7 @@ export class LocaleService extends Bootstrap { this.localizationService.addProvider(this.provider.bind(this)); } - load(): void | Promise { } + load(): void | Promise {} private async provider(locale: string) { switch (locale) { diff --git a/webapp/packages/plugin-log-viewer/src/LogViewer/ILogEntry.ts b/webapp/packages/plugin-log-viewer/src/LogViewer/ILogEntry.ts index 9b5e0f8780..39343075ab 100644 --- a/webapp/packages/plugin-log-viewer/src/LogViewer/ILogEntry.ts +++ b/webapp/packages/plugin-log-viewer/src/LogViewer/ILogEntry.ts @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import type { LogEntry } from '@cloudbeaver/core-sdk'; export interface ILogEntry extends LogEntry { diff --git a/webapp/packages/plugin-log-viewer/src/LogViewer/LogEntry.tsx b/webapp/packages/plugin-log-viewer/src/LogViewer/LogEntry.tsx index c3b57d106e..f6b4d10a9b 100644 --- a/webapp/packages/plugin-log-viewer/src/LogViewer/LogEntry.tsx +++ b/webapp/packages/plugin-log-viewer/src/LogViewer/LogEntry.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import styled, { css, use } from 'reshadow'; @@ -58,12 +57,7 @@ const style = css` } `; -export const LogEntry = observer(function LogEntry({ - item, - onSelect, - selected = false, - className, -}) { +export const LogEntry = observer(function LogEntry({ item, onSelect, selected = false, className }) { const translate = useTranslate(); const isError = !!item.stackTrace; @@ -87,18 +81,14 @@ export const LogEntry = observer(function LogEntry({ {icon && } - {displayTime} + + {displayTime} + - - {isError ? ( - onSelect(item)}> - {message} - - ) : message} - + {isError ? onSelect(item)}>{message} : message} - + , ); }); diff --git a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewer.tsx b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewer.tsx index 6135263b04..a49568d019 100644 --- a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewer.tsx +++ b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewer.tsx @@ -5,7 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback } from 'react'; import styled, { css } from 'reshadow'; @@ -17,16 +16,17 @@ import { LogViewerTable } from './LogViewerTable'; import { useLogViewer } from './useLogViewer'; const styles = css` - Pane { - composes: theme-background-surface theme-text-on-surface from global; - } - log-view-wrapper, Pane { - position: relative; - display: flex; - flex: 1; - flex-direction: column; - overflow: hidden; - } + Pane { + composes: theme-background-surface theme-text-on-surface from global; + } + log-view-wrapper, + Pane { + position: relative; + display: flex; + flex: 1; + flex-direction: column; + overflow: hidden; + } `; export const LogViewer = observer(function LogViewer() { @@ -45,12 +45,7 @@ export const LogViewer = observer(function LogViewer() { return styled(style)( - + - - {logViewerState.selectedItem && ( - - )} + + {logViewerState.selectedItem && } - + , ); }); diff --git a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerBootstrap.ts b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerBootstrap.ts index 453fbcf0f2..3c285ef8cc 100644 --- a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerBootstrap.ts +++ b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerBootstrap.ts @@ -5,23 +5,21 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { Bootstrap, injectable } from '@cloudbeaver/core-di'; -import { MenuService, ActionService, DATA_CONTEXT_MENU, menuExtractItems } from '@cloudbeaver/core-view'; +import { ActionService, DATA_CONTEXT_MENU, menuExtractItems, MenuService } from '@cloudbeaver/core-view'; import { MENU_TOOLS, ToolsPanelService } from '@cloudbeaver/plugin-tools-panel'; import { ACTION_LOG_VIEWER_ENABLE } from '../Actions/ACTION_LOG_VIEWER_ENABLE'; import { LogViewer } from './LogViewer'; import { LogViewerService } from './LogViewerService'; - @injectable() export class LogViewerBootstrap extends Bootstrap { constructor( private readonly toolsPanelService: ToolsPanelService, private readonly menuService: MenuService, private readonly actionService: ActionService, - private readonly logViewerService: LogViewerService + private readonly logViewerService: LogViewerService, ) { super(); } @@ -29,10 +27,7 @@ export class LogViewerBootstrap extends Bootstrap { register(): void { this.menuService.addCreator({ isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === MENU_TOOLS, - getItems: (context, items) => [ - ...items, - ACTION_LOG_VIEWER_ENABLE, - ], + getItems: (context, items) => [...items, ACTION_LOG_VIEWER_ENABLE], orderItems: (context, items) => { const extracted = menuExtractItems(items, [ACTION_LOG_VIEWER_ENABLE]); return [...items, ...extracted]; @@ -41,9 +36,7 @@ export class LogViewerBootstrap extends Bootstrap { this.actionService.addHandler({ id: 'log-viewer-base', - isActionApplicable: (context, action) => [ - ACTION_LOG_VIEWER_ENABLE, - ].includes(action), + isActionApplicable: (context, action) => [ACTION_LOG_VIEWER_ENABLE].includes(action), isChecked: () => this.logViewerService.isActive, isHidden: () => this.logViewerService.disabled, handler: (context, action) => { @@ -66,5 +59,5 @@ export class LogViewerBootstrap extends Bootstrap { }); } - load(): void { } + load(): void {} } diff --git a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerInfoPanel.tsx b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerInfoPanel.tsx index 671c0280bb..9443c438ab 100644 --- a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerInfoPanel.tsx +++ b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerInfoPanel.tsx @@ -5,14 +5,12 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { useCallback } from 'react'; import styled, { css } from 'reshadow'; import { MenuBarSmallItem, Textarea, useClipboard, useTranslate } from '@cloudbeaver/core-blocks'; - import type { ILogEntry } from './ILogEntry'; const styles = css` @@ -50,12 +48,13 @@ const styles = css` min-height: 40px; max-height: 96px; } - type, message { + type, + message { margin-bottom: 12px; } Textarea { flex: 1; - } + } `; interface Props { @@ -64,11 +63,7 @@ interface Props { className?: string; } -export const LogViewerInfoPanel = observer(function LogViewerInfoPanel({ - selectedItem, - onClose, - className, -}) { +export const LogViewerInfoPanel = observer(function LogViewerInfoPanel({ selectedItem, onClose, className }) { const translate = useTranslate(); const copy = useClipboard(); @@ -81,30 +76,18 @@ export const LogViewerInfoPanel = observer(function LogViewerInfoPanel({ return styled(styles)( - + {translate('ui_copy_to_clipboard')} - + {translate('ui_close')} - {typeInfo} + {typeInfo} {selectedItem.message} -