diff --git a/webapp/packages/core-administration/src/AdministrationSettingsService.ts b/webapp/packages/core-administration/src/AdministrationSettingsService.ts new file mode 100644 index 0000000000..ed0762ac91 --- /dev/null +++ b/webapp/packages/core-administration/src/AdministrationSettingsService.ts @@ -0,0 +1,31 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2021 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +import { injectable } from '@cloudbeaver/core-di'; +import { PluginManagerService } from '@cloudbeaver/core-plugin'; + +const defaultSettings = { + baseFeatures: [] as string[], +}; + +export type AdministrationSettings = typeof defaultSettings; + +@injectable() +export class AdministrationSettingsService { + readonly settings = this.pluginManagerService.getPluginSettings('core.administration', defaultSettings); + + constructor(private pluginManagerService: PluginManagerService) { } + + isBase(feature: string): boolean { + return this.getBase().includes(feature); + } + + getBase(): string[] { + return this.settings.getValue('baseFeatures'); + } +} diff --git a/webapp/packages/core-administration/src/index.ts b/webapp/packages/core-administration/src/index.ts index 87d36baa22..e0d2988178 100644 --- a/webapp/packages/core-administration/src/index.ts +++ b/webapp/packages/core-administration/src/index.ts @@ -9,6 +9,7 @@ export * from './AdministrationScreen/ConfigurationWizard/ConfigurationWizardSer export * from './AdministrationScreen/ConfigurationWizard/WizardTopAppBar/WizardTopAppBarService'; export * from './AdministrationToolsPanelStyles'; export * from './AdministrationLocaleService'; +export * from './AdministrationSettingsService'; export * from './EAdminPermission'; export * from './useAdministrationSettings'; diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx index 09b630f321..a635f19b70 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx @@ -95,6 +95,7 @@ interface SwitchType { export const Switch: SwitchType = observer(function Switch({ name, + id, value, defaultValue, description, @@ -142,7 +143,7 @@ export const Switch: SwitchType = observer(function Switch({ as='input' {...rest} type="checkbox" - id={value || name} + id={id || value || name} role="switch" aria-checked={checkboxState.checked} checked={checkboxState.checked} @@ -151,7 +152,7 @@ export const Switch: SwitchType = observer(function Switch({ /> - {children} + {children} {description} diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/useCheckboxState.ts b/webapp/packages/core-blocks/src/FormControls/Checkboxes/useCheckboxState.ts index b7602a4e0f..cb57eaf1ea 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/useCheckboxState.ts +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/useCheckboxState.ts @@ -87,5 +87,5 @@ export function useCheckboxState(options: CheckboxStateOpti refresh(count + 1); }, - }), { checked }); + }), { checked }, ['change']); } diff --git a/webapp/packages/core-bootstrap/src/manifest.ts b/webapp/packages/core-bootstrap/src/manifest.ts index 2f79e647db..116aefca46 100644 --- a/webapp/packages/core-bootstrap/src/manifest.ts +++ b/webapp/packages/core-bootstrap/src/manifest.ts @@ -8,6 +8,7 @@ import { AdministrationLocaleService, + AdministrationSettingsService, AdministrationTopAppBarService, AdministrationScreenService, AdministrationItemService, @@ -117,6 +118,7 @@ export const coreManifest: PluginManifest = { RouterService, // important, should be first because the router starts in load phase first after all plugins register phase NetworkStateService, AdministrationLocaleService, + AdministrationSettingsService, AdministrationTopAppBarService, AdministrationScreenService, AdministrationScreenServiceBootstrap, diff --git a/webapp/packages/core-root/src/ServerConfigResource.ts b/webapp/packages/core-root/src/ServerConfigResource.ts index 32d7175ccf..449febd495 100644 --- a/webapp/packages/core-root/src/ServerConfigResource.ts +++ b/webapp/packages/core-root/src/ServerConfigResource.ts @@ -56,14 +56,20 @@ export class ServerConfigResource extends CachedDataResource(); - constructor(protected fallback?: ISettingsSource) {} + constructor(protected fallback?: ISettingsSource) { + makeObservable(this, { + store: observable, + }); + } has(key: string): boolean { return this.store.has(key) || !!this.fallback?.has(key); diff --git a/webapp/packages/core-utils/src/parseJSONFlat.ts b/webapp/packages/core-utils/src/parseJSONFlat.ts index 862a73f812..10b438c8e3 100644 --- a/webapp/packages/core-utils/src/parseJSONFlat.ts +++ b/webapp/packages/core-utils/src/parseJSONFlat.ts @@ -12,6 +12,12 @@ export function parseJSONFlat( scope?: string ) { if (typeof object === 'object') { + if (Array.isArray(object)) { + if (scope) { + setValue(scope, object); + } + return; + } for (const [key, value] of Object.entries(object)) { parseJSONFlat(value, setValue, `${scope ? `${scope}.` : ''}${key}`); } diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationFeaturesForm.tsx b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationFeaturesForm.tsx new file mode 100644 index 0000000000..4d27fb229d --- /dev/null +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationFeaturesForm.tsx @@ -0,0 +1,65 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2021 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +import { observer } from 'mobx-react-lite'; +import { useContext } from 'react'; +import styled from 'reshadow'; + +import { AdministrationSettingsService } from '@cloudbeaver/core-administration'; +import { BASE_CONTAINERS_STYLES, FormContext, GroupTitle, Loader, PlaceholderComponent, Switch, useDataResource } from '@cloudbeaver/core-blocks'; +import { useService } from '@cloudbeaver/core-di'; +import { useTranslate } from '@cloudbeaver/core-localization'; +import { FeaturesResource } from '@cloudbeaver/core-root'; +import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; +import { useStyles } from '@cloudbeaver/core-theming'; +import type { IConfigurationPlaceholderProps } from '@cloudbeaver/plugin-administration'; + +export const ServerConfigurationFeaturesForm: PlaceholderComponent = observer(function ServerConfigurationFeaturesForm({ + state: { serverConfig }, + configurationWizard, +}) { + const administrationSettingsService = useService(AdministrationSettingsService); + const features = useDataResource(ServerConfigurationFeaturesForm, FeaturesResource, CachedMapAllKey); + const translate = useTranslate(); + const styles = useStyles(BASE_CONTAINERS_STYLES); + const formContext = useContext(FormContext); + + if (formContext === null) { + throw new Error('Form state should be provided'); + } + + if (features.data.length === 0) { + return null; + } + + return styled(styles)( + <> + {translate('administration_configuration_wizard_configuration_features_group')} + + {() => styled(styles)( + <> + {features.data.map(feature => ( + + {feature.label} + + ))} + + )} + + + ); +}); diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPage.tsx b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPage.tsx index 458313479f..40b70e5b22 100644 --- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPage.tsx +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPage.tsx @@ -18,6 +18,7 @@ import { ServerConfigResource } from '@cloudbeaver/core-root'; import { useStyles } from '@cloudbeaver/core-theming'; import { ServerConfigurationConfigurationForm } from './Form/ServerConfigurationConfigurationForm'; +import { ServerConfigurationFeaturesForm } from './Form/ServerConfigurationFeaturesForm'; import { ServerConfigurationInfoForm } from './Form/ServerConfigurationInfoForm'; import { ServerConfigurationNavigatorViewForm } from './Form/ServerConfigurationNavigatorViewForm'; import { ServerConfigurationSecurityForm } from './Form/ServerConfigurationSecurityForm'; @@ -123,6 +124,7 @@ export const ServerConfigurationPage: AdministrationItemContentComponent = obser {translate('administration_configuration_wizard_configuration_plugins')} + diff --git a/webapp/packages/plugin-authentication/src/Administration/ServerConfiguration/AuthenticationProviders.tsx b/webapp/packages/plugin-authentication/src/Administration/ServerConfiguration/AuthenticationProviders.tsx index b5e48c5eb4..8457e777e4 100644 --- a/webapp/packages/plugin-authentication/src/Administration/ServerConfiguration/AuthenticationProviders.tsx +++ b/webapp/packages/plugin-authentication/src/Administration/ServerConfiguration/AuthenticationProviders.tsx @@ -35,7 +35,6 @@ export const AuthenticationProviders: PlaceholderComponent provider.id !== AUTH_PROVIDER_LOCAL_ID); const externalAuthentication = providers.data.length === 1 && localProvider === undefined; const authenticationDisabled = serverConfig.enabledAuthProviders?.length === 0; @@ -54,10 +53,10 @@ export const AuthenticationProviders: PlaceholderComponent - {localProvider && ( - <> - - {translate('administration_configuration_wizard_configuration_authentication_group')} + + {translate('administration_configuration_wizard_configuration_authentication_group')} + {localProvider && ( + <> {translate('administration_configuration_wizard_configuration_anonymous_access')} - - {() => localProvider && styled(styles)( - - {localProvider.label} - - )} - - - {configurationWizard && ( - - )} - - )} - {services.length > 0 ? ( - - {translate('administration_configuration_wizard_configuration_services')} - - {() => styled(styles)( - <> - {services.map(provider => { - const links = authProviderService.getServiceDescriptionLinks(provider); + + )} + + {() => styled(styles)( + <> + {providers.resource.values.map(provider => { + const links = authProviderService.getServiceDescriptionLinks(provider); - return ( - - {provider.description} - {links.map(link => { - const Description = link.description(); - return ; - })} - - )} - disabled={providers.resource.isBase(provider.id)} - mod={['primary']} - small - autoHide - > - {provider.label} - - ); - })} - - )} - - + return ( + + {provider.description} + {links.map(link => { + const Description = link.description(); + return ; + })} + + )} + disabled={providers.resource.isBase(provider.id)} + mod={['primary']} + small + autoHide + > + {provider.label} + + ); + })} + + )} + + + {configurationWizard && localProvider ? ( + ) : } - {!(configurationWizard && localProvider) && } ); }); diff --git a/webapp/packages/plugin-authentication/src/Administration/ServerConfiguration/ServerConfigurationAuthenticationBootstrap.ts b/webapp/packages/plugin-authentication/src/Administration/ServerConfiguration/ServerConfigurationAuthenticationBootstrap.ts index 9fd6cf71f5..2a06e2e494 100644 --- a/webapp/packages/plugin-authentication/src/Administration/ServerConfiguration/ServerConfigurationAuthenticationBootstrap.ts +++ b/webapp/packages/plugin-authentication/src/Administration/ServerConfiguration/ServerConfigurationAuthenticationBootstrap.ts @@ -56,6 +56,7 @@ export class ServerConfigurationAuthenticationBootstrap extends Bootstrap { data.state.serverConfig.anonymousAccessEnabled = config.anonymousAccessEnabled; data.state.serverConfig.enabledAuthProviders = [...config.enabledAuthProviders]; + data.state.serverConfig.enabledFeatures = [...config.enabledFeatures]; } catch (exception) { ExecutorInterrupter.interrupt(contexts); this.notificationService.logException(exception, 'Can\'t load server configuration'); diff --git a/webapp/packages/plugin-authentication/src/Dialog/AuthDialog.tsx b/webapp/packages/plugin-authentication/src/Dialog/AuthDialog.tsx index ad38952228..23fb53f7a0 100644 --- a/webapp/packages/plugin-authentication/src/Dialog/AuthDialog.tsx +++ b/webapp/packages/plugin-authentication/src/Dialog/AuthDialog.tsx @@ -85,8 +85,8 @@ export const AuthDialog: DialogComponent = observer(function const controller = useController(AuthDialogController, link, providerId, rejectDialog); const translate = useTranslate(); - if (!providerId) { - controller.setAdminMode(administrationScreenService.activeScreen !== null); + if (administrationScreenService.activeScreen !== null) { + controller.setAdminMode(administrationScreenService.activeScreen !== null, providerId); } const additional = userInfo.data !== null diff --git a/webapp/packages/plugin-authentication/src/Dialog/AuthDialogController.ts b/webapp/packages/plugin-authentication/src/Dialog/AuthDialogController.ts index 860e02edb6..fe0185295a 100644 --- a/webapp/packages/plugin-authentication/src/Dialog/AuthDialogController.ts +++ b/webapp/packages/plugin-authentication/src/Dialog/AuthDialogController.ts @@ -92,11 +92,13 @@ export class AuthDialogController implements IInitializableController, IDestruct this.loadProviders(); } - setAdminMode(mode: boolean): void { + setAdminMode(mode: boolean, providerId: string | null): void { if (this.admin !== mode) { this.admin = mode; - this.selectFirstAvailable(); + if (!providerId) { + this.selectFirstAvailable(); + } } } diff --git a/webapp/packages/plugin-authentication/src/locales/en.ts b/webapp/packages/plugin-authentication/src/locales/en.ts index 6d9220f8a8..22e24b877a 100644 --- a/webapp/packages/plugin-authentication/src/locales/en.ts +++ b/webapp/packages/plugin-authentication/src/locales/en.ts @@ -53,6 +53,7 @@ export default [ ['administration_configuration_wizard_configuration_anonymous_access', 'Allow anonymous access'], ['administration_configuration_wizard_configuration_anonymous_access_description', 'Allows to work with CloudBeaver without user authentication'], ['administration_configuration_wizard_configuration_authentication_group', 'Authentication settings'], + ['administration_configuration_wizard_configuration_features_group', 'Features'], ['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'], diff --git a/webapp/packages/plugin-authentication/src/locales/it.ts b/webapp/packages/plugin-authentication/src/locales/it.ts index 34818ef585..49e1fc966c 100644 --- a/webapp/packages/plugin-authentication/src/locales/it.ts +++ b/webapp/packages/plugin-authentication/src/locales/it.ts @@ -51,6 +51,7 @@ export default [ ['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_features_group', 'Функции'], ['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'],