refactor: CB-338 forms, tabs, styles

This commit is contained in:
Wroud
2020-10-15 00:35:23 +03:00
parent 4b002c3059
commit 4d24969a35
32 changed files with 536 additions and 464 deletions
@@ -6,22 +6,14 @@
* you may not use this file except in compliance with the License.
*/
import styled, { css } from 'reshadow';
const styles = css`
administration-tools {
height: 48px;
}
`;
type Props = React.PropsWithChildren<{
interface Props {
className?: string;
}>;
}
export function AdministrationTools({ children, className }: Props) {
return styled(styles)(
export const AdministrationTools: React.FC<Props> = function AdministrationTools({ children, className }) {
return (
<administration-tools as='div' className={className}>
{children}
</administration-tools>
);
}
};
@@ -0,0 +1,35 @@
/*
* 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 { css } from 'reshadow';
import { composes } from '@cloudbeaver/core-theming';
export const ADMINISTRATION_TOOLS_STYLES = composes(
css`
AdministrationTools {
composes: theme-background-surface theme-text-on-surface theme-border-color-background from global;
}
`,
css`
AdministrationTools {
padding: 0 16px;
display: flex;
align-items: center;
border-bottom: solid 1px;
height: 48px;
& IconButton {
height: 32px;
width: 32px;
margin-right: 16px;
}
}
`
);
@@ -1,4 +1,5 @@
export * from './Administration/AdministrationTools/AdministrationTools';
export * from './Administration/AdministrationTools/AdministrationToolsStyles';
export * from './AdministrationItem/AdministrationItemService';
export * from './AdministrationItem/IAdministrationItem';
export * from './AdministrationScreen/AdministrationScreenService';
@@ -39,6 +39,9 @@ const checkboxStyles = composes(
display: flex;
align-items: center;
}
checkbox-label {
composes: theme-typography--body2 from global;
}
`
);
@@ -0,0 +1,29 @@
/*
* 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 styled, { css } from 'reshadow';
const styles = css`
box {
flex: 1;
display: flex;
flex-wrap: wrap;
}
`;
interface Props {
className?: string;
}
export const FormBox: React.FC<Props> = function FormBox({ children, className }) {
return styled(styles)(
<box as='div' className={className}>
{children}
</box>
);
};
@@ -0,0 +1,27 @@
/*
* 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 styled, { css } from 'reshadow';
const styles = css`
box-element {
min-width: 450px;
}
`;
interface Props {
className?: string;
}
export const FormBoxElement: React.FC<Props> = function FormBoxElement({ children, className }) {
return styled(styles)(
<box-element as='div' className={className}>
{children}
</box-element>
);
};
@@ -0,0 +1,28 @@
/*
* 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 styled, { css } from 'reshadow';
const styles = css`
group {
box-sizing: border-box;
display: flex;
}
`;
interface Props {
className?: string;
}
export const FormGroup: React.FC<Props> = function FormGroup({ children, className }) {
return styled(styles)(
<group as='div' className={className}>
{children}
</group>
);
};
@@ -18,6 +18,7 @@ import { FormContext } from './FormContext';
type BaseProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'name' | 'value'> & {
mod?: 'surface';
long?: boolean;
short?: boolean;
};
type ControlledProps = BaseProps & {
@@ -50,6 +51,7 @@ export const InputField: InputFieldType = observer(function InputField({
className,
mod,
long,
short,
onChange,
...rest
}: ControlledProps | ObjectProps<any, any>) {
@@ -70,7 +72,7 @@ export const InputField: InputFieldType = observer(function InputField({
const value = state ? state[name] : valueControlled;
return styled(useStyles(baseFormControlStyles))(
<field as="div" className={className} {...use({ long })}>
<field as="div" className={className} {...use({ long, short })}>
<field-label as='label'>{children} {required && '*'}</field-label>
<input
{...rest}
@@ -21,7 +21,7 @@ const styles = composes(
css`
field-label {
composes: theme-typography--body2 from global;
margin-left: 150px;
margin-left: 180px;
text-align: left;
font-weight: initial;
padding-bottom: 8px;
@@ -34,19 +34,19 @@ const styles = composes(
}
`
);
type Props = React.PropsWithChildren<{
interface Props {
className?: string;
long?: boolean;
}>;
}
export function InputGroup({
export const InputGroup: React.FC<Props> = function InputGroup({
children,
className,
long,
}: Props) {
}) {
return styled(useStyles(baseFormControlStyles, styles))(
<field as="div" className={className}>
<field-label as='label' {...use({ long })}>{children}</field-label>
</field>
);
}
};
@@ -37,6 +37,9 @@ const switchStyles = composes(
}
`,
css`
field {
max-width: 450px;
}
field label {
width: auto;
}
@@ -28,9 +28,9 @@ export const baseFormControlStyles = css`
field-label {
composes: theme-typography--body1 from global;
box-sizing: border-box;
width: 150px;
width: 180px;
text-align: right;
padding-right: 24px;
padding: 0 16px;
line-height: 16px;
font-weight: 500;
}
@@ -50,4 +50,13 @@ export const baseFormControlStyles = css`
padding-left: 200px;
}
}
field[|short] {
& field-label {
width: auto;
}
& field-description {
padding-left: auto;
}
}
`;
@@ -0,0 +1,39 @@
/*
* 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 { css } from 'reshadow';
export const BORDER_TAB_STYLES = css`
TabList {
align-items: center;
box-sizing: border-box;
display: inline-flex;
width: 100%;
padding-left: 24px;
outline: none;
}
TabPanel {
overflow: auto !important;
}
Tab {
composes: theme-typography--body2 from global;
text-transform: uppercase;
font-weight: normal;
&:global([aria-selected=true]) {
font-weight: normal !important;
}
& TabTitle {
padding: 0 24px !important;
}
}
`
;
@@ -1,3 +1,4 @@
export * from './BorderTabStyles';
export * from './Tab';
export * from './TabIcon';
export * from './TabTitle';
+3
View File
@@ -16,8 +16,11 @@ export * from './Button';
export * from './FormControls/Checkboxes/Checkbox';
export * from './FormControls/Checkboxes/FieldCheckbox';
export * from './FormControls/Checkboxes/CheckboxMarkup';
export * from './FormControls/FormBox';
export * from './FormControls/FormBoxElement';
export * from './FormControls/Combobox';
export * from './FormControls/FormContext';
export * from './FormControls/FormGroup';
export * from './FormControls/InputField';
export * from './FormControls/InputGroup';
export * from './FormControls/Radio';
@@ -12,7 +12,7 @@ import styled, { css } from 'reshadow';
import {
TabsState, TabList, Tab,
TabTitle, Loader, TabPanel,
ErrorMessage, Button
Button, BORDER_TAB_STYLES
} from '@cloudbeaver/core-blocks';
import { useController } from '@cloudbeaver/core-di';
import { useTranslate } from '@cloudbeaver/core-localization';
@@ -30,10 +30,6 @@ const styles = composes(
composes: theme-ripple theme-background-secondary theme-text-on-secondary from global;
}
ErrorMessage {
composes: theme-background-secondary from global;
}
TabList {
composes: theme-background-surface theme-text-on-surface from global;
}
@@ -71,33 +67,6 @@ const styles = composes(
flex-direction: column;
}
TabList {
align-items: center;
box-sizing: border-box;
display: inline-flex;
width: 100%;
padding-left: 24px;
outline: none;
}
TabPanel {
overflow: auto !important;
}
Tab {
composes: theme-typography--body2 from global;
text-transform: uppercase;
font-weight: normal;
&:global([aria-selected=true]) {
font-weight: normal !important;
}
& TabTitle {
padding: 0 24px !important;
}
}
fill {
flex: 1;
}
@@ -127,7 +96,7 @@ export const ConnectionForm = observer(function ConnectionForm({
const controller = useController(Controller, model, onCancel);
const translate = useTranslate();
return styled(useStyles(styles))(
return styled(useStyles(styles, BORDER_TAB_STYLES))(
<TabsState selectedId='options'>
<box as='div'>
<TabList>
@@ -14,14 +14,13 @@ import {
InputField,
useFocus,
ObjectPropertyInfoForm,
Checkbox,
Textarea,
InputGroup,
RadioGroup,
TabsState,
TabPanel,
Combobox,
SubmittingForm, FieldCheckbox
SubmittingForm, FieldCheckbox, FormBox, FormBoxElement, FormGroup
} from '@cloudbeaver/core-blocks';
import { useController } from '@cloudbeaver/core-di';
import { useTranslate } from '@cloudbeaver/core-localization';
@@ -48,14 +47,6 @@ const styles = css`
flex-direction: column;
flex: 1;
}
box {
flex: 1;
display: flex;
flex-wrap: wrap;
}
box-element {
min-width: 450px;
}
TabPanel {
flex-direction: column;
}
@@ -75,9 +66,9 @@ export const Options = observer(function Options({
return styled(useStyles(styles, formStyles))(
<SubmittingForm ref={focusedRef} onChange={controller.onFormChange} onSubmit={onSave}>
<box as="div">
<box-element as='div'>
<group as="div">
<FormBox>
<FormBoxElement>
<FormGroup>
<FieldCheckbox
name="template"
value={model.connection.id}
@@ -86,8 +77,8 @@ export const Options = observer(function Options({
disabled={model.editing || disabled}
mod='surface'
/>
</group>
<group as="div">
</FormGroup>
<FormGroup>
<Combobox
name='driverId'
state={model.connection}
@@ -101,8 +92,8 @@ export const Options = observer(function Options({
>
{translate('connections_connection_driver')}
</Combobox>
</group>
<group as="div">
</FormGroup>
<FormGroup>
<InputField
type="text"
name="name"
@@ -112,8 +103,8 @@ export const Options = observer(function Options({
>
{translate('connections_connection_name')}
</InputField>
</group>
<group as="div">
</FormGroup>
<FormGroup>
<Textarea
name="description"
rows={3}
@@ -123,9 +114,9 @@ export const Options = observer(function Options({
>
{translate('connections_connection_description')}
</Textarea>
</group>
</box-element>
<box-element as='div'>
</FormGroup>
</FormBoxElement>
<FormBoxElement>
<connection-type as="div">
<RadioGroup name='type' value={type} onChange={onTypeChange}>
<Radio value={EConnectionType.Parameters} disabled={disabled} mod={['primary']}>
@@ -145,7 +136,7 @@ export const Options = observer(function Options({
/>
</TabPanel>
<TabPanel tabId={EConnectionType.URL}>
<group as="div">
<FormGroup>
<InputField
type="text"
name="url"
@@ -156,14 +147,14 @@ export const Options = observer(function Options({
>
{translate('customConnection_url_JDBC')}
</InputField>
</group>
</FormGroup>
</TabPanel>
</TabsState>
{(controller.authModel && !controller.driver?.anonymousAccess) && (
<>
<group as="div">
<FormGroup>
<InputGroup>{translate('connections_connection_edit_authentication')}</InputGroup>
</group>
</FormGroup>
<ObjectPropertyInfoForm
autofillToken='new-password'
properties={controller.authModel.properties}
@@ -171,7 +162,7 @@ export const Options = observer(function Options({
disabled={disabled}
onFocus={controller.resetPassword}
/>
<group as="div">
<FormGroup>
<FieldCheckbox
name="saveCredentials"
value={model.connection.id + 'authNeeded'}
@@ -180,11 +171,11 @@ export const Options = observer(function Options({
disabled={disabled}
mod='surface'
/>
</group>
</FormGroup>
</>
)}
</box-element>
</box>
</FormBoxElement>
</FormBox>
</SubmittingForm>
);
});
@@ -9,7 +9,7 @@
import { observer } from 'mobx-react';
import styled, { use, css } from 'reshadow';
import { InputField } from '@cloudbeaver/core-blocks';
import { FormGroup, InputField } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import { ConnectionInfo } from '@cloudbeaver/core-sdk';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -24,7 +24,7 @@ interface ParametersFormProps {
const styles = css`
layout-grid-inner {
max-width: 650px;
max-width: 630px;
}
`;
@@ -39,7 +39,7 @@ export const ParametersForm = observer(function ParametersForm({
<>
{!embedded && (
<layout-grid-inner as="div">
<layout-grid-cell as='div' {...use({ 'span-tablet': 12, 'span-desktop': 7 })}>
<layout-grid-cell as='div' {...use({ 'span-tablet': 12, 'span-desktop': 8 })}>
<InputField
type="text"
name="host"
@@ -51,21 +51,21 @@ export const ParametersForm = observer(function ParametersForm({
<sub-label as="div">{translate('customConnection_custom_obligatory')}</sub-label>
</InputField>
</layout-grid-cell>
<layout-grid-cell as='div' {...use({ 'span-tablet': 12, 'span-desktop': 5 })}>
<layout-grid-cell as='div' {...use({ 'span-tablet': 12, 'span-desktop': 4 })}>
<InputField
type="number"
name="port"
state={connection}
disabled={disabled}
{...use({ short: true })}
mod='surface'
short
>
{translate('customConnection_custom_port')}
</InputField>
</layout-grid-cell>
</layout-grid-inner>
)}
<group as="div">
<FormGroup>
<InputField
type="text"
name="databaseName"
@@ -75,7 +75,7 @@ export const ParametersForm = observer(function ParametersForm({
>
{translate('customConnection_custom_database')}
</InputField>
</group>
</FormGroup>
</>
);
});
@@ -28,8 +28,4 @@ export const formStyles = css`
composes: theme-typography--caption from global;
line-height: 14px;
}
group {
box-sizing: border-box;
display: flex;
}
`;
@@ -9,7 +9,7 @@
import { observer } from 'mobx-react';
import styled, { css, use } from 'reshadow';
import { AdministrationTools, AdministrationItemContentProps } from '@cloudbeaver/core-administration';
import { AdministrationTools, AdministrationItemContentProps, ADMINISTRATION_TOOLS_STYLES } from '@cloudbeaver/core-administration';
import { Loader, IconButton } from '@cloudbeaver/core-blocks';
import { useController } from '@cloudbeaver/core-di';
import { Translate } from '@cloudbeaver/core-localization';
@@ -21,7 +21,7 @@ import { CreateConnection } from './CreateConnection/CreateConnection';
const styles = composes(
css`
AdministrationTools, layout-grid-cell {
layout-grid-cell {
composes: theme-background-surface theme-text-on-surface from global;
}
@@ -50,15 +50,7 @@ const styles = composes(
}
AdministrationTools {
display: flex;
padding: 0 16px;
align-items: center;
}
IconButton {
height: 32px;
width: 32px;
margin-right: 16px;
border: none;
}
actions {
@@ -80,7 +72,7 @@ export const ConnectionsAdministration: React.FC<AdministrationItemContentProps>
}) {
const controller = useController(ConnectionsAdministrationController);
return styled(useStyles(styles))(
return styled(useStyles(styles, ADMINISTRATION_TOOLS_STYLES))(
<layout-grid as="div">
<layout-grid-inner as="div">
<layout-grid-cell as='div' {...use({ span: 12 })}>
@@ -7,11 +7,11 @@
*/
import { observer } from 'mobx-react';
import { useMemo, useEffect, useCallback } from 'react';
import { useEffect, useCallback } from 'react';
import styled, { css } from 'reshadow';
import {
TabsState, TabList, Tab, TabTitle, IconButton, Loader, StaticImage, Icon
TabsState, TabList, Tab, TabTitle, IconButton, Loader, StaticImage, Icon, BORDER_TAB_STYLES
} from '@cloudbeaver/core-blocks';
import { useController } from '@cloudbeaver/core-di';
import { useTranslate } from '@cloudbeaver/core-localization';
@@ -52,7 +52,7 @@ const styles = composes(
connection-create {
display: flex;
flex-direction: column;
height: 550px;
height: 570px;
overflow: hidden;
}
@@ -116,33 +116,6 @@ const styles = composes(
width: 16px;
}
}
TabList {
align-items: center;
box-sizing: border-box;
display: inline-flex;
padding-left: 24px;
outline: none;
flex: auto 0 0;
}
TabPanel {
overflow: auto !important;
}
Tab {
composes: theme-typography--body2 from global;
text-transform: uppercase;
font-weight: normal;
&:global([aria-selected=true]) {
font-weight: normal !important;
}
& TabTitle {
padding: 0 24px !important;
}
}
`
);
@@ -192,7 +165,7 @@ export const CreateConnection = observer(function CreateConnection({
);
}
return styled(style)(
return styled(style, BORDER_TAB_STYLES)(
<connection-create as='div'>
<TabsState currentTabId={method} onChange={onChange}>
<title-bar as='div'>
@@ -2,3 +2,4 @@ export * from './ExecutionContext';
export * from './Executor';
export * from './IExecutor';
export * from './IExecutorHandler';
export * from './useFormValidator';
@@ -0,0 +1,39 @@
/*
* 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 { useCallback, useEffect, useRef } from 'react';
import { IExecutor } from './IExecutor';
export function useFormValidator(
validationTask: IExecutor<boolean>,
ref: React.RefObject<HTMLFormElement>,
callback?: () => void
): void {
const callbackRef = useRef(callback);
callbackRef.current = callback;
const validate = useCallback(() => {
ref.current?.checkValidity();
ref.current?.reportValidity();
if (callbackRef.current) {
callbackRef.current();
}
}, [ref]);
useEffect(() => {
if (!validationTask) {
return;
}
validationTask.addHandler(validate);
return () => validationTask.removeHandler(validate);
}, [validationTask, validate]);
}
@@ -0,0 +1,57 @@
/*
* 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 { FormGroup, InputGroup, InputField } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import { ServerConfigInput } from '@cloudbeaver/core-sdk';
interface Props {
serverConfig: ServerConfigInput;
}
export const ServerConfigurationAdminForm: React.FC<Props> = observer(function ServerConfigurationAdminForm({
serverConfig,
}) {
const translate = useTranslate();
return (
<>
<FormGroup>
<InputGroup long>{translate('administration_configuration_wizard_configuration_admin')}</InputGroup>
</FormGroup>
<FormGroup>
<InputField
type="text"
name="adminName"
state={serverConfig}
mod='surface'
minLength={6}
required
long
>
{translate('administration_configuration_wizard_configuration_admin_name')}
</InputField>
</FormGroup>
<FormGroup>
<InputField
type="password"
name="adminPassword"
state={serverConfig}
autoComplete='new-password'
mod='surface'
required
long
>
{translate('administration_configuration_wizard_configuration_admin_password')}
</InputField>
</FormGroup>
</>
);
});
@@ -0,0 +1,65 @@
/*
* 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 { FormGroup, InputGroup, Switch } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import { ServerConfigInput } from '@cloudbeaver/core-sdk';
interface Props {
serverConfig: ServerConfigInput;
}
export const ServerConfigurationConfigurationForm: React.FC<Props> = observer(function ServerConfigurationConfigurationForm({
serverConfig,
}) {
const translate = useTranslate();
return (
<>
<FormGroup>
<InputGroup long>{translate('administration_configuration_wizard_configuration_plugins')}</InputGroup>
</FormGroup>
<FormGroup>
<Switch
name="anonymousAccessEnabled"
state={serverConfig}
description={translate('administration_configuration_wizard_configuration_anonymous_access_description')}
mod={['primary']}
disabled={!serverConfig.authenticationEnabled}
long
>
{translate('administration_configuration_wizard_configuration_anonymous_access')}
</Switch>
</FormGroup>
<FormGroup>
<Switch
name="authenticationEnabled"
state={serverConfig}
description={translate('administration_configuration_wizard_configuration_authentication_description')}
mod={['primary']}
long
>
{translate('administration_configuration_wizard_configuration_authentication')}
</Switch>
</FormGroup>
<FormGroup>
<Switch
name="customConnectionsEnabled"
state={serverConfig}
description={translate('administration_configuration_wizard_configuration_custom_connections_description')}
mod={['primary']}
long
>
{translate('administration_configuration_wizard_configuration_custom_connections')}
</Switch>
</FormGroup>
</>
);
});
@@ -0,0 +1,55 @@
/*
* 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 { FormGroup, InputGroup, InputField } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import { ServerConfigInput } from '@cloudbeaver/core-sdk';
interface Props {
serverConfig: ServerConfigInput;
}
export const ServerConfigurationInfoForm: React.FC<Props> = observer(function ServerConfigurationInfoForm({
serverConfig,
}) {
const translate = useTranslate();
return (
<>
<FormGroup>
<InputGroup long>{translate('administration_configuration_wizard_configuration_server_info')}</InputGroup>
</FormGroup>
<FormGroup>
<InputField
type="text"
name='serverName'
state={serverConfig}
mod='surface'
required
long
>
{translate('administration_configuration_wizard_configuration_server_name')}
</InputField>
</FormGroup>
<FormGroup>
<InputField
type="number"
name='sessionExpireTime'
state={serverConfig}
mod='surface'
required
long
>
{translate('administration_configuration_wizard_configuration_server_session_expire_time')}
</InputField>
</FormGroup>
</>
);
});
@@ -1,188 +0,0 @@
/*
* 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, useEffect } from 'react';
import styled, { css } from 'reshadow';
import {
SubmittingForm, InputGroup, InputField, useFocus, Switch, Button
} from '@cloudbeaver/core-blocks';
import { IExecutor } from '@cloudbeaver/core-executor';
import { useTranslate } from '@cloudbeaver/core-localization';
import { ServerConfigInput } from '@cloudbeaver/core-sdk';
import { useStyles } from '@cloudbeaver/core-theming';
export const formStyles = css`
SubmittingForm {
flex: 1;
display: flex;
overflow: auto;
flex-direction: row;
}
group {
box-sizing: border-box;
display: flex;
}
Button {
margin: 12px;
margin-left: 24px;
float: right;
}
`;
const boxStyles = css`
box {
flex: 1;
display: flex;
flex-wrap: wrap;
}
box-element {
width: 450px;
}
`;
interface Props {
serverConfig: ServerConfigInput;
validationTask?: IExecutor<boolean>;
editing?: boolean;
className?: string;
onChange: () => void;
onSubmit: () => void;
}
export const ServerConfigurationForm: React.FC<Props> = observer(function ServerConfigurationForm({
serverConfig,
validationTask,
editing,
className,
onChange,
onSubmit,
}) {
const translate = useTranslate();
const [focusedRef] = useFocus<HTMLFormElement>({ focusFirstChild: true });
const validate = useCallback(() => {
focusedRef.current?.checkValidity();
focusedRef.current?.reportValidity();
}, []);
useEffect(() => {
if (!validationTask) {
return;
}
validationTask.addHandler(validate);
return () => validationTask.removeHandler(validate);
}, [validationTask]);
return styled(useStyles(formStyles, boxStyles))(
<SubmittingForm ref={focusedRef} name='server_config' className={className} onSubmit={onSubmit}>
<box as="div">
<box-element as='div'>
<group as="div">
<InputGroup long>{translate('administration_configuration_wizard_configuration_server_info')}</InputGroup>
</group>
<group as="div">
<InputField
type="text"
name='serverName'
state={serverConfig}
mod='surface'
required
long
>
{translate('administration_configuration_wizard_configuration_server_name')}
</InputField>
</group>
<group as="div">
<InputField
type="number"
name='sessionExpireTime'
state={serverConfig}
mod='surface'
required
long
>
{translate('administration_configuration_wizard_configuration_server_session_expire_time')}
</InputField>
</group>
{!editing && (
<>
<group as="div">
<InputGroup long>{translate('administration_configuration_wizard_configuration_admin')}</InputGroup>
</group>
<InputField
type="text"
name="adminName"
state={serverConfig}
mod='surface'
minLength={6}
required
long
>
{translate('administration_configuration_wizard_configuration_admin_name')}
</InputField>
<InputField
type="password"
name="adminPassword"
state={serverConfig}
autoComplete='new-password'
mod='surface'
required
long
>
{translate('administration_configuration_wizard_configuration_admin_password')}
</InputField>
</>
)}
</box-element>
<box-element as='div'>
<group as="div">
<InputGroup long>{translate('administration_configuration_wizard_configuration_plugins')}</InputGroup>
</group>
<group as="div">
<Switch
name="anonymousAccessEnabled"
state={serverConfig}
description={translate('administration_configuration_wizard_configuration_anonymous_access_description')}
mod={['primary']}
disabled={!serverConfig.authenticationEnabled}
long
>
{translate('administration_configuration_wizard_configuration_anonymous_access')}
</Switch>
</group>
<group as="div">
<Switch
name="authenticationEnabled"
state={serverConfig}
description={translate('administration_configuration_wizard_configuration_authentication_description')}
mod={['primary']}
long
onChange={onChange}
>
{translate('administration_configuration_wizard_configuration_authentication')}
</Switch>
</group>
<group as="div">
<Switch
name="customConnectionsEnabled"
state={serverConfig}
description={translate('administration_configuration_wizard_configuration_custom_connections_description')}
mod={['primary']}
long
>
{translate('administration_configuration_wizard_configuration_custom_connections')}
</Switch>
</group>
</box-element>
</box>
</SubmittingForm>
);
});
@@ -9,19 +9,22 @@
import { observer } from 'mobx-react';
import styled, { use, css } from 'reshadow';
import { AdministrationTools } from '@cloudbeaver/core-administration';
import { IconButton } from '@cloudbeaver/core-blocks';
import { AdministrationTools, ADMINISTRATION_TOOLS_STYLES } from '@cloudbeaver/core-administration';
import { FormBox, FormBoxElement, IconButton, SubmittingForm, useFocus } from '@cloudbeaver/core-blocks';
import { useController, useService } from '@cloudbeaver/core-di';
import { useFormValidator } from '@cloudbeaver/core-executor';
import { useTranslate } from '@cloudbeaver/core-localization';
import { useStyles, composes } from '@cloudbeaver/core-theming';
import { ServerConfigurationForm } from './ServerConfigurationForm';
import { ServerConfigurationAdminForm } from './Form/ServerConfigurationAdminForm';
import { ServerConfigurationConfigurationForm } from './Form/ServerConfigurationConfigurationForm';
import { ServerConfigurationInfoForm } from './Form/ServerConfigurationInfoForm';
import { ServerConfigurationPageController } from './ServerConfigurationPageController';
import { ServerConfigurationService } from './ServerConfigurationService';
const styles = composes(
css`
AdministrationTools, layout-grid-cell {
layout-grid-cell {
composes: theme-background-surface theme-text-on-surface theme-border-color-background from global;
}
@@ -44,25 +47,19 @@ const styles = composes(
border: solid 1px;
}
message-box, AdministrationTools {
message-box {
border-bottom: solid 1px;
}
message-box, ServerConfigurationForm {
message-box, SubmittingForm {
padding: 16px 24px;
}
AdministrationTools {
SubmittingForm {
flex: 1;
display: flex;
padding: 0 16px;
align-items: center;
border-bottom: solid 1px;
}
IconButton {
height: 32px;
width: 32px;
margin-right: 16px;
overflow: auto;
flex-direction: row;
}
p {
@@ -73,10 +70,12 @@ const styles = composes(
export const ServerConfigurationPage = observer(function ServerConfigurationPage() {
const translate = useTranslate();
const [focusedRef] = useFocus<HTMLFormElement>({ focusFirstChild: true });
const service = useService(ServerConfigurationService);
const controller = useController(ServerConfigurationPageController);
useFormValidator(service.validationTask, focusedRef);
return styled(useStyles(styles))(
return styled(useStyles(styles, ADMINISTRATION_TOOLS_STYLES))(
<layout-grid as="div">
<layout-grid-inner as="div">
<layout-grid-cell as='div' {...use({ span: 12 })}>
@@ -91,13 +90,17 @@ export const ServerConfigurationPage = observer(function ServerConfigurationPage
<IconButton name="admin-cancel" viewBox="0 0 28 28" onClick={controller.reset} />
</AdministrationTools>
)}
<ServerConfigurationForm
serverConfig={controller.state.serverConfig}
validationTask={service.validationTask}
editing={controller.editing}
onChange={controller.change}
onSubmit={controller.save}
/>
<SubmittingForm ref={focusedRef} name='server_config' onSubmit={controller.save} onChange={controller.change}>
<FormBox>
<FormBoxElement>
<ServerConfigurationInfoForm serverConfig={controller.state.serverConfig} />
{!controller.editing && <ServerConfigurationAdminForm serverConfig={controller.state.serverConfig} />}
</FormBoxElement>
<FormBoxElement>
<ServerConfigurationConfigurationForm serverConfig={controller.state.serverConfig} />
</FormBoxElement>
</FormBox>
</SubmittingForm>
</layout-grid-cell>
</layout-grid-inner>
</layout-grid>
@@ -1,3 +1,7 @@
import { manifest } from './manifest';
export default manifest;
export * from './ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationAdminForm';
export * from './ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationConfigurationForm';
export * from './ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationInfoForm';
@@ -17,7 +17,7 @@ import {
InputField,
FieldCheckbox,
useFocus,
InputGroup
InputGroup, FormBox, FormBoxElement, FormGroup, BORDER_TAB_STYLES
} from '@cloudbeaver/core-blocks';
import { useController } from '@cloudbeaver/core-di';
import { useTranslate } from '@cloudbeaver/core-localization';
@@ -41,7 +41,7 @@ const styles = composes(
composes: theme-background-secondary from global;
}
box {
FormBox {
composes: theme-background-secondary theme-text-on-secondary from global;
}
@@ -60,33 +60,6 @@ const styles = composes(
flex-direction: column;
}
TabList {
align-items: center;
box-sizing: border-box;
display: inline-flex;
width: 100%;
padding-left: 24px;
outline: none;
}
TabPanel {
overflow: auto !important;
}
Tab {
composes: theme-typography--body2 from global;
text-transform: uppercase;
font-weight: normal;
&:global([aria-selected=true]) {
font-weight: normal !important;
}
& TabTitle {
padding: 0 24px !important;
}
}
ErrorMessage {
position: sticky;
bottom: 0;
@@ -111,16 +84,6 @@ const styles = composes(
flex: 1;
width: 100%;
}
flex-box {
flex: 1;
display: flex;
flex-wrap: wrap;
}
flex-box-element {
min-width: 450px;
}
`
);
@@ -156,7 +119,7 @@ export const UserForm = observer(function UserForm({
[]
);
return styled(useStyles(styles))(
return styled(useStyles(styles, BORDER_TAB_STYLES))(
<TabsState selectedId='info'>
<box as='div'>
<TabList>
@@ -187,12 +150,12 @@ export const UserForm = observer(function UserForm({
<content-box as='div'>
<SubmittingForm ref={focusedRef} onSubmit={controller.save}>
<TabPanel tabId='info'>
<flex-box as="div">
<flex-box-element as='div'>
<group as="div">
<FormBox>
<FormBoxElement>
<FormGroup>
<InputGroup>{translate('authentication_user_credentials')}</InputGroup>
</group>
<group as="div">
</FormGroup>
<FormGroup>
<InputField
type='text'
name='login'
@@ -204,8 +167,8 @@ export const UserForm = observer(function UserForm({
>
{translate('authentication_user_name')}
</InputField>
</group>
<group as="div">
</FormGroup>
<FormGroup>
<InputField
type='password'
name='password'
@@ -218,8 +181,8 @@ export const UserForm = observer(function UserForm({
>
{translate('authentication_user_password')}
</InputField>
</group>
<group as="div">
</FormGroup>
<FormGroup>
<InputField
type='password'
name='password_repeat'
@@ -231,14 +194,14 @@ export const UserForm = observer(function UserForm({
>
{translate('authentication_user_password_repeat')}
</InputField>
</group>
</flex-box-element>
<flex-box-element as='div'>
<group as="div">
</FormGroup>
</FormBoxElement>
<FormBoxElement>
<FormGroup>
<InputGroup>{translate('authentication_user_role')}</InputGroup>
</group>
</FormGroup>
{controller.roles.map((role, i) => (
<group key={role.roleId} as="div">
<FormGroup key={role.roleId}>
<FieldCheckbox
value={role.roleId}
name='role'
@@ -248,10 +211,10 @@ export const UserForm = observer(function UserForm({
mod='surface'
onChange={checked => handleRoleChange(role.roleId, checked)}
/>
</group>
</FormGroup>
))}
</flex-box-element>
</flex-box>
</FormBoxElement>
</FormBox>
</TabPanel>
{controller.isLoading && <Loader overlay />}
<TabPanel tabId='connections_access'>
@@ -9,7 +9,7 @@
import { observer } from 'mobx-react';
import styled, { css, use } from 'reshadow';
import { AdministrationTools, AdministrationItemContentProps } from '@cloudbeaver/core-administration';
import { AdministrationTools, AdministrationItemContentProps, ADMINISTRATION_TOOLS_STYLES } from '@cloudbeaver/core-administration';
import { Loader, IconButton } from '@cloudbeaver/core-blocks';
import { useController } from '@cloudbeaver/core-di';
import { useStyles, composes } from '@cloudbeaver/core-theming';
@@ -21,7 +21,7 @@ import { UsersTable } from './UsersTable/UsersTable';
const styles = composes(
css`
AdministrationTools, layout-grid-cell {
layout-grid-cell {
composes: theme-background-surface theme-text-on-surface from global;
}
@@ -44,15 +44,7 @@ const styles = composes(
}
AdministrationTools {
display: flex;
padding: 0 16px;
align-items: center;
}
IconButton {
height: 32px;
width: 32px;
margin-right: 16px;
border: none;
}
`
);
@@ -66,7 +58,7 @@ export const UsersAdministration = observer(function UsersAdministration({
controller.create();
}
return styled(useStyles(styles))(
return styled(useStyles(styles, ADMINISTRATION_TOOLS_STYLES))(
<layout-grid as="div">
<layout-grid-inner as="div">
<layout-grid-cell as='div' {...use({ span: 12 })}>
@@ -30,29 +30,34 @@ export const ParametersForm = observer(function ParametersForm({
return styled(useStyles(formStyles))(
<>
{!embedded && (
<group as="div">
<InputField
type="text"
name="host"
value={controller.config.host}
disabled={controller.isConnecting}
mod='surface'
onChange={value => controller.onChange('host', value)}
>
{translate('customConnection_custom_host')}
<sub-label as="div">{translate('customConnection_custom_obligatory')}</sub-label>
</InputField>
<InputField
type="number"
name="port"
value={controller.config.port}
disabled={controller.isConnecting}
mod='surface'
onChange={value => controller.onChange('port', value)}
>
{translate('customConnection_custom_port')}
</InputField>
</group>
<layout-grid-inner as="div">
<layout-grid-cell as='div' {...use({ 'span-tablet': 12, 'span-desktop': 8 })}>
<InputField
type="text"
name="host"
value={controller.config.host}
disabled={controller.isConnecting}
mod='surface'
onChange={value => controller.onChange('host', value)}
>
{translate('customConnection_custom_host')}
<sub-label as="div">{translate('customConnection_custom_obligatory')}</sub-label>
</InputField>
</layout-grid-cell>
<layout-grid-cell as='div' {...use({ 'span-tablet': 12, 'span-desktop': 4 })}>
<InputField
type="number"
name="port"
value={controller.config.port}
disabled={controller.isConnecting}
mod='surface'
short
onChange={value => controller.onChange('port', value)}
>
{translate('customConnection_custom_port')}
</InputField>
</layout-grid-cell>
</layout-grid-inner>
)}
<group as="div">
<InputField
@@ -11,7 +11,7 @@ import { useState } from 'react';
import styled, { css } from 'reshadow';
import {
SubmittingForm, ErrorMessage, TabsState, TabList, Tab, TabTitle, TabPanel, Loader
SubmittingForm, ErrorMessage, TabsState, TabList, Tab, TabTitle, TabPanel, Loader, BORDER_TAB_STYLES
} from '@cloudbeaver/core-blocks';
import { DBDriver } from '@cloudbeaver/core-connections';
import { useController } from '@cloudbeaver/core-di';
@@ -43,29 +43,12 @@ const styles = composes(
max-height: 550px;
min-height: 550px;
}
SubmittingForm, BaseTabPanel {
SubmittingForm {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
TabList {
box-sizing: border-box;
display: inline-flex;
width: 100%;
padding-left: 24px;
outline: none;
}
Tab {
composes: theme-typography--body2 from global;
text-transform: uppercase;
font-weight: normal;
&:global([aria-selected=true]) {
font-weight: normal !important;
}
}
ErrorMessage {
position: sticky;
bottom: 0;
@@ -91,7 +74,7 @@ export const ConnectionFormDialog = observer(function ConnectionFormDialog({
const controller = useController(ConnectionFormDialogController, driver, onClose);
const [loadProperties, setLoadProperties] = useState(false);
return styled(useStyles(styles))(
return styled(useStyles(styles, BORDER_TAB_STYLES))(
<TabsState selectedId='options'>
<CommonDialogWrapper
title={title}