diff --git a/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenServiceBootstrap.ts b/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenServiceBootstrap.ts index e8eafe8583..81bf84c4ff 100644 --- a/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenServiceBootstrap.ts +++ b/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenServiceBootstrap.ts @@ -7,7 +7,7 @@ */ import { injectable, Bootstrap } from '@cloudbeaver/core-di'; -import { PermissionsService } from '@cloudbeaver/core-root'; +import { PermissionsService, ServerConfigResource } from '@cloudbeaver/core-root'; import { ScreenService, RouterState } from '@cloudbeaver/core-routing'; import { AdministrationItemService } from '../AdministrationItem/AdministrationItemService'; @@ -23,7 +23,8 @@ export class AdministrationScreenServiceBootstrap extends Bootstrap { private screenService: ScreenService, private permissionsService: PermissionsService, private administrationItemService: AdministrationItemService, - private administrationScreenService: AdministrationScreenService + private administrationScreenService: AdministrationScreenService, + private serverConfigResource: ServerConfigResource ) { super(); this.permissionsService.onUpdate.subscribe(this.handleActivate.bind(this)); @@ -87,7 +88,14 @@ export class AdministrationScreenServiceBootstrap extends Bootstrap { }); } - load(): void | Promise { } + async load() { + const config = await this.serverConfigResource.load(null); + + if (config?.configurationMode) { + this.administrationScreenService.configurationWizard = true; + this.administrationScreenService.navigateToRoot(); + } + } private async handleCanActivate(toState: RouterState, fromState: RouterState) { if (!toState.params?.item) { @@ -103,16 +111,11 @@ export class AdministrationScreenServiceBootstrap extends Bootstrap { } private async handleActivate() { - if (!this.permissionsService.has(EAdminPermission.admin)) { + if (await !this.permissionsService.hasAsync(EAdminPermission.admin)) { this.screenService.navigateToRoot(); return; } - // FIXME: for development purposes only, must be removed - if (this.screenService.isActive(AdministrationScreenService.setupName)) { - this.administrationScreenService.configurationWizard = true; - } - if (this.administrationScreenService.activeItem) { await this.administrationItemService.activate( this.administrationScreenService.activeItem, diff --git a/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/ConfigurationWizardService.ts b/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/ConfigurationWizardService.ts index 782381f488..e8ec38b5c9 100644 --- a/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/ConfigurationWizardService.ts +++ b/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/ConfigurationWizardService.ts @@ -9,6 +9,7 @@ import { observable, computed } from 'mobx'; import { injectable } from '@cloudbeaver/core-di'; +import { SessionResource, ServerConfigResource } from '@cloudbeaver/core-root'; import { ScreenService } from '@cloudbeaver/core-routing'; import { LocalStorageSaveService } from '@cloudbeaver/core-settings'; @@ -83,7 +84,9 @@ export class ConfigurationWizardService { private administrationItemService: AdministrationItemService, private administrationScreenService: AdministrationScreenService, private autoSaveService: LocalStorageSaveService, - private screenService: ScreenService + private screenService: ScreenService, + private sessionResource: SessionResource, + private serverConfigResource: ServerConfigResource ) { this.state = { finishedSteps: [], @@ -168,6 +171,8 @@ export class ConfigurationWizardService { await step.configurationWizardOptions.onConfigurationFinish(); } } + await this.serverConfigResource.update(); + await this.sessionResource.update(); this.administrationScreenService.clearItemsState(); this.state.finishedSteps = []; this.administrationScreenService.configurationWizard = false; diff --git a/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/ConfigurationWizardPagesBootstrapService.ts b/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/ConfigurationWizardPagesBootstrapService.ts index a3692cc2d8..9245398f7c 100644 --- a/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/ConfigurationWizardPagesBootstrapService.ts +++ b/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/ConfigurationWizardPagesBootstrapService.ts @@ -74,8 +74,8 @@ export class ConfigurationWizardPagesBootstrapService extends Bootstrap { } try { - await this.graphQLService.gql.configureServer({ configuration: state.serverConfig }); await this.graphQLService.gql.setDefaultNavigatorSettings({ settings: state.navigatorConfig }); + await this.graphQLService.gql.configureServer({ configuration: state.serverConfig }); } catch (exception) { this.notificationService.logException(exception, 'Can\'t save server configuration'); diff --git a/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/Welcome/WelcomeForm.tsx b/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/Welcome/WelcomeForm.tsx index 2452ca4a51..606e679f09 100644 --- a/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/Welcome/WelcomeForm.tsx +++ b/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/Welcome/WelcomeForm.tsx @@ -10,7 +10,7 @@ import { observer } from 'mobx-react'; import styled, { css } from 'reshadow'; import { - SubmittingForm, InputGroup, InputField, Checkbox, useFocus + SubmittingForm, InputGroup, InputField, Checkbox, useFocus, Switch } from '@cloudbeaver/core-blocks'; import { useTranslate } from '@cloudbeaver/core-localization'; import { ServerConfigInput, NavigatorSettingsInput } from '@cloudbeaver/core-sdk'; @@ -49,19 +49,19 @@ const boxStyles = css` flex-wrap: wrap; } box-element { - min-width: 450px; + width: 450px; } `; type Props = { serverConfig: ServerConfigInput; - navigatorConfig: NavigatorSettingsInput; + onChange: () => void; onSave: () => void; } export const WelcomeConfigForm = observer(function WelcomeConfigForm({ serverConfig, - navigatorConfig, + onChange, onSave, }: Props) { const translate = useTranslate(); @@ -78,6 +78,7 @@ export const WelcomeConfigForm = observer(function WelcomeConfigForm({ name='serverName' state={serverConfig} mod='surface' + required > {translate('administration_configuration_wizard_welcome_server_name')} @@ -90,6 +91,7 @@ export const WelcomeConfigForm = observer(function WelcomeConfigForm({ name="adminName" state={serverConfig} mod='surface' + required > {translate('administration_configuration_wizard_welcome_admin_name')} @@ -98,6 +100,7 @@ export const WelcomeConfigForm = observer(function WelcomeConfigForm({ name="adminPassword" state={serverConfig} mod='surface' + required > {translate('administration_configuration_wizard_welcome_admin_password')} @@ -105,89 +108,36 @@ export const WelcomeConfigForm = observer(function WelcomeConfigForm({ {translate('administration_configuration_wizard_welcome_plugins')} - + description={translate('administration_configuration_wizard_welcome_anonymous_access_description')} + mod={['primary']} + disabled={!serverConfig.authenticationEnabled} + > + {translate('administration_configuration_wizard_welcome_anonymous_access')} + - + description={translate('administration_configuration_wizard_welcome_authentication_description')} + onChange={onChange} + mod={['primary']} + > + {translate('administration_configuration_wizard_welcome_authentication')} + - - - - diff --git a/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/Welcome/WelcomePage.tsx b/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/Welcome/WelcomePage.tsx index 6698b4189d..a261a94f69 100644 --- a/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/Welcome/WelcomePage.tsx +++ b/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/Welcome/WelcomePage.tsx @@ -54,7 +54,7 @@ export const WelcomePage = observer(function WelcomePage() {

Here you can configure something...

diff --git a/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/Welcome/WelcomePageController.ts b/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/Welcome/WelcomePageController.ts index 2336760626..c81af85af9 100644 --- a/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/Welcome/WelcomePageController.ts +++ b/webapp/packages/core-administration/src/AdministrationScreen/ConfigurationWizard/Pages/Welcome/WelcomePageController.ts @@ -27,7 +27,7 @@ export class WelcomePageController { serverName: 'CloudBeaver', adminName: 'admin', adminPassword: '', - anonymousAccessEnabled: false, + anonymousAccessEnabled: true, authenticationEnabled: false, customConnectionsEnabled: false, }, @@ -43,5 +43,11 @@ export class WelcomePageController { })); } + onChange = () => { + if (!this.state.serverConfig.authenticationEnabled) { + this.state.serverConfig.anonymousAccessEnabled = true; + } + } + finish = () => this.configurationWizardService.next() } diff --git a/webapp/packages/core-administration/src/locales/en.ts b/webapp/packages/core-administration/src/locales/en.ts index 7ba07b3db1..2ea649bd00 100644 --- a/webapp/packages/core-administration/src/locales/en.ts +++ b/webapp/packages/core-administration/src/locales/en.ts @@ -2,18 +2,21 @@ export default [ ['administration_menu_enter', 'Administration'], ['administration_menu_back', 'Back to app'], ['administration_configuration_wizard_title', 'Initial Server Configuration'], - ['administration_configuration_wizard_welcome', 'Welcome'], - ['administration_configuration_wizard_welcome_plugins', 'Plugins'], - ['administration_configuration_wizard_welcome_step_description', 'Welcome'], + ['administration_configuration_wizard_welcome', 'Server configuration'], + ['administration_configuration_wizard_welcome_plugins', 'Configuration'], + ['administration_configuration_wizard_welcome_step_description', 'Server configuration'], ['administration_configuration_wizard_welcome_server_name', 'Server Name'], - ['administration_configuration_wizard_welcome_admin', 'Admin Credentials'], - ['administration_configuration_wizard_welcome_admin_name', 'Name'], - ['administration_configuration_wizard_welcome_admin_password', 'Password'], - ['administration_configuration_wizard_welcome_anonymous_access', 'Anonymous Access'], - ['administration_configuration_wizard_welcome_authentication', 'Authentication'], - ['administration_configuration_wizard_welcome_custom_connections', 'Custom Connections'], - ['administration_configuration_wizard_finish', 'Finalization'], - ['administration_configuration_wizard_finish_step_description', 'Finalization'], + ['administration_configuration_wizard_welcome_admin', 'Administrator'], + ['administration_configuration_wizard_welcome_admin_name', 'Admin user name'], + ['administration_configuration_wizard_welcome_admin_password', 'Admin password'], + ['administration_configuration_wizard_welcome_anonymous_access', 'Allow anonymous access'], + ['administration_configuration_wizard_welcome_anonymous_access_description', 'Allows to work with CloudBeaver without user authentication'], + ['administration_configuration_wizard_welcome_authentication', 'Enable users authentication'], + ['administration_configuration_wizard_welcome_authentication_description', 'Allows users to authenticate. Otherwise only anonymous access is enabled'], + ['administration_configuration_wizard_welcome_custom_connections', 'Enable custom connections'], + ['administration_configuration_wizard_welcome_custom_connections_description', 'Allows users to create custom connections. Otherwise only administrator can create connections'], + ['administration_configuration_wizard_finish', 'Confirmation'], + ['administration_configuration_wizard_finish_step_description', 'Confirmation'], ['administration_configuration_wizard_welcome_navigator', 'Navigator'], ['administration_configuration_wizard_welcome_navigator_hide_folders', 'Hide Folders'], ['administration_configuration_wizard_welcome_navigator_hide_schemas', 'Hide Schemas'], diff --git a/webapp/packages/core-blocks/src/FormControls/InputField.tsx b/webapp/packages/core-blocks/src/FormControls/InputField.tsx index 36ad51b805..0ff925ef99 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputField.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputField.tsx @@ -44,6 +44,7 @@ export const InputField: InputFieldType = observer(function InputField( ) { const { name, + required, state, children, className, @@ -65,13 +66,14 @@ export const InputField: InputFieldType = observer(function InputField( return styled(useStyles(baseFormControlStyles))( - {children} + {children} {required && '*'} ); diff --git a/webapp/packages/core-blocks/src/FormControls/InputGroup.tsx b/webapp/packages/core-blocks/src/FormControls/InputGroup.tsx index 961df06584..6f1d7e0ef9 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputGroup.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputGroup.tsx @@ -6,21 +6,30 @@ * you may not use this file except in compliance with the License. */ -import styled, { use, css } from 'reshadow'; +import styled, { css } from 'reshadow'; -import { useStyles } from '@cloudbeaver/core-theming'; +import { useStyles, composes } from '@cloudbeaver/core-theming'; import { baseFormControlStyles } from './baseFormControlStyles'; -const styles = css` - field-label { - composes: theme-typography--body2 from global; - margin-left: 150px; - text-align: left; - font-weight: initial; - } -`; - +const styles = composes( + css` + field-label { + composes: theme-border-color-background from global; + } + `, + css` + field-label { + composes: theme-typography--body2 from global; + margin-left: 150px; + text-align: left; + font-weight: initial; + padding-bottom: 8px; + border-bottom: solid 1px #dedede; + width: 100%; + } + ` +); type Props = React.PropsWithChildren<{ className?: string; }> diff --git a/webapp/packages/core-blocks/src/FormControls/Switch.tsx b/webapp/packages/core-blocks/src/FormControls/Switch.tsx new file mode 100644 index 0000000000..2d3d1b46f2 --- /dev/null +++ b/webapp/packages/core-blocks/src/FormControls/Switch.tsx @@ -0,0 +1,154 @@ +/* + * cloudbeaver - Cloud Database Manager + * Copyright (C) 2020 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'; +import { useCallback } from 'react'; +import styled, { css } from 'reshadow'; + +import { useStyles, composes } from '@cloudbeaver/core-theming'; + +import { baseFormControlStyles } from './baseFormControlStyles'; + +const switchStyles = composes( + 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; + } + `, + css` + field label { + width: auto; + } + ` +); + +const switchMod = { + primary: composes( + css` + switch-control { + composes: theme-switch_primary from global; + } + ` + ), +}; + +const switchState = { + disabled: composes( + css` + switch-control { + composes: theme-switch--disabled from global; + } + ` + ), + checked: composes( + css` + switch-control { + composes: theme-switch--checked from global; + } + ` + ), +}; + +type BaseProps = Omit, 'onChange' | 'type' | 'value' | 'checked'> & { + mod?: (keyof typeof switchMod)[]; + label?: string; + description?: string; +} + +type ControlledProps = BaseProps & { + checked?: boolean; + onChange?(value: boolean, name?: string): any; + + state?: never; +} + +type ObjectProps = BaseProps & { + name: TKey; + state: TState; + onChange?(value: boolean, name: TKey): any; + + checked?: never; +} + +type SwitchType = { + (props: ControlledProps): JSX.Element; + (props: ObjectProps): JSX.Element; +} + +export const Switch: SwitchType = observer(function Switch(props: ControlledProps | ObjectProps) { + const { + name, + id, + label, + description, + state, + className, + children, + onChange, + mod = [], + disabled, + ...rest + } = props; + + const handleChange = useCallback((event: React.ChangeEvent) => { + if (state) { + state[name] = event.target.checked; + } + if (onChange) { + onChange(event.target.checked, name); + } + }, [state, name, onChange]); + + const checked = state ? state[name] : props.checked; + + return styled(useStyles( + baseFormControlStyles, + switchStyles, + ...mod.map(mod => switchMod[mod]), + disabled && switchState.disabled, + checked && switchState.checked + ))( + + {children} + + + + + + + + + {description} + + ); +}); diff --git a/webapp/packages/core-blocks/src/FormControls/baseFormControlStyles.ts b/webapp/packages/core-blocks/src/FormControls/baseFormControlStyles.ts index 9b1c498406..c7d5855e72 100644 --- a/webapp/packages/core-blocks/src/FormControls/baseFormControlStyles.ts +++ b/webapp/packages/core-blocks/src/FormControls/baseFormControlStyles.ts @@ -11,6 +11,7 @@ import { css } from 'reshadow'; export const baseFormControlStyles = css` field { display: flex; + flex-wrap: wrap; flex: auto; box-sizing: border-box; align-items: center; @@ -33,4 +34,11 @@ export const baseFormControlStyles = css` line-height: 16px; font-weight: 500; } + + field-description { + composes: theme-typography--caption from global; + flex-basis: 100%; + padding-top: 8px; + padding-left: 150px; + } `; diff --git a/webapp/packages/core-blocks/src/index.ts b/webapp/packages/core-blocks/src/index.ts index 199e8f239f..3e3751f26d 100644 --- a/webapp/packages/core-blocks/src/index.ts +++ b/webapp/packages/core-blocks/src/index.ts @@ -20,6 +20,7 @@ export * from './FormControls/InputGroup'; export * from './FormControls/Radio'; export * from './FormControls/ShadowInput'; export * from './FormControls/SubmittingForm'; +export * from './FormControls/Switch'; export * from './FormControls/Textarea'; export * from './ErrorMessage'; export * from './IconButton'; diff --git a/webapp/packages/core-bootstrap/src/AppBootstrap.ts b/webapp/packages/core-bootstrap/src/AppBootstrap.ts index c15fb0a149..9ea9d9d40d 100644 --- a/webapp/packages/core-bootstrap/src/AppBootstrap.ts +++ b/webapp/packages/core-bootstrap/src/AppBootstrap.ts @@ -42,6 +42,7 @@ export class AppBootstrap { ) { } register(): void | Promise { + this.routerService.start(); this.exceptionsCatcherService.subscribe(); this.sessionExpireService.subscribe(); @@ -60,6 +61,5 @@ export class AppBootstrap { async doAfterPluginsInit() { // todo this should be moved to the NavigationTabs component creation phase but now it leads to bugs await this.navigationTabsService.restoreTabs(); - this.routerService.start(); } } diff --git a/webapp/packages/core-connections/src/Administration/Connections/ConnectionsDrawerItem.tsx b/webapp/packages/core-connections/src/Administration/Connections/ConnectionsDrawerItem.tsx index 9c9e2b722b..afe74616cf 100644 --- a/webapp/packages/core-connections/src/Administration/Connections/ConnectionsDrawerItem.tsx +++ b/webapp/packages/core-connections/src/Administration/Connections/ConnectionsDrawerItem.tsx @@ -14,12 +14,12 @@ import { Translate } from '@cloudbeaver/core-localization'; import { useStyles } from '@cloudbeaver/core-theming'; export function ConnectionsDrawerItem({ - item, onSelect, style, disabled, + item, onSelect, style, disabled, configurationWizard, }: AdministrationItemDrawerProps) { return styled(useStyles(...style))( onSelect(item.name)} disabled={disabled}> - + ); } diff --git a/webapp/packages/core-connections/src/locales/en.ts b/webapp/packages/core-connections/src/locales/en.ts index b0691b3670..fc7f9cc131 100644 --- a/webapp/packages/core-connections/src/locales/en.ts +++ b/webapp/packages/core-connections/src/locales/en.ts @@ -1,7 +1,8 @@ export default [ ['connections_administration_item', 'Connection Management'], ['connections_administration_new_connection', 'New connection'], - ['connections_administration_configuration_wizard_step_description', 'Configuring connections...'], + ['connections_administration_configuration_wizard_step_title', 'Database connections'], + ['connections_administration_configuration_wizard_step_description', 'Database connections'], ['connections_connection_edit_authentication', 'Authentication'], ['connections_connection_edit_access', 'Access'], ['connections_connection_edit_access_load_failed', 'Connection access loading failed'], diff --git a/webapp/packages/core-di/src/useController.ts b/webapp/packages/core-di/src/useController.ts index 80af4427c9..9fb42121f1 100644 --- a/webapp/packages/core-di/src/useController.ts +++ b/webapp/packages/core-di/src/useController.ts @@ -7,7 +7,7 @@ */ import { - useContext, useEffect, useRef, useState, useMemo, + useContext, useEffect, useRef, useMemo, } from 'react'; import { appContext } from './AppContext'; @@ -35,7 +35,9 @@ export function useController(ctor: IServiceConstructor, ...args: any[]): controller.init(...args); } controllerRef.current = controller; - }, [...args]); + }, [...args, args.length]); + /* we put dynamic array length as the dependency because of preact bug, + otherwise useMemo will not be triggered on array change */ useEffect(() => () => { if (isDestructibleController(controllerRef.current)) { diff --git a/webapp/packages/core-root/src/ServerConfigResource.ts b/webapp/packages/core-root/src/ServerConfigResource.ts index 4c57c831d7..82631d7f22 100644 --- a/webapp/packages/core-root/src/ServerConfigResource.ts +++ b/webapp/packages/core-root/src/ServerConfigResource.ts @@ -21,6 +21,10 @@ export class ServerConfigResource extends CachedDataResource { const { serverConfig } = await this.graphQLService.gql.serverConfig(); diff --git a/webapp/packages/core-root/src/SessionResource.ts b/webapp/packages/core-root/src/SessionResource.ts index 091d6b065c..0a89e82c8d 100644 --- a/webapp/packages/core-root/src/SessionResource.ts +++ b/webapp/packages/core-root/src/SessionResource.ts @@ -30,6 +30,10 @@ export class SessionResource extends CachedDataResource { const { session } = await this.graphQLService.gql.openSession(); diff --git a/webapp/packages/core-sdk/src/queries/session/serverConfig.gql b/webapp/packages/core-sdk/src/queries/session/serverConfig.gql index f79600e364..1315778c05 100644 --- a/webapp/packages/core-sdk/src/queries/session/serverConfig.gql +++ b/webapp/packages/core-sdk/src/queries/session/serverConfig.gql @@ -6,8 +6,13 @@ query serverConfig { supportsCustomConnections supportsConnectionBrowser supportsWorkspaces + anonymousAccessEnabled authenticationEnabled + + configurationMode + developmentMode + supportedLanguages { isoCode displayName diff --git a/webapp/packages/core-sdk/src/sdk.ts b/webapp/packages/core-sdk/src/sdk.ts index 2af765f092..cf26f636c1 100644 --- a/webapp/packages/core-sdk/src/sdk.ts +++ b/webapp/packages/core-sdk/src/sdk.ts @@ -1271,7 +1271,7 @@ export type ReadSessionLogQuery = { log: Array; export type ServerConfigQuery = { serverConfig: ( - Pick + Pick & { supportedLanguages: Array>; defaultNavigatorSettings: Pick } ); }; @@ -2117,6 +2117,8 @@ export const ServerConfigDocument = ` supportsWorkspaces anonymousAccessEnabled authenticationEnabled + configurationMode + developmentMode supportedLanguages { isoCode displayName diff --git a/webapp/packages/core-theming/package.json b/webapp/packages/core-theming/package.json index d3012794fa..264588f6c0 100644 --- a/webapp/packages/core-theming/package.json +++ b/webapp/packages/core-theming/package.json @@ -20,7 +20,8 @@ "@material/radio": "^4.0.0", "@material/ripple": "^4.0.0", "@material/theme": "^4.0.0", - "@material/typography": "^4.0.0" + "@material/typography": "^4.0.0", + "@material/switch": "^4.0.0" }, "peerDependencies": { "@cloudbeaver/core-di": "^0.1.0", diff --git a/webapp/packages/core-theming/src/styles/_mixins.scss b/webapp/packages/core-theming/src/styles/_mixins.scss index e6055bb20b..11193d9aa8 100644 --- a/webapp/packages/core-theming/src/styles/_mixins.scss +++ b/webapp/packages/core-theming/src/styles/_mixins.scss @@ -20,6 +20,7 @@ @import 'tag'; @import 'button'; @import 'radio'; +@import 'switch'; @import 'tabs'; @import 'table'; @import 'placeholder'; diff --git a/webapp/packages/core-theming/src/styles/_switch.scss b/webapp/packages/core-theming/src/styles/_switch.scss new file mode 100644 index 0000000000..3efede43a7 --- /dev/null +++ b/webapp/packages/core-theming/src/styles/_switch.scss @@ -0,0 +1,44 @@ +/* + * cloudbeaver - Cloud Database Manager + * Copyright (C) 2020 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 '@material/switch/mixins'; + +@mixin switch-core-styles($query: mdc-feature-all()) { + @include mdc-switch-core-styles($query); + + .theme-switch { + composes: mdc-switch; + } + .theme-switch_native-control { + composes: mdc-switch__native-control; + } + .theme-switch__track { + composes: mdc-switch__track; + } + .theme-switch__thumb-underlay { + composes: mdc-switch__thumb-underlay; + } + .theme-switch__thumb { + composes: mdc-switch__thumb; + } + .theme-switch--checked { + composes: mdc-switch--checked; + } + .theme-switch--disabled { + composes: mdc-switch--disabled; + } + + .theme-switch_primary { + $mdc-switch-baseline-theme-color: primary; + + @include mdc-switch-toggled-on-track-color($mdc-switch-baseline-theme-color, $query); + @include mdc-switch-toggled-on-thumb-color($mdc-switch-baseline-theme-color, $query); + @include mdc-switch-toggled-off-track-color($mdc-switch-toggled-off-track-color, $query); + @include mdc-switch-toggled-off-thumb-color($mdc-switch-toggled-off-thumb-color, $query); + } +} \ No newline at end of file diff --git a/webapp/packages/core-theming/src/styles/theme-dark.module.scss b/webapp/packages/core-theming/src/styles/theme-dark.module.scss index b27cc09a7c..e19839cc23 100644 --- a/webapp/packages/core-theming/src/styles/theme-dark.module.scss +++ b/webapp/packages/core-theming/src/styles/theme-dark.module.scss @@ -16,6 +16,7 @@ @include table; @include button-core-styles; @include radio-core-styles; +@include switch-core-styles; @include form-controls; @include placeholder; @include delimiter($mdc-theme-secondary); diff --git a/webapp/packages/core-theming/src/styles/theme-light.module.scss b/webapp/packages/core-theming/src/styles/theme-light.module.scss index 697d1093c8..71d0533c3f 100644 --- a/webapp/packages/core-theming/src/styles/theme-light.module.scss +++ b/webapp/packages/core-theming/src/styles/theme-light.module.scss @@ -16,6 +16,7 @@ @include table; @include button-core-styles; @include radio-core-styles; +@include switch-core-styles; @include form-controls; @include placeholder; @include delimiter($mdc-theme-secondary); diff --git a/webapp/packages/core-theming/src/useStyles.ts b/webapp/packages/core-theming/src/useStyles.ts index c08de54bcb..c8bdaf8fd5 100644 --- a/webapp/packages/core-theming/src/useStyles.ts +++ b/webapp/packages/core-theming/src/useStyles.ts @@ -26,29 +26,29 @@ export type Style = BaseStyles | ThemeSelector * @param componentStyles styles array */ export function useStyles( - ...componentStyles: Array