mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
Merge remote-tracking branch 'origin/devel' into devel
This commit is contained in:
@@ -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');
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
|
||||
@@ -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({
|
||||
/>
|
||||
</switch-control-underlay>
|
||||
</switch-control>
|
||||
<field-label as="label" htmlFor={value || name}>{children}</field-label>
|
||||
<field-label as="label" htmlFor={id || value || name}>{children}</field-label>
|
||||
</switch-body>
|
||||
<field-description>{description}</field-description>
|
||||
</field>
|
||||
|
||||
@@ -87,5 +87,5 @@ export function useCheckboxState<TKey extends string>(options: CheckboxStateOpti
|
||||
|
||||
refresh(count + 1);
|
||||
},
|
||||
}), { checked });
|
||||
}), { checked }, ['change']);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -56,14 +56,20 @@ export class ServerConfigResource extends CachedDataResource<ServerConfig | null
|
||||
}
|
||||
|
||||
get publicDisabled(): boolean {
|
||||
if (this.data?.configurationMode
|
||||
|| (this.data?.licenseRequired && !this.data?.licenseValid)) {
|
||||
if (
|
||||
this.data?.configurationMode
|
||||
|| (this.data?.licenseRequired && !this.data?.licenseValid)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
get enabledFeatures(): string[] {
|
||||
return this.update.enabledFeatures || this.data?.enabledFeatures || [];
|
||||
}
|
||||
|
||||
get enabledAuthProviders(): string[] {
|
||||
return this.update.enabledAuthProviders || this.data?.enabledAuthProviders || [];
|
||||
}
|
||||
@@ -76,6 +82,10 @@ export class ServerConfigResource extends CachedDataResource<ServerConfig | null
|
||||
return this.update.publicCredentialsSaveEnabled ?? this.data?.publicCredentialsSaveEnabled ?? false;
|
||||
}
|
||||
|
||||
isFeatureEnabled(feature: string): boolean {
|
||||
return this.enabledFeatures.includes(feature);
|
||||
}
|
||||
|
||||
isChanged(): boolean {
|
||||
if (!this.data || Object.keys(this.update).length === 0) {
|
||||
return false;
|
||||
@@ -97,6 +107,7 @@ export class ServerConfigResource extends CachedDataResource<ServerConfig | null
|
||||
|
||||
|| this.update.customConnectionsEnabled !== this.data.supportsCustomConnections
|
||||
|| !isArraysEqual(this.update.enabledAuthProviders || [], this.data.enabledAuthProviders)
|
||||
|| !isArraysEqual(this.update.enabledFeatures || [], this.data.enabledFeatures)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -194,5 +205,6 @@ export class ServerConfigResource extends CachedDataResource<ServerConfig | null
|
||||
|
||||
this.update.customConnectionsEnabled = serverConfig.supportsCustomConnections;
|
||||
this.update.enabledAuthProviders = [...serverConfig.enabledAuthProviders];
|
||||
this.update.enabledFeatures = [...serverConfig.enabledFeatures];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,18 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { makeObservable, observable } from 'mobx';
|
||||
|
||||
import type { ISettingsSource } from './ISettingsSource';
|
||||
|
||||
export class SettingsSource implements ISettingsSource {
|
||||
protected store = new Map<string, any>();
|
||||
|
||||
constructor(protected fallback?: ISettingsSource) {}
|
||||
constructor(protected fallback?: ISettingsSource) {
|
||||
makeObservable<this, 'store'>(this, {
|
||||
store: observable,
|
||||
});
|
||||
}
|
||||
|
||||
has(key: string): boolean {
|
||||
return this.store.has(key) || !!this.fallback?.has(key);
|
||||
|
||||
@@ -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<any>(object)) {
|
||||
parseJSONFlat(value, setValue, `${scope ? `${scope}.` : ''}${key}`);
|
||||
}
|
||||
|
||||
+65
@@ -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<IConfigurationPlaceholderProps> = 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)(
|
||||
<>
|
||||
<GroupTitle>{translate('administration_configuration_wizard_configuration_features_group')}</GroupTitle>
|
||||
<Loader state={features} inline>
|
||||
{() => styled(styles)(
|
||||
<>
|
||||
{features.data.map(feature => (
|
||||
<Switch
|
||||
key={feature.id}
|
||||
value={feature.id}
|
||||
name="enabledFeatures"
|
||||
state={serverConfig}
|
||||
description={feature.description}
|
||||
disabled={administrationSettingsService.isBase(feature.id)}
|
||||
mod={['primary']}
|
||||
small
|
||||
>
|
||||
{feature.label}
|
||||
</Switch>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</Loader>
|
||||
</>
|
||||
);
|
||||
});
|
||||
+2
@@ -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
|
||||
<GroupTitle>{translate('administration_configuration_wizard_configuration_plugins')}</GroupTitle>
|
||||
<ServerConfigurationConfigurationForm serverConfig={service.state.serverConfig} />
|
||||
<ServerConfigurationNavigatorViewForm configs={service.state} />
|
||||
<ServerConfigurationFeaturesForm state={service.state} configurationWizard={configurationWizard} />
|
||||
<Placeholder container={service.pluginsContainer} />
|
||||
</Group>
|
||||
<ServerConfigurationSecurityForm serverConfig={service.state.serverConfig} />
|
||||
|
||||
+42
-64
@@ -35,7 +35,6 @@ export const AuthenticationProviders: PlaceholderComponent<IConfigurationPlaceho
|
||||
}
|
||||
|
||||
const localProvider = providers.resource.get(AUTH_PROVIDER_LOCAL_ID);
|
||||
const services = providers.resource.values.filter(provider => 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<IConfigurationPlaceho
|
||||
|
||||
return styled(styles)(
|
||||
<Container wrap gap>
|
||||
{localProvider && (
|
||||
<>
|
||||
<Group key='authentication' form gap medium>
|
||||
<GroupTitle>{translate('administration_configuration_wizard_configuration_authentication_group')}</GroupTitle>
|
||||
<Group key='authentication' form gap medium>
|
||||
<GroupTitle>{translate('administration_configuration_wizard_configuration_authentication_group')}</GroupTitle>
|
||||
{localProvider && (
|
||||
<>
|
||||
<Switch
|
||||
name="anonymousAccessEnabled"
|
||||
state={serverConfig}
|
||||
@@ -69,67 +68,46 @@ export const AuthenticationProviders: PlaceholderComponent<IConfigurationPlaceho
|
||||
>
|
||||
{translate('administration_configuration_wizard_configuration_anonymous_access')}
|
||||
</Switch>
|
||||
<Loader state={providers} inline>
|
||||
{() => localProvider && styled(styles)(
|
||||
<Switch
|
||||
key={localProvider.id}
|
||||
value={localProvider.id}
|
||||
name="enabledAuthProviders"
|
||||
state={serverConfig}
|
||||
description={localProvider.description}
|
||||
mod={['primary']}
|
||||
small
|
||||
autoHide
|
||||
>
|
||||
{localProvider.label}
|
||||
</Switch>
|
||||
)}
|
||||
</Loader>
|
||||
</Group>
|
||||
{configurationWizard && (
|
||||
<ServerConfigurationAdminForm serverConfig={serverConfig} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{services.length > 0 ? (
|
||||
<Group key='services' form gap medium>
|
||||
<GroupTitle>{translate('administration_configuration_wizard_configuration_services')}</GroupTitle>
|
||||
<Loader state={providers} inline>
|
||||
{() => styled(styles)(
|
||||
<>
|
||||
{services.map(provider => {
|
||||
const links = authProviderService.getServiceDescriptionLinks(provider);
|
||||
</>
|
||||
)}
|
||||
<Loader state={providers} inline>
|
||||
{() => styled(styles)(
|
||||
<>
|
||||
{providers.resource.values.map(provider => {
|
||||
const links = authProviderService.getServiceDescriptionLinks(provider);
|
||||
|
||||
return (
|
||||
<Switch
|
||||
key={provider.id}
|
||||
value={provider.id}
|
||||
name="enabledAuthProviders"
|
||||
state={serverConfig}
|
||||
description={(
|
||||
<>
|
||||
{provider.description}
|
||||
{links.map(link => {
|
||||
const Description = link.description();
|
||||
return <Description key={link.id} configurationWizard={configurationWizard} />;
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
disabled={providers.resource.isBase(provider.id)}
|
||||
mod={['primary']}
|
||||
small
|
||||
autoHide
|
||||
>
|
||||
{provider.label}
|
||||
</Switch>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</Loader>
|
||||
</Group>
|
||||
return (
|
||||
<Switch
|
||||
key={provider.id}
|
||||
id={`authProvider_${provider.id}`}
|
||||
value={provider.id}
|
||||
name="enabledAuthProviders"
|
||||
state={serverConfig}
|
||||
description={(
|
||||
<>
|
||||
{provider.description}
|
||||
{links.map(link => {
|
||||
const Description = link.description();
|
||||
return <Description key={link.id} configurationWizard={configurationWizard} />;
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
disabled={providers.resource.isBase(provider.id)}
|
||||
mod={['primary']}
|
||||
small
|
||||
autoHide
|
||||
>
|
||||
{provider.label}
|
||||
</Switch>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</Loader>
|
||||
</Group>
|
||||
{configurationWizard && localProvider ? (
|
||||
<ServerConfigurationAdminForm serverConfig={serverConfig} />
|
||||
) : <Container medium />}
|
||||
{!(configurationWizard && localProvider) && <Container medium />}
|
||||
</Container>
|
||||
);
|
||||
});
|
||||
|
||||
+1
@@ -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');
|
||||
|
||||
@@ -85,8 +85,8 @@ export const AuthDialog: DialogComponent<IAuthPayload, null> = 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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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'],
|
||||
|
||||
@@ -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'],
|
||||
|
||||
Reference in New Issue
Block a user