Merge pull request #510 from dbeaver/fix/remove-html-sanitizer

fix(core-blocks): CB-218, CB-1321 remove html-sanitizer and old compo…
This commit is contained in:
Alexey
2021-10-14 17:04:44 +03:00
committed by GitHub
58 changed files with 632 additions and 1803 deletions
@@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite';
import { useCallback } from 'react';
import styled, { css } from 'reshadow';
import { Button, TextareaNew, useClipboard } from '@cloudbeaver/core-blocks';
import { Button, Textarea, useClipboard } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import type { ILogEntry } from './ILogEntry';
@@ -53,7 +53,7 @@ const styles = css`
type, message {
margin-bottom: 12px;
}
TextareaNew {
Textarea {
flex: 1;
}
`;
@@ -91,7 +91,7 @@ export const LogViewerInfoPanel = observer<Props>(function LogViewerInfoPanel({
<content-wrapper>
<type as='h2'>{typeInfo}</type>
<message title={selectedItem.message}>{selectedItem.message}</message>
<TextareaNew
<Textarea
name="value"
rows={3}
value={selectedItem.stackTrace}
+1 -3
View File
@@ -15,9 +15,7 @@
"lint-fix": "eslint ./src/ --ext .ts,.tsx --fix"
},
"dependencies": {
"go-split": "^2.x.x",
"sanitize-html": "^1.x.x",
"react-sanitized-html": "^2.x.x"
"go-split": "^2.x.x"
},
"peerDependencies": {
"@cloudbeaver/core-di": "^0.1.0",
@@ -121,17 +121,17 @@ export const CheckboxMarkup: React.FC<ICheckboxMarkupProps> = function CheckboxM
style
)
)(
<checkbox-container className={className} title={title} as='div'>
<checkbox as='div'>
<checkbox-container className={className} title={title}>
<checkbox>
<checkbox-input as='input' type='checkbox' {...rest} id={id || rest.name} />
<checkbox-background as='div'>
<checkbox-background>
<checkbox-checkmark as='svg' viewBox='0 0 24 24'>
<checkbox-checkmark-path as='path' fill='none' d='M1.73,12.91 8.1,19.28 22.79,4.59' />
</checkbox-checkmark>
<checkbox-mixedmark as='div' />
<checkbox-mixedmark />
</checkbox-background>
{ripple && (
<checkbox-ripple as='div' />
<checkbox-ripple />
)}
</checkbox>
{label && (id || rest.name) && <checkbox-label as='label' htmlFor={id || rest.name}>{label}</checkbox-label>}
@@ -14,10 +14,25 @@ import { baseFormControlStyles } from '../baseFormControlStyles';
import { isControlPresented } from '../isControlPresented';
import { Checkbox, CheckboxBaseProps, CheckboxType, ICheckboxControlledProps, ICheckboxObjectProps } from './Checkbox';
const fieldCheckboxStyles = css`
const style = css`
Checkbox {
margin: -10px;
}
field {
display: flex;
align-items: flex-end;
white-space: pre-wrap;
}
field-label {
composes: theme-typography--body2 from global;
cursor: pointer;
user-select: none;
padding-left: 10px;
line-height: 16px;
}
Checkbox[disabled] + field-label {
cursor: auto;
}
`;
export const FieldCheckbox: CheckboxType = function FieldCheckbox({
@@ -25,16 +40,22 @@ export const FieldCheckbox: CheckboxType = function FieldCheckbox({
className,
...rest
}: CheckboxBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps<any>)) {
const styles = useStyles(baseFormControlStyles, fieldCheckboxStyles);
const styles = useStyles(baseFormControlStyles, style);
if (rest.autoHide && !isControlPresented(rest.name, rest.state)) {
return null;
}
return styled(styles)(
<field className={className} as="div">
<field-label as="div">{children}</field-label>
<field className={className}>
<Checkbox {...(rest as CheckboxBaseProps & ICheckboxControlledProps)} />
<field-label
htmlFor={rest.id || rest.name}
title={rest.title}
as="label"
>
{children}
</field-label>
</field>
);
};
@@ -1,61 +0,0 @@
/*
* 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 styled, { css } from 'reshadow';
import { useStyles } from '@cloudbeaver/core-theming';
import { baseFormControlStylesNew } from '../baseFormControlStylesNew';
import { isControlPresented } from '../isControlPresented';
import { Checkbox, CheckboxBaseProps, CheckboxType, ICheckboxControlledProps, ICheckboxObjectProps } from './Checkbox';
const fieldCheckboxStyles = css`
Checkbox {
margin: -10px;
}
field {
display: flex;
align-items: flex-end;
white-space: pre-wrap;
}
field-label {
composes: theme-typography--body2 from global;
cursor: pointer;
user-select: none;
padding-left: 10px;
line-height: 16px;
}
Checkbox[disabled] + field-label {
cursor: auto;
}
`;
export const FieldCheckboxNew: CheckboxType = function FieldCheckboxNew({
children,
className,
...rest
}: CheckboxBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps<any>)) {
const styles = useStyles(baseFormControlStylesNew, fieldCheckboxStyles);
if (rest.autoHide && !isControlPresented(rest.name, rest.state)) {
return null;
}
return styled(styles)(
<field className={className}>
<Checkbox {...(rest as CheckboxBaseProps & ICheckboxControlledProps)} />
<field-label
htmlFor={rest.id || rest.name}
title={rest.title}
as="label"
>
{children}
</field-label>
</field>
);
};
@@ -11,6 +11,7 @@ import styled, { css } from 'reshadow';
import { useStyles, composes } from '@cloudbeaver/core-theming';
import { filterLayoutFakeProps } from '../../Containers/filterLayoutFakeProps';
import { baseFormControlStyles } from '../baseFormControlStyles';
import { isControlPresented } from '../isControlPresented';
import type { ICheckboxControlledProps, ICheckboxObjectProps } from './Checkbox';
@@ -18,34 +19,39 @@ import { useCheckboxState } from './useCheckboxState';
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;
}
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 {
max-width: 450px;
switch-body {
display: flex;
align-items: center;
}
field label {
width: auto;
}
switch-control {
margin-left: 2px;
field-label {
composes: theme-typography--body1 from global;
cursor: pointer;
user-select: none;
display: block;
padding-left: 18px;
min-width: 50px;
white-space: pre-wrap;
font-weight: 500;
}
`
);
@@ -79,7 +85,7 @@ const switchState = {
interface IBaseProps {
mod?: Array<keyof typeof switchMod>;
description?: string;
description?: React.ReactNode;
}
interface SwitchType {
@@ -91,7 +97,6 @@ export const Switch: SwitchType = observer(function Switch({
name,
value,
defaultValue,
label,
description,
state,
checked,
@@ -113,6 +118,7 @@ export const Switch: SwitchType = observer(function Switch({
name,
onChange,
});
rest = filterLayoutFakeProps(rest);
const styles = useStyles(
baseFormControlStyles,
switchStyles,
@@ -126,27 +132,28 @@ export const Switch: SwitchType = observer(function Switch({
}
return styled(styles)(
<field as="div" className={className}>
<field-label as="div">{children}</field-label>
<switch-control as='div'>
<switch-control-track as='div' />
<switch-control-underlay as='div'>
<switch-control-thumb as='div' />
<switch-input
as='input'
{...rest}
type="checkbox"
id={value || name}
role="switch"
aria-checked={checkboxState.checked}
checked={checkboxState.checked}
disabled={disabled}
onChange={checkboxState.change}
/>
</switch-control-underlay>
</switch-control>
<label htmlFor={value || name}>{label}</label>
<field-description as='div'>{description}</field-description>
<field className={className}>
<switch-body>
<switch-control>
<switch-control-track />
<switch-control-underlay>
<switch-control-thumb />
<switch-input
as='input'
{...rest}
type="checkbox"
id={value || name}
role="switch"
aria-checked={checkboxState.checked}
checked={checkboxState.checked}
disabled={disabled}
onChange={checkboxState.change}
/>
</switch-control-underlay>
</switch-control>
<field-label as="label" htmlFor={value || name}>{children}</field-label>
</switch-body>
<field-description>{description}</field-description>
</field>
);
});
@@ -1,159 +0,0 @@
/*
* 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 styled, { css } from 'reshadow';
import { useStyles, composes } from '@cloudbeaver/core-theming';
import { filterLayoutFakeProps } from '../../Containers/filterLayoutFakeProps';
import { baseFormControlStylesNew } from '../baseFormControlStylesNew';
import { isControlPresented } from '../isControlPresented';
import type { ICheckboxControlledProps, ICheckboxObjectProps } from './Checkbox';
import { useCheckboxState } from './useCheckboxState';
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`
switch-body {
display: flex;
align-items: center;
}
field-label {
composes: theme-typography--body1 from global;
cursor: pointer;
user-select: none;
display: block;
padding-left: 18px;
min-width: 50px;
white-space: pre-wrap;
font-weight: 500;
}
`
);
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;
}
`
),
};
interface IBaseProps {
mod?: Array<keyof typeof switchMod>;
description?: React.ReactNode;
}
interface SwitchType {
(props: IBaseProps & ICheckboxControlledProps): React.ReactElement<any, any> | null;
<TKey extends string>(props: IBaseProps & ICheckboxObjectProps<TKey>): React.ReactElement<any, any> | null;
}
export const SwitchNew: SwitchType = observer(function SwitchNew({
name,
value,
defaultValue,
description,
state,
checked,
defaultChecked,
className,
children,
onChange,
mod = [],
autoHide,
disabled,
...rest
}: IBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps<any>)) {
const checkboxState = useCheckboxState({
value,
defaultValue,
checked,
defaultChecked,
state,
name,
onChange,
});
rest = filterLayoutFakeProps(rest);
const styles = useStyles(
baseFormControlStylesNew,
switchStyles,
...mod.map(mod => switchMod[mod]),
disabled && switchState.disabled,
checkboxState.checked && switchState.checked
);
if (autoHide && !isControlPresented(name, state)) {
return null;
}
return styled(styles)(
<field className={className}>
<switch-body>
<switch-control>
<switch-control-track />
<switch-control-underlay>
<switch-control-thumb />
<switch-input
as='input'
{...rest}
type="checkbox"
id={value || name}
role="switch"
aria-checked={checkboxState.checked}
checked={checkboxState.checked}
disabled={disabled}
onChange={checkboxState.change}
/>
</switch-control-underlay>
</switch-control>
<field-label as="label" htmlFor={value || name}>{children}</field-label>
</switch-body>
<field-description>{description}</field-description>
</field>
);
});
@@ -8,7 +8,7 @@
import { observer } from 'mobx-react-lite';
import {
useLayoutEffect, useCallback, useState, useRef, useContext
useLayoutEffect, useCallback, useState, useRef, useContext, useEffect
} from 'react';
import {
useMenuState,
@@ -20,6 +20,8 @@ import styled, { css, use } from 'reshadow';
import { useStyles, composes } from '@cloudbeaver/core-theming';
import { filterLayoutFakeProps } from '../Containers/filterLayoutFakeProps';
import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps';
import { Icon } from '../Icon';
import { IconButton } from '../IconButton';
import { baseFormControlStyles } from './baseFormControlStyles';
@@ -30,7 +32,7 @@ const styles = composes(
Menu {
composes: theme-text-on-surface theme-background-surface from global;
}
MenuItem, MenuButton {
MenuItem {
composes: theme-ripple from global;
}
`,
@@ -38,11 +40,25 @@ const styles = composes(
field input {
margin: 0;
}
field-label {
display: block;
padding-bottom: 10px;
composes: theme-typography--body1 from global;
font-weight: 500;
}
input {
padding-right: 12px !important;
}
MenuButton {
position: absolute;
right: 0;
background: transparent;
outline: none;
padding: 4px;
cursor: pointer;
&:hover {
opacity: 0.7;
}
}
Menu {
@@ -59,7 +75,7 @@ const styles = composes(
& MenuItem {
background: transparent;
display: block;
padding: 4px 36px;
padding: 4px 12px;
text-align: left;
outline: none;
color: inherit;
@@ -82,12 +98,11 @@ const styles = composes(
`
);
type BaseProps<TKey, TValue> = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'onSelect' | 'name' | 'value'> & {
type BaseProps<TKey, TValue> = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'onSelect' | 'name' | 'value' | 'defaultValue'> & ILayoutSizeProps & {
propertyName?: string;
items: TValue[];
mod?: 'surface';
long?: boolean;
searchable?: boolean;
defaultValue?: string;
keySelector: (item: TValue) => TKey;
valueSelector: (item: TValue) => string;
onSwitch?: (state: boolean) => void;
@@ -98,7 +113,6 @@ type ControlledProps<TKey, TValue> = BaseProps<TKey, TValue> & {
value?: string;
onSelect?: (value: TKey, name: string | undefined, prev: TKey) => void;
onChange?: (value: string, name: string | undefined) => any;
state?: never;
};
@@ -107,7 +121,6 @@ type ObjectProps<TValue, TKey extends keyof TState, TState> = BaseProps<TState[T
state: TState;
onSelect?: (value: TState[TKey], name: TKey | undefined, prev: TState[TKey]) => void;
onChange?: (value: string, name: TKey | undefined) => any;
value?: never;
};
@@ -118,6 +131,7 @@ interface ComboboxType {
export const Combobox: ComboboxType = observer(function Combobox({
value: controlledValue,
defaultValue,
name,
state,
propertyName,
@@ -125,10 +139,9 @@ export const Combobox: ComboboxType = observer(function Combobox({
children,
title,
className,
mod,
long,
searchable,
readOnly,
disabled,
keySelector = v => v,
valueSelector = v => v,
onChange = () => {},
@@ -136,6 +149,7 @@ export const Combobox: ComboboxType = observer(function Combobox({
onSwitch,
...rest
}: ControlledProps<any, any> | ObjectProps<any, any, any>) {
rest = filterLayoutFakeProps(rest);
const context = useContext(FormContext);
const ref = useRef<HTMLInputElement>(null);
const menu = useMenuState({
@@ -143,15 +157,19 @@ export const Combobox: ComboboxType = observer(function Combobox({
currentId: null,
gutter: 4,
});
const [searchValue, setSearchValue] = useState('');
let value: string | number | readonly string[] | undefined = controlledValue;
const [searchValue, setSearchValue] = useState<string | null>(null);
let value: string | number | readonly string[] | undefined = controlledValue ?? defaultValue ?? undefined;
if (state) {
if (name in state) {
value = state[name];
} else if (rest.defaultValue !== undefined) {
value = rest.defaultValue;
}
if (state && name !== undefined && name in state) {
value = state[name];
}
const selectedItem = items.find(item => keySelector(item) === value);
let inputValue = (selectedItem ? valueSelector(selectedItem) : searchValue) ?? '';
if (searchValue !== null && selectedItem && valueSelector(selectedItem) !== searchValue) {
inputValue = searchValue;
}
const handleChange = useCallback(
@@ -175,7 +193,7 @@ export const Combobox: ComboboxType = observer(function Combobox({
if (context) {
context.change(null, name);
}
setSearchValue('');
setSearchValue(null);
},
[value, state, name, menu, context, onSelect]
);
@@ -193,55 +211,55 @@ export const Combobox: ComboboxType = observer(function Combobox({
if (context) {
context.change(id, name);
}
setSearchValue(null);
},
[value, state, name, menu, context, onSelect]
);
useEffect(() => {
if (ref.current === document.activeElement && inputValue === searchValue) {
menu.show();
}
});
useLayoutEffect(() => onSwitch?.(menu.visible), [onSwitch, menu.visible]);
const selectedItem = items.find(item => keySelector(item) === value);
const filteredItems = items.filter(
item => selectedItem || !searchValue || valueSelector(item).toUpperCase().includes(searchValue.toUpperCase())
item => !searchValue || valueSelector(item).toUpperCase().includes(searchValue.toUpperCase())
);
if (ref.current === document.activeElement && !selectedItem && searchValue) {
menu.show();
}
return styled(useStyles(baseFormControlStyles, styles))(
<field as="div" className={className} {...use({ long })}>
<field-label title={title} as='label'>{children}</field-label>
<input-box as="div">
<field className={className}>
<field-label title={title} as='label'>{children}{rest.required && ' *'}</field-label>
<input-box>
<input
ref={ref}
role='new'
autoComplete="off"
name={name}
title={title}
value={selectedItem ? valueSelector(selectedItem) : searchValue}
readOnly={!!selectedItem || readOnly}
value={inputValue}
disabled={disabled}
readOnly={readOnly}
onChange={handleChange}
{...use({ mod })}
{...rest}
/>
{(selectedItem && !readOnly && searchable) && (
<IconButton type="button" name="reject" viewBox="0 0 11 11" onClick={handleRemove} />
)}
{!readOnly && (
<>
<MenuButton {...menu}><Icon name="arrow" viewBox="0 0 16 16" {...use({ focus: menu.visible })} /></MenuButton>
<Menu
{...menu}
aria-label={propertyName}
unstable_initialFocusRef={ref}
unstable_finalFocusRef={ref}
>
{filteredItems.map(item => (
<MenuItem key={keySelector(item)} id={keySelector(item)} type='button' {...menu} onClick={handleMenuSelect}>
{valueSelector(item)}
</MenuItem>
))}
</Menu>
</>
)}
<MenuButton {...menu} disabled={readOnly || disabled}><Icon name="arrow" viewBox="0 0 16 16" {...use({ focus: menu.visible })} /></MenuButton>
<Menu
{...menu}
aria-label={propertyName}
unstable_initialFocusRef={ref}
unstable_finalFocusRef={ref}
>
{filteredItems.map(item => (
<MenuItem key={keySelector(item)} id={keySelector(item)} type='button' {...menu} onClick={handleMenuSelect}>
{valueSelector(item)}
</MenuItem>
))}
</Menu>
</input-box>
</field>
);
@@ -1,266 +0,0 @@
/*
* 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 {
useLayoutEffect, useCallback, useState, useRef, useContext, useEffect
} from 'react';
import {
useMenuState,
Menu,
MenuItem,
MenuButton
} from 'reakit/Menu';
import styled, { css, use } from 'reshadow';
import { useStyles, composes } from '@cloudbeaver/core-theming';
import { filterLayoutFakeProps } from '../Containers/filterLayoutFakeProps';
import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps';
import { Icon } from '../Icon';
import { IconButton } from '../IconButton';
import { baseFormControlStylesNew } from './baseFormControlStylesNew';
import { FormContext } from './FormContext';
const styles = composes(
css`
Menu {
composes: theme-text-on-surface theme-background-surface from global;
}
MenuItem {
composes: theme-ripple from global;
}
`,
css`
field input {
margin: 0;
}
field-label {
display: block;
padding-bottom: 10px;
composes: theme-typography--body1 from global;
font-weight: 500;
}
input {
padding-right: 12px !important;
}
MenuButton {
position: absolute;
right: 0;
background: transparent;
outline: none;
padding: 4px;
cursor: pointer;
&:hover {
opacity: 0.7;
}
}
Menu {
composes: theme-typography--caption theme-elevation-z3 from global;
display: flex;
flex-direction: column;
width: 100%;
max-height: 150px;
overflow: auto;
outline: none;
padding: 4px 0;
z-index: 999;
& MenuItem {
background: transparent;
display: block;
padding: 4px 12px;
text-align: left;
outline: none;
color: inherit;
cursor: pointer;
}
}
Icon {
height: 16px;
display: block;
}
MenuButton Icon[|focus] {
transform: rotate(180deg);
}
input-box {
flex: 1;
position: relative;
display: flex;
align-items: center;
}
`
);
type BaseProps<TKey, TValue> = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'onSelect' | 'name' | 'value' | 'defaultValue'> & ILayoutSizeProps & {
propertyName?: string;
items: TValue[];
searchable?: boolean;
defaultValue?: string;
keySelector: (item: TValue) => TKey;
valueSelector: (item: TValue) => string;
onSwitch?: (state: boolean) => void;
};
type ControlledProps<TKey, TValue> = BaseProps<TKey, TValue> & {
name?: string;
value?: string;
onSelect?: (value: TKey, name: string | undefined, prev: TKey) => void;
onChange?: (value: string, name: string | undefined) => any;
state?: never;
};
type ObjectProps<TValue, TKey extends keyof TState, TState> = BaseProps<TState[TKey], TValue> & {
name: TKey;
state: TState;
onSelect?: (value: TState[TKey], name: TKey | undefined, prev: TState[TKey]) => void;
onChange?: (value: string, name: TKey | undefined) => any;
value?: never;
};
interface ComboboxType {
<TKey, TValue>(props: ControlledProps<TKey, TValue>): JSX.Element;
<TValue, TKey extends keyof TState, TState>(props: ObjectProps<TValue, TKey, TState>): JSX.Element;
}
export const ComboboxNew: ComboboxType = observer(function ComboboxNew({
value: controlledValue,
defaultValue,
name,
state,
propertyName,
items,
children,
title,
className,
searchable,
readOnly,
disabled,
keySelector = v => v,
valueSelector = v => v,
onChange = () => {},
onSelect,
onSwitch,
...rest
}: ControlledProps<any, any> | ObjectProps<any, any, any>) {
rest = filterLayoutFakeProps(rest);
const context = useContext(FormContext);
const ref = useRef<HTMLInputElement>(null);
const menu = useMenuState({
placement: 'bottom-end',
currentId: null,
gutter: 4,
});
const [searchValue, setSearchValue] = useState<string | null>(null);
let value: string | number | readonly string[] | undefined = controlledValue ?? defaultValue ?? undefined;
if (state && name !== undefined && name in state) {
value = state[name];
}
const selectedItem = items.find(item => keySelector(item) === value);
let inputValue = (selectedItem ? valueSelector(selectedItem) : searchValue) ?? '';
if (searchValue !== null && selectedItem && valueSelector(selectedItem) !== searchValue) {
inputValue = searchValue;
}
const handleChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value;
onChange(value, name);
setSearchValue(value);
},
[name, onChange]
);
const handleRemove = useCallback(
() => {
menu.hide();
if (state) {
state[name] = null;
}
if (onSelect) {
onSelect(null, name, value);
}
if (context) {
context.change(null, name);
}
setSearchValue(null);
},
[value, state, name, menu, context, onSelect]
);
const handleMenuSelect = useCallback(
(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
menu.hide();
const id = event.currentTarget.id;
if (state) {
state[name] = id;
}
if (onSelect) {
onSelect(id, name, value);
}
if (context) {
context.change(id, name);
}
setSearchValue(null);
},
[value, state, name, menu, context, onSelect]
);
useEffect(() => {
if (ref.current === document.activeElement && inputValue === searchValue) {
menu.show();
}
});
useLayoutEffect(() => onSwitch?.(menu.visible), [onSwitch, menu.visible]);
const filteredItems = items.filter(
item => !searchValue || valueSelector(item).toUpperCase().includes(searchValue.toUpperCase())
);
return styled(useStyles(baseFormControlStylesNew, styles))(
<field className={className}>
<field-label title={title} as='label'>{children}{rest.required && ' *'}</field-label>
<input-box>
<input
ref={ref}
role='new'
autoComplete="off"
name={name}
title={title}
value={inputValue}
disabled={disabled}
readOnly={readOnly}
onChange={handleChange}
{...rest}
/>
{(selectedItem && !readOnly && searchable) && (
<IconButton type="button" name="reject" viewBox="0 0 11 11" onClick={handleRemove} />
)}
<MenuButton {...menu} disabled={readOnly || disabled}><Icon name="arrow" viewBox="0 0 16 16" {...use({ focus: menu.visible })} /></MenuButton>
<Menu
{...menu}
aria-label={propertyName}
unstable_initialFocusRef={ref}
unstable_finalFocusRef={ref}
>
{filteredItems.map(item => (
<MenuItem key={keySelector(item)} id={keySelector(item)} type='button' {...menu} onClick={handleMenuSelect}>
{valueSelector(item)}
</MenuItem>
))}
</Menu>
</input-box>
</field>
);
});
@@ -14,7 +14,7 @@ import { composes, useStyles } from '@cloudbeaver/core-theming';
import { IconButton } from '../IconButton';
import { useFocus } from '../useFocus';
import { InputFieldNew } from './InputFieldNew';
import { InputField } from './InputField';
const styles = css`
filter-container {
@@ -22,7 +22,7 @@ const styles = css`
min-width: 24px;
min-height: 24px;
}
InputFieldNew {
InputField {
display: none;
width: 300px;
&[|max] {
@@ -148,7 +148,7 @@ export const Filter = observer<ControlledProps | ObjectsProps<any, any>>(functio
return styled(useStyles(styles, toggleMode && toggleModeButtonStyle))(
<filter-container className={className}>
<InputFieldNew
<InputField
ref={inputRef}
style={innerInputStyle}
placeholder={placeholder}
@@ -6,32 +6,37 @@
* you may not use this file except in compliance with the License.
*/
import styled, { use } from 'reshadow';
import styled, { css } from 'reshadow';
import { useStyles } from '@cloudbeaver/core-theming';
import { baseFormControlStyles } from './baseFormControlStyles';
const style = css`
field-label {
composes: theme-typography--body1 from global;
font-weight: 500;
}
`;
interface Props {
label?: string;
long?: boolean;
short?: boolean;
raw?: boolean;
title?: string;
className?: string;
}
export const FormFieldDescription: React.FC<Props> = function FormFieldDescription({
label,
long,
short,
raw,
title,
children,
className,
}) {
return styled(useStyles(baseFormControlStyles))(
<field as='div' className={className} {...use({ long, short, raw })}>
const styles = useStyles(baseFormControlStyles, style);
return styled(styles)(
<field title={title} className={className}>
{label && <field-label as='label'>{label}</field-label>}
<field-description as='div'>
<field-description>
{children}
</field-description>
</field>
@@ -1,45 +0,0 @@
/*
* 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 styled from 'reshadow';
import { css } from 'reshadow';
import { useStyles } from '@cloudbeaver/core-theming';
import { baseFormControlStylesNew } from './baseFormControlStylesNew';
const formFieldDescriptionNewStyles = css`
field-label {
composes: theme-typography--body1 from global;
font-weight: 500;
}
`;
interface Props {
label?: string;
title?: string;
className?: string;
}
export const FormFieldDescriptionNew: React.FC<Props> = function FormFieldDescriptionNew({
label,
title,
children,
className,
}) {
const styles = useStyles(baseFormControlStylesNew, formFieldDescriptionNewStyles);
return styled(styles)(
<field title={title} as='div' className={className}>
{label && <field-label as='label'>{label}</field-label>}
<field-description as='div'>
{children}
</field-description>
</field>
);
};
@@ -7,26 +7,73 @@
*/
import { observer } from 'mobx-react-lite';
import { useCallback, useContext } from 'react';
import styled, { use } from 'reshadow';
import { useCallback, useContext, useState } from 'react';
import styled, { use, css } from 'reshadow';
import { useStyles } from '@cloudbeaver/core-theming';
import { useTranslate } from '@cloudbeaver/core-localization';
import { ComponentStyle, composes, useStyles } from '@cloudbeaver/core-theming';
import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps';
import { Icon } from '../Icon';
import { baseFormControlStyles } from './baseFormControlStyles';
import { FormContext } from './FormContext';
import { isControlPresented } from './isControlPresented';
type BaseProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'name' | 'value'> & {
const INPUT_FIELD_STYLES = composes(
css`
Icon {
composes: theme-text-on-secondary from global;
}
`,
css`
field-label {
display: block;
composes: theme-typography--body1 from global;
font-weight: 500;
}
field-label:not(:empty) {
padding-bottom: 10px;
}
input-container {
position: relative;
}
icon-container {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
display: flex;
width: 24px;
height: 24px;
cursor: pointer;
& Icon {
width: 100%;
height: 100%;
}
}
input[disabled] + icon-container {
cursor: auto;
opacity: 0.8;
}
input:not(:only-child) {
padding-right: 32px !important;
}
`);
type BaseProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'name' | 'value'> & ILayoutSizeProps & {
description?: string;
mod?: 'surface';
long?: boolean;
short?: boolean;
ref?: React.Ref<HTMLInputElement>;
style?: ComponentStyle;
onCustomCopy?: () => void;
};
type ControlledProps = BaseProps & {
name?: string;
value?: string;
onChange?: (value: string, name?: string) => any;
value?: string | number;
mapState?: (value: string | number) => string | number;
mapValue?: (value: string | number) => string | number;
onChange?: (value: string | number, name?: string) => any;
state?: never;
autoHide?: never;
};
@@ -34,7 +81,9 @@ type ControlledProps = BaseProps & {
type ObjectProps<TKey extends keyof TState, TState> = BaseProps & {
name: TKey;
state: TState;
onChange?: (value: string, name: TKey) => any;
mapState?: (value: TState[TKey]) => TState[TKey] | string | number;
mapValue?: (value: TState[TKey]) => TState[TKey];
onChange?: (value: TState[TKey], name: TKey) => any;
autoHide?: boolean;
value?: never;
};
@@ -46,61 +95,107 @@ interface InputFieldType {
export const InputField: InputFieldType = observer(function InputField({
name,
style,
value: valueControlled,
defaultValue,
required,
state,
mapState,
mapValue,
children,
className,
description,
mod,
long,
short,
fill,
small,
medium,
large,
tiny,
autoHide,
onChange,
onCustomCopy,
...rest
}: ControlledProps | ObjectProps<any, any>) {
const styles = useStyles(baseFormControlStyles);
}: ControlledProps | ObjectProps<any, any>, ref: React.Ref<HTMLInputElement>) {
const [passwordRevealed, setPasswordRevealed] = useState(false);
const translate = useTranslate();
const styles = useStyles(baseFormControlStyles, INPUT_FIELD_STYLES, style);
const context = useContext(FormContext);
const revealPassword = useCallback(() => {
if (rest.disabled) {
return;
}
setPasswordRevealed(prev => !prev);
}, [rest.disabled]);
const handleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const value = mapValue?.(event.target.value) ?? event.target.value;
if (state) {
state[name] = event.target.value;
state[name] = value;
}
if (onChange) {
onChange(event.target.value, name);
onChange(value, name);
}
if (context) {
context.change(event.target.value, name);
context.change(value, name);
}
}, [state, name, context, onChange]);
if (autoHide && !isControlPresented(name, state, defaultValue)) {
return null;
}
let value: any = valueControlled ?? defaultValue ?? undefined;
if (state && name !== undefined && name in state) {
value = state[name];
}
if (autoHide && !isControlPresented(name, state, defaultValue)) {
return null;
if (mapState) {
value = mapState(value);
}
const showRevealPasswordButton = rest.type === 'password' && !rest.readOnly;
return styled(styles)(
<field as="div" className={className} {...use({ long, short })}>
<field-label as='label' title={rest.title}>{children} {required && '*'}</field-label>
<input
{...rest}
name={name}
value={value ?? ''}
onChange={handleChange}
{...use({ mod })}
required={required}
/>
<field className={className} {...use({ small, medium, large, tiny })}>
<field-label title={rest.title}>{children}{required && ' *'}</field-label>
<input-container>
<input
ref={ref}
role='new'
{...rest}
type={passwordRevealed ? 'text' : rest.type}
name={name}
value={value ?? ''}
onChange={handleChange}
{...use({ mod })}
required={required}
/>
{showRevealPasswordButton && (
<icon-container
title={translate('ui_reveal_password')}
onClick={revealPassword}
>
<Icon
name={passwordRevealed ? 'password-hide' : 'password-show'}
viewBox='0 0 16 16'
/>
</icon-container>
)}
{onCustomCopy && (
<icon-container title={translate('ui_copy_to_clipboard')} onClick={onCustomCopy}>
<Icon name="copy" viewBox='0 0 32 32' />
</icon-container>
)}
</input-container>
{description && (
<field-description as='div'>
<field-description>
{description}
</field-description>
)}
</field>
);
});
}, { forwardRef: true });
@@ -1,201 +0,0 @@
/*
* 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 { useCallback, useContext, useState } from 'react';
import styled, { use, css } from 'reshadow';
import { useTranslate } from '@cloudbeaver/core-localization';
import { ComponentStyle, composes, useStyles } from '@cloudbeaver/core-theming';
import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps';
import { Icon } from '../Icon';
import { baseFormControlStylesNew } from './baseFormControlStylesNew';
import { FormContext } from './FormContext';
import { isControlPresented } from './isControlPresented';
const INPUT_FIELD_STYLES = composes(
css`
Icon {
composes: theme-text-on-secondary from global;
}
`,
css`
field-label {
display: block;
composes: theme-typography--body1 from global;
font-weight: 500;
}
field-label:not(:empty) {
padding-bottom: 10px;
}
input-container {
position: relative;
}
icon-container {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
display: flex;
width: 24px;
height: 24px;
cursor: pointer;
& Icon {
width: 100%;
height: 100%;
}
}
input[disabled] + icon-container {
cursor: auto;
opacity: 0.8;
}
input:not(:only-child) {
padding-right: 32px !important;
}
`);
type BaseProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'name' | 'value'> & ILayoutSizeProps & {
description?: string;
mod?: 'surface';
ref?: React.Ref<HTMLInputElement>;
style?: ComponentStyle;
onCustomCopy?: () => void;
};
type ControlledProps = BaseProps & {
name?: string;
value?: string | number;
mapState?: (value: string | number) => string | number;
mapValue?: (value: string | number) => string | number;
onChange?: (value: string | number, name?: string) => any;
state?: never;
autoHide?: never;
};
type ObjectProps<TKey extends keyof TState, TState> = BaseProps & {
name: TKey;
state: TState;
mapState?: (value: TState[TKey]) => TState[TKey] | string | number;
mapValue?: (value: TState[TKey]) => TState[TKey];
onChange?: (value: TState[TKey], name: TKey) => any;
autoHide?: boolean;
value?: never;
};
interface InputFieldType {
(props: ControlledProps): React.ReactElement<any, any> | null;
<TKey extends keyof TState, TState>(props: ObjectProps<TKey, TState>): React.ReactElement<any, any> | null;
}
export const InputFieldNew: InputFieldType = observer(function InputFieldNew({
name,
style,
value: valueControlled,
defaultValue,
required,
state,
mapState,
mapValue,
children,
className,
description,
mod,
fill,
small,
medium,
large,
tiny,
autoHide,
onChange,
onCustomCopy,
...rest
}: ControlledProps | ObjectProps<any, any>, ref: React.Ref<HTMLInputElement>) {
const [passwordRevealed, setPasswordRevealed] = useState(false);
const translate = useTranslate();
const styles = useStyles(baseFormControlStylesNew, INPUT_FIELD_STYLES, style);
const context = useContext(FormContext);
const revealPassword = useCallback(() => {
if (rest.disabled) {
return;
}
setPasswordRevealed(prev => !prev);
}, [rest.disabled]);
const handleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const value = mapValue?.(event.target.value) ?? event.target.value;
if (state) {
state[name] = value;
}
if (onChange) {
onChange(value, name);
}
if (context) {
context.change(value, name);
}
}, [state, name, context, onChange]);
if (autoHide && !isControlPresented(name, state, defaultValue)) {
return null;
}
let value: any = valueControlled ?? defaultValue ?? undefined;
if (state && name !== undefined && name in state) {
value = state[name];
}
if (mapState) {
value = mapState(value);
}
const showRevealPasswordButton = rest.type === 'password' && !rest.readOnly;
return styled(styles)(
<field className={className} {...use({ small, medium, large, tiny })}>
<field-label title={rest.title}>{children}{required && ' *'}</field-label>
<input-container>
<input
ref={ref}
role='new'
{...rest}
type={passwordRevealed ? 'text' : rest.type}
name={name}
value={value ?? ''}
onChange={handleChange}
{...use({ mod })}
required={required}
/>
{showRevealPasswordButton && (
<icon-container
title={translate('ui_reveal_password')}
onClick={revealPassword}
>
<Icon
name={passwordRevealed ? 'password-hide' : 'password-show'}
viewBox='0 0 16 16'
/>
</icon-container>
)}
{onCustomCopy && (
<icon-container title={translate('ui_copy_to_clipboard')} onClick={onCustomCopy}>
<Icon name="copy" viewBox='0 0 32 32' />
</icon-container>
)}
</input-container>
{description && (
<field-description>
{description}
</field-description>
)}
</field>
);
}, { forwardRef: true });
@@ -1,52 +0,0 @@
/*
* 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 styled, { css, use } from 'reshadow';
import { useStyles, composes } from '@cloudbeaver/core-theming';
import { baseFormControlStyles } from './baseFormControlStyles';
const styles = composes(
css`
field-label {
composes: theme-border-color-background from global;
}
`,
css`
field-label {
composes: theme-typography--body2 from global;
margin-left: 180px;
text-align: left;
font-weight: initial;
padding-bottom: 8px;
border-bottom: solid 1px #dedede;
width: 100%;
&[|long] {
margin-left: 200px;
}
}
`
);
interface Props {
className?: string;
long?: boolean;
}
export const InputGroup: React.FC<Props> = function InputGroup({
children,
className,
long,
}) {
return styled(useStyles(baseFormControlStyles, styles))(
<field as="div" className={className}>
<field-label as='label' {...use({ long })}>{children}</field-label>
</field>
);
};
@@ -10,8 +10,9 @@ import { observer } from 'mobx-react-lite';
import { useCallback, useContext } from 'react';
import styled, { css, use } from 'reshadow';
import { useStyles } from '@cloudbeaver/core-theming';
import { ComponentStyle, useStyles } from '@cloudbeaver/core-theming';
import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps';
import { baseFormControlStyles } from './baseFormControlStyles';
import { FormContext } from './FormContext';
@@ -19,18 +20,39 @@ const styles = css`
textarea {
line-height: 19px;
}
field[|embedded] {
height: 100%;
display: flex;
flex-direction: column;
& textarea {
border-radius: 0 !important;
height: 100%;
resize: none !important;
}
}
field-label {
display: block;
padding-bottom: 10px;
composes: theme-typography--body1 from global;
font-weight: 500;
&:empty {
display: none;
}
}
`;
type BaseProps = Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'onChange'> & {
type BaseProps = Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'onChange' | 'style'> & ILayoutSizeProps & {
mod?: 'surface';
long?: boolean;
style?: ComponentStyle;
embedded?: boolean;
};
type ControlledProps = BaseProps & {
name?: string;
value?: string;
onChange?: (value: string, name?: string) => any;
state?: never;
};
@@ -38,7 +60,6 @@ type ObjectProps<TKey extends keyof TState, TState> = BaseProps & {
name: TKey;
state: TState;
onChange?: (value: string, name: TKey) => any;
value?: never;
};
@@ -49,12 +70,18 @@ interface TextareaType {
export const Textarea: TextareaType = observer(function Textarea({
name,
style,
value: controlledValue,
state,
children,
className,
fill,
tiny,
small,
medium,
large,
mod,
long,
embedded,
onChange = () => {},
...rest
}: ControlledProps | ObjectProps<any, any>) {
@@ -74,13 +101,15 @@ export const Textarea: TextareaType = observer(function Textarea({
const value = state ? state[name] : controlledValue;
return styled(useStyles(baseFormControlStyles, styles))(
<field as="div" className={className} {...use({ long })}>
<field-label as='label'>{children}</field-label>
return styled(useStyles(baseFormControlStyles, styles, style))(
<field className={className} {...use({ tiny, small, medium, large, embedded })}>
<field-label as='label' title={rest.title}>{children}</field-label>
<textarea
{...rest}
role='new'
value={value ?? ''}
name={name}
data-embedded={embedded}
onChange={handleChange}
{...use({ mod })}
/>
@@ -1,118 +0,0 @@
/*
* 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 { useCallback, useContext } from 'react';
import styled, { css, use } from 'reshadow';
import { ComponentStyle, useStyles } from '@cloudbeaver/core-theming';
import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps';
import { baseFormControlStylesNew } from './baseFormControlStylesNew';
import { FormContext } from './FormContext';
const styles = css`
textarea {
line-height: 19px;
}
field[|embedded] {
height: 100%;
display: flex;
flex-direction: column;
& textarea {
border-radius: 0 !important;
height: 100%;
resize: none !important;
}
}
field-label {
display: block;
padding-bottom: 10px;
composes: theme-typography--body1 from global;
font-weight: 500;
&:empty {
display: none;
}
}
`;
type BaseProps = Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'onChange' | 'style'> & ILayoutSizeProps & {
mod?: 'surface';
style?: ComponentStyle;
embedded?: boolean;
};
type ControlledProps = BaseProps & {
name?: string;
value?: string;
onChange?: (value: string, name?: string) => any;
state?: never;
};
type ObjectProps<TKey extends keyof TState, TState> = BaseProps & {
name: TKey;
state: TState;
onChange?: (value: string, name: TKey) => any;
value?: never;
};
interface TextareaType {
(props: ControlledProps): JSX.Element;
<TKey extends keyof TState, TState>(props: ObjectProps<TKey, TState>): JSX.Element;
}
export const TextareaNew: TextareaType = observer(function TextareaNew({
name,
style,
value: controlledValue,
state,
children,
className,
fill,
tiny,
small,
medium,
large,
mod,
embedded,
onChange = () => {},
...rest
}: ControlledProps | ObjectProps<any, any>) {
const context = useContext(FormContext);
const handleChange = useCallback((event: React.ChangeEvent<HTMLTextAreaElement>) => {
if (state) {
state[name] = event.target.value;
}
if (onChange) {
onChange(event.target.value, name);
}
if (context) {
context.change(event.target.value, name);
}
}, [state, name, onChange]);
const value = state ? state[name] : controlledValue;
return styled(useStyles(baseFormControlStylesNew, styles, style))(
<field className={className} {...use({ tiny, small, medium, large, embedded })}>
<field-label as='label' title={rest.title}>{children}</field-label>
<textarea
{...rest}
role='new'
value={value ?? ''}
name={name}
data-embedded={embedded}
onChange={handleChange}
{...use({ mod })}
/>
</field>
);
});
@@ -18,66 +18,29 @@ export const baseFormControlStyles = composes(
`,
css`
field {
display: flex;
flex-wrap: wrap;
flex: auto;
box-sizing: border-box;
align-items: center;
padding: 12px;
min-height: 54px;
& input,
& textarea {
flex: 1;
min-height: 26px;
max-width: 100%;
&[|small] {
max-width: 250px;
}
&[|medium] {
max-width: 450px;
}
&[|large] {
max-width: 650px;
}
}
field-label {
composes: theme-typography--body1 from global;
box-sizing: border-box;
width: 180px;
text-align: right;
padding: 0 16px;
line-height: 16px;
font-weight: 500;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
field-description {
composes: theme-typography--caption from global;
flex-basis: 100%;
padding-top: 8px;
padding-bottom: 8px;
padding-left: 180px;
}
field[|raw] {
& field-description {
padding: 0;
}
}
field[|long] {
& field-label {
width: 200px;
}
& field-description {
padding-left: 200px;
}
}
field[|short] {
& field-label {
width: auto;
}
& field-description {
padding-left: auto;
}
}
field-label + field-description {
padding-left: 0!important;
flex-basis: auto;
padding-top: 4px;
}
`
);
@@ -1,46 +0,0 @@
/*
* 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 { css } from 'reshadow';
import { composes } from '@cloudbeaver/core-theming';
export const baseFormControlStylesNew = composes(
css`
field-description {
composes: theme-text-text-hint-on-light from global;
}
`,
css`
field {
box-sizing: border-box;
max-width: 100%;
&[|small] {
max-width: 250px;
}
&[|medium] {
max-width: 450px;
}
&[|large] {
max-width: 650px;
}
}
field-label {
box-sizing: border-box;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
field-description {
composes: theme-typography--caption from global;
padding-top: 4px;
}
`
);
@@ -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 type { DetailedHTMLProps, IframeHTMLAttributes } from 'react';
import styled, { css } from 'reshadow';
import { composes, useStyles } from '@cloudbeaver/core-theming';
const styles = composes(
css`
iframe {
composes: theme-border-color-background from global;
}
`,
css`
iframe {
border: 1px solid;
}
`
);
export const Iframe: React.FC<DetailedHTMLProps<IframeHTMLAttributes<HTMLIFrameElement>, HTMLIFrameElement>> = function Iframe(props) {
return styled(useStyles(styles))(
<iframe {...props} />
);
};
@@ -8,127 +8,17 @@
import { observer } from 'mobx-react-lite';
import { useCallback } from 'react';
import styled from 'reshadow';
import { InputField } from '@cloudbeaver/core-blocks';
import type { ObjectPropertyInfo } from '@cloudbeaver/core-sdk';
import { useStyles } from '@cloudbeaver/core-theming';
import { FieldCheckbox } from '../../FormControls/Checkboxes/FieldCheckbox';
import { Combobox } from '../../FormControls/Combobox';
import { FormFieldDescription } from '../../FormControls/FormFieldDescription';
import { FormGroup } from '../../FormControls/FormGroup';
import { isControlPresented } from '../../FormControls/isControlPresented';
import { Link } from '../../Link';
import type { ILayoutSizeProps } from '../../Containers/ILayoutSizeProps';
import { TextPlaceholder } from '../../TextPlaceholder';
import { formStyles } from './formStyles';
import { RenderField } from './RenderField';
const RESERVED_KEYWORDS = ['no', 'off', 'new-password'];
interface RenderFieldProps {
property: ObjectPropertyInfo;
state: Record<string, any>;
editable?: boolean;
autofillToken?: string;
disabled?: boolean;
readOnly?: boolean;
autoHide?: boolean;
showRememberTip?: boolean;
onFocus?: (event: React.FocusEvent<HTMLInputElement>) => void;
}
const RenderField = observer<RenderFieldProps>(function RenderField({
property,
state,
editable = true,
autofillToken = '',
disabled,
readOnly,
autoHide,
showRememberTip,
onFocus,
}) {
const href = property.features.includes('href');
const password = property.features.includes('password');
const checkbox = property.dataType === 'Boolean';
const combobox = property.validValues && property.validValues.length > 0;
let description: string | undefined;
if (href) {
return (
<FormFieldDescription label={property.displayName} raw>
<Link href={state[property.id!]} target='_blank' rel='noopener noreferrer'>{property.description}</Link>
</FormFieldDescription>
);
}
if (!editable) {
if (autoHide && !isControlPresented(property.id!, state)) {
return null;
}
return (
<FormFieldDescription label={property.displayName} raw>
{state[property.id!]}
</FormFieldDescription>
);
}
if (showRememberTip && password && property.value) {
description = 'Password saved';
}
if (checkbox) {
return (
<FieldCheckbox
id={property.id}
name={property.id!}
state={state}
label={property.displayName}
title={property.description}
disabled={disabled}
/>
);
}
if (combobox) {
return (
<Combobox
name={property.id!}
state={state}
items={property.validValues!}
keySelector={value => value}
valueSelector={value => value}
defaultValue={property.defaultValue}
mod="surface"
title={property.description}
disabled={disabled}
>
{property.displayName ?? ''}
</Combobox>
);
}
return (
<InputField
type={password ? 'password' : 'text'}
name={property.id!}
state={state}
description={description}
disabled={disabled}
readOnly={readOnly}
autoHide={autoHide}
autoComplete={RESERVED_KEYWORDS.includes(autofillToken) ? autofillToken : `${autofillToken} ${property.id}`}
mod='surface'
onFocus={onFocus}
>
{property.displayName}
</InputField>
);
});
interface ObjectPropertyFormProps {
properties: ObjectPropertyInfo[] | undefined;
state: Record<string, string | number>;
interface ObjectPropertyFormProps extends ILayoutSizeProps {
properties: ObjectPropertyInfo[];
state?: Record<string, any>;
category?: string | null;
editable?: boolean;
autofillToken?: string;
className?: string;
@@ -142,32 +32,36 @@ interface ObjectPropertyFormProps {
export const ObjectPropertyInfoForm = observer<ObjectPropertyFormProps>(function ObjectPropertyInfoForm({
properties,
state,
category,
editable = true,
autofillToken = '',
className,
autofillToken = '',
disabled,
readOnly,
autoHide,
showRememberTip,
onFocus,
}) {
const style = useStyles(formStyles);
const handleFocus = useCallback((e: React.FocusEvent<HTMLInputElement>) => {
if (onFocus) {
onFocus(e.target.name);
}
}, [onFocus]);
if (!properties || properties.length === 0) {
if (properties.length === 0) {
return <TextPlaceholder>Properties empty</TextPlaceholder>;
}
return styled(style)(
<form-body as='div' className={className}>
{properties.map(property => (
<FormGroup key={property.id}>
return (
<>
{properties.map(property => {
if (category !== undefined && property.category !== category) {
return null;
}
return (
<RenderField
key={property.id}
className={className}
property={property}
state={state}
editable={editable}
@@ -178,8 +72,8 @@ export const ObjectPropertyInfoForm = observer<ObjectPropertyFormProps>(function
showRememberTip={showRememberTip}
onFocus={handleFocus}
/>
</FormGroup>
))}
</form-body>
);
})}
</>
);
});
@@ -1,79 +0,0 @@
/*
* 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 { useCallback } from 'react';
import type { ObjectPropertyInfo } from '@cloudbeaver/core-sdk';
import type { ILayoutSizeProps } from '../../Containers/ILayoutSizeProps';
import { TextPlaceholder } from '../../TextPlaceholder';
import { RenderField } from './RenderField';
interface ObjectPropertyFormProps extends ILayoutSizeProps {
properties: ObjectPropertyInfo[];
state?: Record<string, any>;
category?: string | null;
editable?: boolean;
autofillToken?: string;
className?: string;
disabled?: boolean;
readOnly?: boolean;
autoHide?: boolean;
showRememberTip?: boolean;
onFocus?: (name: string) => void;
}
export const ObjectPropertyInfoFormNew = observer<ObjectPropertyFormProps>(function ObjectPropertyInfoFormNew({
properties,
state,
category,
editable = true,
className,
autofillToken = '',
disabled,
readOnly,
autoHide,
showRememberTip,
onFocus,
}) {
const handleFocus = useCallback((e: React.FocusEvent<HTMLInputElement>) => {
if (onFocus) {
onFocus(e.target.name);
}
}, [onFocus]);
if (properties.length === 0) {
return <TextPlaceholder>Properties empty</TextPlaceholder>;
}
return (
<>
{properties.map(property => {
if (category !== undefined && property.category !== category) {
return null;
}
return (
<RenderField
key={property.id}
className={className}
property={property}
state={state}
editable={editable}
autofillToken={autofillToken}
disabled={disabled}
readOnly={readOnly}
autoHide={autoHide}
showRememberTip={showRememberTip}
onFocus={handleFocus}
/>
);
})}
</>
);
});
@@ -10,12 +10,12 @@ import { observer } from 'mobx-react-lite';
import type { ObjectPropertyInfo } from '@cloudbeaver/core-sdk';
import { FieldCheckboxNew } from '../../FormControls/Checkboxes/FieldCheckboxNew';
import { ComboboxNew } from '../../FormControls/ComboboxNew';
import { FormFieldDescriptionNew } from '../../FormControls/FormFieldDescriptionNew';
import { InputFieldNew } from '../../FormControls/InputFieldNew';
import { FieldCheckbox } from '../../FormControls/Checkboxes/FieldCheckbox';
import { Combobox } from '../../FormControls/Combobox';
import { FormFieldDescription } from '../../FormControls/FormFieldDescription';
import { InputField } from '../../FormControls/InputField';
import { isControlPresented } from '../../FormControls/isControlPresented';
import { TextareaNew } from '../../FormControls/TextareaNew';
import { Textarea } from '../../FormControls/Textarea';
import { Link } from '../../Link';
const RESERVED_KEYWORDS = ['no', 'off', 'new-password'];
@@ -86,9 +86,9 @@ export const RenderField = observer<RenderFieldProps>(function RenderField({
if (controltype === 'link') {
return (
<FormFieldDescriptionNew label={property.displayName} className={className}>
<FormFieldDescription label={property.displayName} className={className}>
<Link href={state?.[property.id!]} target='_blank' rel='noopener noreferrer'>{property.description}</Link>
</FormFieldDescriptionNew>
</FormFieldDescription>
);
}
@@ -97,9 +97,9 @@ export const RenderField = observer<RenderFieldProps>(function RenderField({
return null;
}
return (
<FormFieldDescriptionNew title={property.description} label={property.displayName} className={className}>
<FormFieldDescription title={property.description} label={property.displayName} className={className}>
{state?.[property.id!]}
</FormFieldDescriptionNew>
</FormFieldDescription>
);
}
@@ -110,7 +110,7 @@ export const RenderField = observer<RenderFieldProps>(function RenderField({
if (controltype === 'checkbox') {
if (state !== undefined) {
return (
<FieldCheckboxNew
<FieldCheckbox
id={property.id}
name={property.id!}
state={state}
@@ -120,11 +120,11 @@ export const RenderField = observer<RenderFieldProps>(function RenderField({
className={className}
>
{property.displayName ?? ''}
</FieldCheckboxNew>
</FieldCheckbox>
);
}
return (
<FieldCheckboxNew
<FieldCheckbox
id={property.id}
name={property.id!}
checked={value}
@@ -134,14 +134,14 @@ export const RenderField = observer<RenderFieldProps>(function RenderField({
className={className}
>
{property.displayName ?? ''}
</FieldCheckboxNew>
</FieldCheckbox>
);
}
if (controltype === 'combobox') {
if (state !== undefined) {
return (
<ComboboxNew
<Combobox
name={property.id!}
state={state}
items={property.validValues!}
@@ -154,12 +154,12 @@ export const RenderField = observer<RenderFieldProps>(function RenderField({
className={className}
>
{property.displayName ?? ''}
</ComboboxNew>
</Combobox>
);
}
return (
<ComboboxNew
<Combobox
name={property.id!}
items={property.validValues!}
keySelector={value => value}
@@ -171,14 +171,14 @@ export const RenderField = observer<RenderFieldProps>(function RenderField({
className={className}
>
{property.displayName ?? ''}
</ComboboxNew>
</Combobox>
);
}
if (controltype === 'textarea') {
if (state !== undefined) {
return (
<TextareaNew
<Textarea
title={property.description}
name={property.id!}
state={state}
@@ -188,12 +188,12 @@ export const RenderField = observer<RenderFieldProps>(function RenderField({
className={className}
>
{property.displayName ?? ''}
</TextareaNew>
</Textarea>
);
}
return (
<TextareaNew
<Textarea
title={property.description}
name={property.id!}
value={value}
@@ -203,13 +203,13 @@ export const RenderField = observer<RenderFieldProps>(function RenderField({
className={className}
>
{property.displayName ?? ''}
</TextareaNew>
</Textarea>
);
}
if (state !== undefined) {
return (
<InputFieldNew
<InputField
type={password ? 'password' : 'text'}
title={property.description}
name={property.id!}
@@ -225,11 +225,11 @@ export const RenderField = observer<RenderFieldProps>(function RenderField({
onFocus={onFocus}
>
{property.displayName}
</InputFieldNew>
</InputField>
);
}
return (
<InputFieldNew
<InputField
type={password ? 'password' : 'text'}
title={property.description}
name={property.id!}
@@ -244,6 +244,6 @@ export const RenderField = observer<RenderFieldProps>(function RenderField({
onFocus={onFocus}
>
{property.displayName}
</InputFieldNew>
</InputField>
);
});
@@ -1,18 +0,0 @@
/*
* 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 { css } from 'reshadow';
export const formStyles = css`
form-body {
flex: 1;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
`;
@@ -1,28 +0,0 @@
/*
* 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.
*/
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference path="react-sanitized-html.d.ts" />
import Sanitized from 'react-sanitized-html';
export interface SanitizedHTMLProps {
html: string;
}
const allowedTags = ['h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol',
'nl', 'li', 'b', 'i', 'strong', 'em', 'strike', 'code', 'hr', 'br', 'div',
'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre'];
const nonTextTags = ['title', 'style', 'script', 'textarea', 'noscript'];
export function ReactSanitizedHTML({ html }: SanitizedHTMLProps) {
return (
<Sanitized html={html} allowedTags={allowedTags} nonTextTags={nonTextTags} />
);
}
@@ -1,31 +0,0 @@
/*
* 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 { ComplexLoader, createComplexLoader, Loader } from '@cloudbeaver/core-blocks';
const loader = createComplexLoader(async function loader() {
const { ReactSanitizedHTML } = await import('./ReactSanitizedHTML');
return { ReactSanitizedHTML };
});
interface Props {
html: string;
}
export const SanitizedHTML: React.FC<Props> = function SanitizedHTML({ html }) {
return (
<ComplexLoader
loader={loader}
placeholder={<Loader />}
>
{({ ReactSanitizedHTML }) => (
<ReactSanitizedHTML html={html} />
)}
</ComplexLoader>
);
};
@@ -1,14 +0,0 @@
declare module 'react-sanitized-html' {
import { Component } from 'react';
interface ReactSanitizedHtmlProps {
html: string;
// see https://github.com/apostrophecms/sanitize-html documentation
allowedTags?: string[];
nonTextTags?: string[];
}
export default class ReactSanitizedHtml extends Component<ReactSanitizedHtmlProps, any> {
}
}
+1 -9
View File
@@ -16,7 +16,6 @@ export * from './layout/AppLogo';
export * from './layout/TopAppBar';
export * from './Loader/Loader';
export * from './ObjectPropertyInfo/ObjectPropertyInfoForm/ObjectPropertyInfoForm';
export * from './ObjectPropertyInfo/ObjectPropertyInfoForm/ObjectPropertyInfoFormNew';
export * from './ObjectPropertyInfo/useObjectPropertyCategories';
export * from './Placeholder/Placeholder';
@@ -25,7 +24,6 @@ export * from './Placeholder/PlaceholderContainer';
export * from './PropertiesTable/PropertiesTable';
export * from './PropertiesTable/IProperty';
export * from './SanitizedHTML/SanitizedHTML';
export * from './Slide/SlideBox';
export * from './Slide/SlideBoxStyles';
export * from './Slide/SlideElement';
@@ -98,10 +96,8 @@ export * from './ToolsPanel/ToolsAction';
export * from './ToolsPanel/ToolsPanel';
export * from './FormControls/Checkboxes/Checkbox';
export * from './FormControls/Checkboxes/FieldCheckbox';
export * from './FormControls/Checkboxes/FieldCheckboxNew';
export * from './FormControls/Checkboxes/CheckboxMarkup';
export * from './FormControls/Checkboxes/Switch';
export * from './FormControls/Checkboxes/SwitchNew';
export * from './FormControls/Checkboxes/useCheckboxState';
export * from './FormControls/FormBox';
export * from './FormControls/Filter';
@@ -117,21 +113,16 @@ export * from './Containers/IContainerProps';
export * from './Containers/ILayoutSizeProps';
export * from './FormControls/FormBoxElement';
export * from './FormControls/Combobox';
export * from './FormControls/ComboboxNew';
export * from './FormControls/FormContext';
export * from './FormControls/FormFieldDescription';
export * from './FormControls/FormFieldDescriptionNew';
export * from './FormControls/FormGroup';
export * from './FormControls/InputField';
export * from './FormControls/InputFieldNew';
export * from './FormControls/InputGroup';
export * from './FormControls/Radio';
export * from './FormControls/RadioGroup';
export * from './FormControls/RadioGroupContext';
export * from './FormControls/ShadowInput';
export * from './FormControls/SubmittingForm';
export * from './FormControls/Textarea';
export * from './FormControls/TextareaNew';
export * from './Link';
export * from './Cell';
export * from './ErrorMessage';
@@ -143,6 +134,7 @@ export * from './IconOrImage';
export * from './StaticImage';
export * from './TextPlaceholder';
export * from './InfoItem';
export * from './Iframe';
export * from './useClickEvents';
export * from './useClipboard';
export * from './useDataResource';
@@ -24,8 +24,6 @@ const excludedFromVendor = [
'backbone',
'lodash',
'canvg',
'sanitize-html',
'react-sanitized-html',
'dagre',
'svg-pathdata',
'@emotion',
@@ -9,7 +9,7 @@
import { observer } from 'mobx-react-lite';
import styled from 'reshadow';
import { BASE_CONTAINERS_STYLES, Container, FieldCheckboxNew, Group, GroupTitle, ObjectPropertyInfoFormNew, TextPlaceholder, useMapResource } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, Container, FieldCheckbox, Group, GroupTitle, ObjectPropertyInfoForm, TextPlaceholder, useMapResource } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import type { ObjectPropertyInfo } from '@cloudbeaver/core-sdk';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -48,14 +48,14 @@ export const ConnectionAuthenticationForm = observer<Props>(function ConnectionA
{properties ? (
<>
{!!networkHandlers?.length && <GroupTitle>{translate('connections_database_authentication')}</GroupTitle>}
<ObjectPropertyInfoFormNew
<ObjectPropertyInfoForm
autofillToken={`section-${formId || ''} section-auth`}
properties={properties}
state={config.credentials}
disabled={disabled}
/>
{allowSaveCredentials && (
<FieldCheckboxNew
<FieldCheckbox
id={formId || 'DBAuthSaveCredentials'}
name="saveCredentials"
label={translate('connections_connection_edit_save_credentials')}
@@ -9,7 +9,7 @@
import { observer } from 'mobx-react-lite';
import styled from 'reshadow';
import { BASE_CONTAINERS_STYLES, FieldCheckboxNew, GroupTitle, InputFieldNew, useMapResource } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, FieldCheckbox, GroupTitle, InputField, useMapResource } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import type { NetworkHandlerConfigInput } from '@cloudbeaver/core-sdk';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -41,7 +41,7 @@ export const NetworkHandlerAuthForm = observer<Props>(function NetworkHandlerAut
return styled(useStyles(BASE_CONTAINERS_STYLES))(
<>
<GroupTitle>{handler.data?.label || translate(`connections_network_handler_${id}_title`, 'connections_network_handler_default_title')}</GroupTitle>
<InputFieldNew
<InputField
type="text"
name="userName"
state={state}
@@ -49,8 +49,8 @@ export const NetworkHandlerAuthForm = observer<Props>(function NetworkHandlerAut
mod='surface'
>
{translate(`connections_network_handler_${id}_user`, 'connections_network_handler_default_user')}
</InputFieldNew>
<InputFieldNew
</InputField>
<InputField
type="password"
name="password"
state={state}
@@ -58,9 +58,9 @@ export const NetworkHandlerAuthForm = observer<Props>(function NetworkHandlerAut
mod='surface'
>
{translate(`connections_network_handler_${id}_password`, 'connections_network_handler_default_password')}
</InputFieldNew>
</InputField>
{allowSaveCredentials && (
<FieldCheckboxNew
<FieldCheckbox
id={id + ' savePassword'}
name="savePassword"
state={state}
@@ -13,7 +13,7 @@ import styled, { css } from 'reshadow';
import { useAdministrationSettings } from '@cloudbeaver/core-administration';
import { AUTH_PROVIDER_LOCAL_ID } from '@cloudbeaver/core-authentication';
import {
InputFieldNew,
InputField,
SubmittingForm,
TabContainerPanelComponent,
useMapResource,
@@ -21,10 +21,10 @@ import {
BASE_CONTAINERS_STYLES,
Group,
GroupTitle,
FieldCheckboxNew,
ObjectPropertyInfoFormNew,
TextareaNew,
ComboboxNew,
FieldCheckbox,
ObjectPropertyInfoForm,
Textarea,
Combobox,
Container,
useFormValidator,
} from '@cloudbeaver/core-blocks';
@@ -39,7 +39,7 @@ import { DBDriverResource } from '../../DBDriverResource';
import { isJDBCConnection } from '../../isJDBCConnection';
import { ConnectionFormService } from '../ConnectionFormService';
import type { IConnectionFormProps } from '../IConnectionFormProps';
import { ParametersFormNew } from './ParametersFormNew';
import { ParametersForm } from './ParametersForm';
import { useOptions } from './useOptions';
const styles = css`
@@ -120,7 +120,7 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
<Container medium gap>
<Group form gap>
<Container wrap gap>
<ComboboxNew
<Combobox
name='driverId'
state={config}
items={drivers}
@@ -132,8 +132,8 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
fill
>
{translate('connections_connection_driver')}
</ComboboxNew>
<InputFieldNew
</Combobox>
<InputField
type="text"
name="name"
minLength={1}
@@ -146,10 +146,10 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
fill
>
{translate('connections_connection_name')}
</InputFieldNew>
</InputField>
</Container>
{JDBC ? (
<InputFieldNew
<InputField
type="text"
name="url"
state={config}
@@ -159,9 +159,9 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
mod='surface'
>
{translate('customConnection_url_JDBC')}
</InputFieldNew>
</InputField>
) : (
<ParametersFormNew
<ParametersForm
config={config}
embedded={driver.data?.embedded}
disabled={disabled}
@@ -170,7 +170,7 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
/>
)}
{admin && originLocal && (
<FieldCheckboxNew
<FieldCheckbox
id={config.connectionId}
name="template"
state={config}
@@ -179,9 +179,9 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
// autoHide={} // maybe better to use autoHide
>
{translate('connections_connection_template')}
</FieldCheckboxNew>
</FieldCheckbox>
)}
<TextareaNew
<Textarea
name="description"
rows={3}
state={config}
@@ -189,7 +189,7 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
readOnly={readonly}
>
{translate('connections_connection_description')}
</TextareaNew>
</Textarea>
</Group>
</Container>
<Container medium gap>
@@ -197,7 +197,7 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
<Group form gap>
<GroupTitle>{translate('connections_connection_edit_authentication')}</GroupTitle>
<Container wrap gap>
<ObjectPropertyInfoFormNew
<ObjectPropertyInfoForm
autofillToken='new-password'
properties={properties}
state={config.credentials}
@@ -208,13 +208,13 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
/>
</Container>
{credentialsSavingEnabled && (
<FieldCheckboxNew
<FieldCheckbox
id={config.connectionId + 'authNeeded'}
name="saveCredentials"
state={config}
disabled={disabled || readonly}
>{translate('connections_connection_edit_save_credentials')}
</FieldCheckboxNew>
</FieldCheckbox>
)}
</Group>
)}
@@ -223,7 +223,7 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
<GroupTitle>{translate('connections_connection_edit_settings')}</GroupTitle>
{booleanProviderProperties && booleanProviderProperties.length > 0 && (
<Container gap wrap>
<ObjectPropertyInfoFormNew
<ObjectPropertyInfoForm
properties={booleanProviderProperties}
state={config.providerProperties}
disabled={disabled}
@@ -234,7 +234,7 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
)}
{providerPropertiesWithoutBoolean && (
<Container wrap gap>
<ObjectPropertyInfoFormNew
<ObjectPropertyInfoForm
properties={providerPropertiesWithoutBoolean}
state={config.providerProperties}
disabled={disabled}
@@ -7,9 +7,9 @@
*/
import { observer } from 'mobx-react-lite';
import styled, { css, use } from 'reshadow';
import styled from 'reshadow';
import { FormGroup, InputField } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, Container, InputField } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import type { ConnectionConfig } from '@cloudbeaver/core-sdk';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -19,66 +19,54 @@ interface Props {
disabled?: boolean;
embedded?: boolean;
readOnly?: boolean;
originLocal?: boolean;
}
const parametersFormStyles = css`
sub-label {
composes: theme-typography--caption from global;
line-height: 14px;
}`;
export const ParametersForm = observer<Props>(function ParametersForm({
config,
embedded,
disabled,
readOnly,
originLocal,
}) {
const translate = useTranslate();
return styled(useStyles(parametersFormStyles))(
<>
return styled(useStyles(BASE_CONTAINERS_STYLES))(
<Container gap>
{!embedded && (
<layout-grid-inner as="div">
<layout-grid-cell as='div' {...use({ 'span-tablet': 12, 'span-desktop': 8 })}>
<InputField
type="text"
name="host"
state={config}
disabled={disabled}
readOnly={readOnly}
mod='surface'
>
{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"
state={config}
disabled={disabled}
readOnly={readOnly}
mod='surface'
short
>
{translate('customConnection_custom_port')}
</InputField>
</layout-grid-cell>
</layout-grid-inner>
<Container wrap gap>
<InputField
type="text"
name="host"
state={config}
disabled={disabled}
readOnly={readOnly || !originLocal}
small
required
>
{translate('customConnection_custom_host')}
</InputField>
<InputField
type="number"
name="port"
state={config}
disabled={disabled}
readOnly={readOnly || !originLocal}
tiny
>
{translate('customConnection_custom_port')}
</InputField>
</Container>
)}
<FormGroup>
<InputField
type="text"
name="databaseName"
state={config}
disabled={disabled}
readOnly={readOnly}
mod='surface'
>
{translate('customConnection_custom_database')}
</InputField>
</FormGroup>
</>
<InputField
type="text"
name="databaseName"
state={config}
disabled={disabled}
readOnly={readOnly}
>
{translate('customConnection_custom_database')}
</InputField>
</Container>
);
});
@@ -1,72 +0,0 @@
/*
* 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 styled from 'reshadow';
import { BASE_CONTAINERS_STYLES, Container, InputFieldNew } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import type { ConnectionConfig } from '@cloudbeaver/core-sdk';
import { useStyles } from '@cloudbeaver/core-theming';
interface Props {
config: ConnectionConfig;
disabled?: boolean;
embedded?: boolean;
readOnly?: boolean;
originLocal?: boolean;
}
export const ParametersFormNew = observer<Props>(function ParametersFormNew({
config,
embedded,
disabled,
readOnly,
originLocal,
}) {
const translate = useTranslate();
return styled(useStyles(BASE_CONTAINERS_STYLES))(
<Container gap>
{!embedded && (
<Container wrap gap>
<InputFieldNew
type="text"
name="host"
state={config}
disabled={disabled}
readOnly={readOnly || !originLocal}
small
required
>
{translate('customConnection_custom_host')}
</InputFieldNew>
<InputFieldNew
type="number"
name="port"
state={config}
disabled={disabled}
readOnly={readOnly || !originLocal}
tiny
>
{translate('customConnection_custom_port')}
</InputFieldNew>
</Container>
)}
<InputFieldNew
type="text"
name="databaseName"
state={config}
disabled={disabled}
readOnly={readOnly}
>
{translate('customConnection_custom_database')}
</InputFieldNew>
</Container>
);
});
@@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { UserInfoResource } from '@cloudbeaver/core-authentication';
import { TextPlaceholder, useTab, Loader, useTabState, ExceptionMessage, useMapResource, ColoredContainer, Group, ObjectPropertyInfoFormNew, BASE_CONTAINERS_STYLES } from '@cloudbeaver/core-blocks';
import { TextPlaceholder, useTab, Loader, useTabState, ExceptionMessage, useMapResource, ColoredContainer, Group, ObjectPropertyInfoForm, BASE_CONTAINERS_STYLES } from '@cloudbeaver/core-blocks';
import type { TabContainerPanelComponent } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { useTranslate } from '@cloudbeaver/core-localization';
@@ -103,7 +103,7 @@ export const OriginInfo: TabContainerPanelComponent<IConnectionFormProps> = obse
return styled(styles)(
<ColoredContainer parent>
<Group large gap>
<ObjectPropertyInfoFormNew
<ObjectPropertyInfoForm
properties={connection.data.origin.details}
state={state}
readOnly
@@ -12,7 +12,7 @@ import styled from 'reshadow';
import { css } from 'reshadow';
import { useAdministrationSettings } from '@cloudbeaver/core-administration';
import { Group, SubmittingForm, useMapResource, Button, ColoredContainer, InputFieldNew, FieldCheckboxNew, BASE_CONTAINERS_STYLES, SwitchNew, GroupItem, Container } from '@cloudbeaver/core-blocks';
import { Group, SubmittingForm, useMapResource, Button, ColoredContainer, InputField, FieldCheckbox, BASE_CONTAINERS_STYLES, Switch, GroupItem, Container } from '@cloudbeaver/core-blocks';
import type { TabContainerPanelComponent } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -78,16 +78,16 @@ export const SSH: TabContainerPanelComponent<IConnectionFormProps> = observer(fu
<SubmittingForm onSubmit={save}>
<ColoredContainer parent>
<Group form gap keepSize large>
<SwitchNew
<Switch
name="enabled"
state={state}
mod={['primary']}
disabled={disabled || readonly}
>
{translate('connections_network_handler_ssh_tunnel_enable')}
</SwitchNew>
</Switch>
<Container wrap gap>
<InputFieldNew
<InputField
type="text"
name="host"
state={state.properties}
@@ -97,8 +97,8 @@ export const SSH: TabContainerPanelComponent<IConnectionFormProps> = observer(fu
small
>
{translate('connections_network_handler_ssh_tunnel_host')}
</InputFieldNew>
<InputFieldNew
</InputField>
<InputField
type="number"
name="port"
state={state.properties}
@@ -108,10 +108,10 @@ export const SSH: TabContainerPanelComponent<IConnectionFormProps> = observer(fu
tiny
>
{translate('connections_network_handler_ssh_tunnel_port')}
</InputFieldNew>
</InputField>
</Container>
<Container wrap gap>
<InputFieldNew
<InputField
type="text"
name="userName"
state={state}
@@ -121,8 +121,8 @@ export const SSH: TabContainerPanelComponent<IConnectionFormProps> = observer(fu
tiny
>
{translate('connections_network_handler_ssh_tunnel_user')}
</InputFieldNew>
<InputFieldNew
</InputField>
<InputField
type="password"
name="password"
placeholder={passwordHint}
@@ -134,16 +134,16 @@ export const SSH: TabContainerPanelComponent<IConnectionFormProps> = observer(fu
tiny
>
{translate('connections_network_handler_ssh_tunnel_password')}
</InputFieldNew>
</InputField>
</Container>
{credentialsSavingEnabled && (
<FieldCheckboxNew
<FieldCheckbox
id={SSH_TUNNEL_ID + ' savePassword'}
name="savePassword"
state={state}
disabled={disabled || !enabled || readonly}
>{translate('connections_connection_edit_save_credentials')}
</FieldCheckboxNew>
</FieldCheckbox>
)}
<GroupItem>
<Button
@@ -9,7 +9,7 @@
import { useState } from 'react';
import styled, { css } from 'reshadow';
import { BASE_CONTAINERS_STYLES, Button, Container, InputFieldNew, SubmittingForm, useFocus } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, Button, Container, InputField, SubmittingForm, useFocus } from '@cloudbeaver/core-blocks';
import { Translate, useTranslate } from '@cloudbeaver/core-localization';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -84,12 +84,12 @@ export const RenameDialog: DialogComponent<RenameDialogPayload, string> = functi
>
<SubmittingForm ref={focusedRef} onSubmit={() => resolveDialog(name)}>
<Container center>
<InputFieldNew
<InputField
value={name}
onChange={value => setName(String(value))}
>
{translate('ui_name') + ':'}
</InputFieldNew>
</InputField>
</Container>
</SubmittingForm>
</CommonDialogWrapper>
@@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite';
import { useCallback, useMemo } from 'react';
import styled from 'reshadow';
import { useClipboard, Button, SanitizedHTML } from '@cloudbeaver/core-blocks';
import { useClipboard, Button, Iframe } from '@cloudbeaver/core-blocks';
import { CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -66,7 +66,7 @@ export const ErrorDetailsDialog: DialogComponent<Error | string, null> = observe
onReject={props.rejectDialog}
>
{error.reason && <property>{error.reason}</property>}
{error.htmlBody && (<SanitizedHTML html={error.htmlBody} />)}
{error.htmlBody && <Iframe srcDoc={error.htmlBody} />}
{error.errors.map(
(error, id) => (
<>
@@ -10,7 +10,7 @@
import { observer } from 'mobx-react-lite';
import styled from 'reshadow';
import { BASE_CONTAINERS_STYLES, SwitchNew } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, Switch } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import type { ServerConfigInput } from '@cloudbeaver/core-sdk';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -25,7 +25,7 @@ export const ServerConfigurationConfigurationForm = observer<Props>(function Ser
const translate = useTranslate();
return styled(useStyles(BASE_CONTAINERS_STYLES))(
<>
<SwitchNew
<Switch
name="customConnectionsEnabled"
state={serverConfig}
description={translate('administration_configuration_wizard_configuration_custom_connections_description')}
@@ -34,7 +34,7 @@ export const ServerConfigurationConfigurationForm = observer<Props>(function Ser
autoHide
>
{translate('administration_configuration_wizard_configuration_custom_connections')}
</SwitchNew>
</Switch>
</>
);
});
@@ -10,7 +10,7 @@
import { observer } from 'mobx-react-lite';
import styled from 'reshadow';
import { Group, GroupTitle, BASE_CONTAINERS_STYLES, InputFieldNew } from '@cloudbeaver/core-blocks';
import { Group, GroupTitle, BASE_CONTAINERS_STYLES, InputField } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -27,7 +27,7 @@ export const ServerConfigurationInfoForm = observer<Props>(function ServerConfig
return styled(useStyles(BASE_CONTAINERS_STYLES))(
<Group form gap medium>
<GroupTitle>{translate('administration_configuration_wizard_configuration_server_info')}</GroupTitle>
<InputFieldNew
<InputField
type="text"
name="serverName"
state={state.serverConfig}
@@ -36,8 +36,8 @@ export const ServerConfigurationInfoForm = observer<Props>(function ServerConfig
medium
>
{translate('administration_configuration_wizard_configuration_server_name')}
</InputFieldNew>
<InputFieldNew
</InputField>
<InputField
title={translate('administration_configuration_wizard_configuration_server_url_description')}
type="url"
name="serverURL"
@@ -47,8 +47,8 @@ export const ServerConfigurationInfoForm = observer<Props>(function ServerConfig
medium
>
{translate('administration_configuration_wizard_configuration_server_url')}
</InputFieldNew>
<InputFieldNew
</InputField>
<InputField
title={translate('administration_configuration_wizard_configuration_server_session_lifetime_description')}
type="number"
name="sessionExpireTime"
@@ -61,7 +61,7 @@ export const ServerConfigurationInfoForm = observer<Props>(function ServerConfig
tiny
>
{translate('administration_configuration_wizard_configuration_server_session_lifetime')}
</InputFieldNew>
</InputField>
</Group>
);
});
@@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite';
import { useCallback } from 'react';
import styled from 'reshadow';
import { BASE_CONTAINERS_STYLES, SwitchNew } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, Switch } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import { CONNECTION_NAVIGATOR_VIEW_SETTINGS, isNavigatorViewSettingsEqual } from '@cloudbeaver/core-root';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -38,7 +38,7 @@ export const ServerConfigurationNavigatorViewForm = observer<Props>(function Ser
return styled(useStyles(BASE_CONTAINERS_STYLES))(
<>
<SwitchNew
<Switch
name="simpleNavigatorViewEnabled"
description={translate('administration_configuration_wizard_configuration_navigation_tree_view_description')}
mod={['primary']}
@@ -47,7 +47,7 @@ export const ServerConfigurationNavigatorViewForm = observer<Props>(function Ser
onChange={onNavigatorViewChangeHandler}
>
{translate('administration_configuration_wizard_configuration_navigation_tree_view')}
</SwitchNew>
</Switch>
</>
);
});
@@ -9,7 +9,7 @@
import { observer } from 'mobx-react-lite';
import styled from 'reshadow';
import { BASE_CONTAINERS_STYLES, Group, GroupTitle, SwitchNew } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, Group, GroupTitle, Switch } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import type { ServerConfigInput } from '@cloudbeaver/core-sdk';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -25,7 +25,7 @@ export const ServerConfigurationSecurityForm = observer<Props>(function ServerCo
return styled(useStyles(BASE_CONTAINERS_STYLES))(
<Group form gap medium>
<GroupTitle>{translate('administration_configuration_wizard_configuration_security')}</GroupTitle>
<SwitchNew
<Switch
name="adminCredentialsSaveEnabled"
state={serverConfig}
description={translate('administration_configuration_wizard_configuration_security_admin_credentials_description')}
@@ -34,8 +34,8 @@ export const ServerConfigurationSecurityForm = observer<Props>(function ServerCo
autoHide
>
{translate('administration_configuration_wizard_configuration_security_admin_credentials')}
</SwitchNew>
<SwitchNew
</Switch>
<Switch
name="publicCredentialsSaveEnabled"
state={serverConfig}
description={translate('administration_configuration_wizard_configuration_security_public_credentials_description')}
@@ -45,7 +45,7 @@ export const ServerConfigurationSecurityForm = observer<Props>(function ServerCo
autoHide
>
{translate('administration_configuration_wizard_configuration_security_public_credentials')}
</SwitchNew>
</Switch>
</Group>
);
});
@@ -12,7 +12,7 @@ import styled, { css, use } from 'reshadow';
import { AuthProvidersResource } from '@cloudbeaver/core-authentication';
import {
TableItem, TableColumnValue, TableItemSelect, TableItemExpand,
Placeholder, StaticImage, useMapResource, FieldCheckboxNew
Placeholder, StaticImage, useMapResource, FieldCheckbox
} from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import type { AdminAuthProviderConfiguration } from '@cloudbeaver/core-sdk';
@@ -63,7 +63,7 @@ export const AuthConfiguration = observer<Props>(function AuthConfiguration({ co
<TableColumnValue>{configuration.providerId}</TableColumnValue>
<TableColumnValue title={configuration.description} ellipsis>{configuration.description || ''}</TableColumnValue>
<TableColumnValue>
<FieldCheckboxNew checked={configuration.disabled} disabled />
<FieldCheckbox checked={configuration.disabled} disabled />
</TableColumnValue>
<TableColumnValue flex {...use({ gap: true })}>
<Placeholder container={service.configurationDetailsPlaceholder} configuration={configuration} />
@@ -12,9 +12,9 @@ import styled, { css } from 'reshadow';
import { AuthConfigurationParametersResource, AuthProvidersResource } from '@cloudbeaver/core-authentication';
import {
BASE_CONTAINERS_STYLES, ColoredContainer, ComboboxNew, FieldCheckboxNew, Group, GroupTitle,
InputFieldNew, Link, ObjectPropertyInfoFormNew, SubmittingForm, TabContainerPanelComponent,
TextareaNew, useClipboard, useMapResource, useObjectPropertyCategories
BASE_CONTAINERS_STYLES, ColoredContainer, Combobox, FieldCheckbox, Group, GroupTitle,
InputField, Link, ObjectPropertyInfoForm, SubmittingForm, TabContainerPanelComponent,
Textarea, useClipboard, useMapResource, useObjectPropertyCategories
} from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import { AuthProviderConfigurationParametersFragment, CachedMapAllKey } from '@cloudbeaver/core-sdk';
@@ -56,7 +56,7 @@ export const AuthConfigurationOptions: TabContainerPanelComponent<IAuthConfigura
<SubmittingForm ref={formRef} onSubmit={state.save}>
<ColoredContainer parent gap overflow>
<Group small gap>
<ComboboxNew
<Combobox
name='providerId'
state={state.config}
items={identityProviders}
@@ -70,8 +70,8 @@ export const AuthConfigurationOptions: TabContainerPanelComponent<IAuthConfigura
fill
>
{translate('administration_identity_providers_provider')}
</ComboboxNew>
<InputFieldNew
</Combobox>
<InputField
name='id'
state={state.config}
readOnly={state.readonly || edit}
@@ -81,8 +81,8 @@ export const AuthConfigurationOptions: TabContainerPanelComponent<IAuthConfigura
fill
>
{translate('administration_identity_providers_provider_id')}
</InputFieldNew>
<InputFieldNew
</InputField>
<InputField
name='displayName'
state={state.config}
minLength={1}
@@ -93,24 +93,24 @@ export const AuthConfigurationOptions: TabContainerPanelComponent<IAuthConfigura
fill
>
{translate('administration_identity_providers_provider_configuration_name')}
</InputFieldNew>
<TextareaNew
</InputField>
<Textarea
name='description'
state={state.config}
disabled={state.disabled}
readOnly={state.readonly}
>
{translate('administration_identity_providers_provider_configuration_description')}
</TextareaNew>
<InputFieldNew
</Textarea>
<InputField
name='iconURL'
state={state.config}
disabled={state.disabled}
readOnly={state.readonly}
>
{translate('administration_identity_providers_provider_configuration_icon_url')}
</InputFieldNew>
<FieldCheckboxNew
</InputField>
<FieldCheckbox
id={edit ? state.config.id : 'AuthConfigurationDisabled'}
name='disabled'
state={state.config}
@@ -118,14 +118,14 @@ export const AuthConfigurationOptions: TabContainerPanelComponent<IAuthConfigura
readOnly={state.readonly}
>
{translate('administration_identity_providers_provider_configuration_disabled')}
</FieldCheckboxNew>
</FieldCheckbox>
</Group>
{parameters.isLoaded() && parameters.data && (
<>
{isUncategorizedExists && (
<Group small gap vertical>
<GroupTitle>{translate('administration_identity_providers_provider_configuration_parameters')}</GroupTitle>
<ObjectPropertyInfoFormNew
<ObjectPropertyInfoForm
state={state.config.parameters}
properties={parameters.data}
category={null}
@@ -137,7 +137,7 @@ export const AuthConfigurationOptions: TabContainerPanelComponent<IAuthConfigura
{categories.map(category => (
<Group key={category} small gap vertical>
<GroupTitle keepSize>{category}</GroupTitle>
<ObjectPropertyInfoFormNew
<ObjectPropertyInfoForm
state={state.config.parameters}
properties={parameters.data!}
category={category}
@@ -152,7 +152,7 @@ export const AuthConfigurationOptions: TabContainerPanelComponent<IAuthConfigura
{(state.config.metadataLink || state.config.signInLink || state.config.signOutLink) && (
<Group small gap>
<GroupTitle>{translate('administration_identity_providers_provider_configuration_links')}</GroupTitle>
<InputFieldNew
<InputField
name='signInLink'
state={state.config}
title={state.config.signInLink}
@@ -162,8 +162,8 @@ export const AuthConfigurationOptions: TabContainerPanelComponent<IAuthConfigura
onCustomCopy={() => copy(state.config.signInLink!, true)}
>
Sign in
</InputFieldNew>
<InputFieldNew
</InputField>
<InputField
name='signOutLink'
state={state.config}
title={state.config.signOutLink}
@@ -173,7 +173,7 @@ export const AuthConfigurationOptions: TabContainerPanelComponent<IAuthConfigura
onCustomCopy={() => copy(state.config.signOutLink!, true)}
>
Sign out
</InputFieldNew>
</InputField>
{state.config.metadataLink && (
<Link
href={state.config.metadataLink}
@@ -12,7 +12,7 @@ import styled, { css } from 'reshadow';
import {
BASE_CONTAINERS_STYLES, ColoredContainer, Group,
InputFieldNew, SubmittingForm, TabContainerPanelComponent, TextareaNew,
InputField, SubmittingForm, TabContainerPanelComponent, Textarea,
} from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -39,7 +39,7 @@ export const RoleOptions: TabContainerPanelComponent<IRoleFormProps> = observer(
<SubmittingForm ref={formRef} onSubmit={state.save}>
<ColoredContainer parent gap overflow>
<Group small gap>
<InputFieldNew
<InputField
name='roleId'
state={state.config}
readOnly={state.readonly || edit}
@@ -49,8 +49,8 @@ export const RoleOptions: TabContainerPanelComponent<IRoleFormProps> = observer(
fill
>
{translate('administration_roles_role_id')}
</InputFieldNew>
<InputFieldNew
</InputField>
<InputField
name='roleName'
state={state.config}
readOnly={state.readonly}
@@ -59,8 +59,8 @@ export const RoleOptions: TabContainerPanelComponent<IRoleFormProps> = observer(
fill
>
{translate('administration_roles_role_name')}
</InputFieldNew>
<TextareaNew
</InputField>
<Textarea
name='description'
state={state.config}
readOnly={state.readonly}
@@ -69,7 +69,7 @@ export const RoleOptions: TabContainerPanelComponent<IRoleFormProps> = observer(
fill
>
{translate('administration_roles_role_description')}
</TextareaNew>
</Textarea>
</Group>
</ColoredContainer>
</SubmittingForm>
@@ -11,7 +11,7 @@ import { useContext } from 'react';
import styled from 'reshadow';
import { AuthProviderService, AuthProvidersResource, AUTH_PROVIDER_LOCAL_ID } from '@cloudbeaver/core-authentication';
import { BASE_CONTAINERS_STYLES, Container, FormContext, Group, GroupTitle, Loader, PlaceholderComponent, SwitchNew, useExecutor, useMapResource } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, Container, FormContext, Group, GroupTitle, Loader, PlaceholderComponent, Switch, useExecutor, useMapResource } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { useTranslate } from '@cloudbeaver/core-localization';
import { CachedMapAllKey } from '@cloudbeaver/core-sdk';
@@ -58,7 +58,7 @@ export const AuthenticationProviders: PlaceholderComponent<IConfigurationPlaceho
<>
<Group key='authentication' form gap medium>
<GroupTitle>{translate('administration_configuration_wizard_configuration_authentication_group')}</GroupTitle>
<SwitchNew
<Switch
name="anonymousAccessEnabled"
state={serverConfig}
description={translate('administration_configuration_wizard_configuration_anonymous_access_description')}
@@ -68,10 +68,10 @@ export const AuthenticationProviders: PlaceholderComponent<IConfigurationPlaceho
autoHide
>
{translate('administration_configuration_wizard_configuration_anonymous_access')}
</SwitchNew>
</Switch>
<Loader state={providers} inline>
{() => localProvider && styled(styles)(
<SwitchNew
<Switch
key={localProvider.id}
value={localProvider.id}
name="enabledAuthProviders"
@@ -82,7 +82,7 @@ export const AuthenticationProviders: PlaceholderComponent<IConfigurationPlaceho
autoHide
>
{localProvider.label}
</SwitchNew>
</Switch>
)}
</Loader>
</Group>
@@ -101,7 +101,7 @@ export const AuthenticationProviders: PlaceholderComponent<IConfigurationPlaceho
const links = authProviderService.getServiceDescriptionLinks(provider);
return (
<SwitchNew
<Switch
key={provider.id}
value={provider.id}
name="enabledAuthProviders"
@@ -121,7 +121,7 @@ export const AuthenticationProviders: PlaceholderComponent<IConfigurationPlaceho
autoHide
>
{provider.label}
</SwitchNew>
</Switch>
);
})}
</>
@@ -10,7 +10,7 @@
import { observer } from 'mobx-react-lite';
import styled from 'reshadow';
import { BASE_CONTAINERS_STYLES, Group, GroupTitle, InputFieldNew } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, Group, GroupTitle, InputField } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import type { ServerConfigInput } from '@cloudbeaver/core-sdk';
import { useStyles } from '@cloudbeaver/core-theming';
@@ -28,7 +28,7 @@ export const ServerConfigurationAdminForm = observer<Props>(function ServerConfi
return styled(style)(
<Group form gap medium>
<GroupTitle>{translate('administration_configuration_wizard_configuration_admin')}</GroupTitle>
<InputFieldNew
<InputField
type="text"
name="adminName"
state={serverConfig}
@@ -38,8 +38,8 @@ export const ServerConfigurationAdminForm = observer<Props>(function ServerConfi
tiny
>
{translate('administration_configuration_wizard_configuration_admin_name')}
</InputFieldNew>
<InputFieldNew
</InputField>
<InputField
type="password"
name="adminPassword"
state={serverConfig}
@@ -49,7 +49,7 @@ export const ServerConfigurationAdminForm = observer<Props>(function ServerConfi
tiny
>
{translate('administration_configuration_wizard_configuration_admin_password')}
</InputFieldNew>
</InputField>
</Group>
);
});
@@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite';
import styled from 'reshadow';
import { AUTH_PROVIDER_LOCAL_ID, UserInfoResource, UsersResource } from '@cloudbeaver/core-authentication';
import { TextPlaceholder, useTab, Loader, useTabState, ExceptionMessage, BASE_CONTAINERS_STYLES, ColoredContainer, ObjectPropertyInfoFormNew, Group } from '@cloudbeaver/core-blocks';
import { TextPlaceholder, useTab, Loader, useTabState, ExceptionMessage, BASE_CONTAINERS_STYLES, ColoredContainer, ObjectPropertyInfoForm, Group } from '@cloudbeaver/core-blocks';
import type { TabContainerPanelComponent } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { useTranslate } from '@cloudbeaver/core-localization';
@@ -132,7 +132,7 @@ export const OriginInfo: TabContainerPanelComponent<IUserFormProps> = observer(f
return styled(style)(
<ColoredContainer parent>
<Group gap large>
<ObjectPropertyInfoFormNew
<ObjectPropertyInfoForm
properties={state.properties}
state={state.state}
readOnly
@@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite';
import { useCallback } from 'react';
import styled, { css } from 'reshadow';
import { BASE_CONTAINERS_STYLES, ColoredContainer, FieldCheckboxNew, Group, GroupTitle, InputFieldNew, TabContainerPanelComponent } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, ColoredContainer, FieldCheckbox, Group, GroupTitle, InputField, TabContainerPanelComponent } from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import { useStyles } from '@cloudbeaver/core-theming';
import { uuid } from '@cloudbeaver/core-utils';
@@ -38,7 +38,7 @@ export const UserInfo: TabContainerPanelComponent<IUserFormProps> = observer(fun
<ColoredContainer parent gap overflow>
<Group small gap vertical overflow>
<GroupTitle keepSize>{translate('authentication_user_credentials')}</GroupTitle>
<InputFieldNew
<InputField
type='text'
name='login'
state={controller.credentials}
@@ -50,10 +50,10 @@ export const UserInfo: TabContainerPanelComponent<IUserFormProps> = observer(fun
required
>
{translate('authentication_user_name')}
</InputFieldNew>
</InputField>
{controller.local && (
<>
<InputFieldNew
<InputField
type='password'
name='password'
state={controller.credentials}
@@ -66,8 +66,8 @@ export const UserInfo: TabContainerPanelComponent<IUserFormProps> = observer(fun
required
>
{translate('authentication_user_password')}
</InputFieldNew>
<InputFieldNew
</InputField>
<InputField
type='password'
name='passwordRepeat'
state={controller.credentials}
@@ -79,7 +79,7 @@ export const UserInfo: TabContainerPanelComponent<IUserFormProps> = observer(fun
required
>
{translate('authentication_user_password_repeat')}
</InputFieldNew>
</InputField>
</>
)}
</Group>
@@ -89,7 +89,7 @@ export const UserInfo: TabContainerPanelComponent<IUserFormProps> = observer(fun
const label = `${role.roleId}${role.roleName && role.roleName !== role.roleId ? ' (' + role.roleName + ')' : ''}`;
const tooltip = `${label}${role.description ? '\n' + role.description : ''}`;
return (
<FieldCheckboxNew
<FieldCheckbox
key={role.roleId}
id={uuid()}
title={tooltip}
@@ -99,7 +99,7 @@ export const UserInfo: TabContainerPanelComponent<IUserFormProps> = observer(fun
onChange={checked => handleRoleChange(role.roleId, checked)}
>
{label}
</FieldCheckboxNew>
</FieldCheckbox>
);
})}
</Group>
@@ -11,7 +11,7 @@ import { useCallback } from 'react';
import styled from 'reshadow';
import type { AuthProvider } from '@cloudbeaver/core-authentication';
import { BASE_CONTAINERS_STYLES, Group, InputFieldNew, useFocus } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, Group, InputField, useFocus } from '@cloudbeaver/core-blocks';
import { useStyles } from '@cloudbeaver/core-theming';
interface Props {
@@ -33,7 +33,7 @@ export const AuthProviderForm = observer<Props>(function AuthProviderForm({
return styled(useStyles(BASE_CONTAINERS_STYLES))(
<Group ref={elementRef} gap small center>
{provider.credentialParameters.map(parameter => parameter.user && (
<InputFieldNew
<InputField
key={parameter.id}
title={parameter.description}
type={parameter.encryption === 'none' ? 'text' : 'password'}
@@ -45,7 +45,7 @@ export const AuthProviderForm = observer<Props>(function AuthProviderForm({
onChange={value => handleChange(parameter.id, value)}
>
{parameter.displayName}
</InputFieldNew>
</InputField>
))}
</Group>
);
@@ -12,7 +12,7 @@ import { useState, useCallback, useEffect } from 'react';
import styled, { css } from 'reshadow';
import { UsersResource } from '@cloudbeaver/core-authentication';
import { BASE_CONTAINERS_STYLES, Container, ErrorMessage, Group, InputFieldNew, SubmittingForm, useErrorDetails, useFocus } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, Container, ErrorMessage, Group, InputField, SubmittingForm, useErrorDetails, useFocus } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { CommonDialogWrapper, DialogComponent, DialogComponentProps } from '@cloudbeaver/core-dialogs';
import { NotificationService } from '@cloudbeaver/core-events';
@@ -113,7 +113,7 @@ export const ChangeUserPasswordDialog: DialogComponent<null, null> = observer(
<SubmittingForm onSubmit={change}>
<Container>
<Group small gap center>
<InputFieldNew
<InputField
ref={focusedRef}
type='password'
name='oldPassword'
@@ -124,8 +124,8 @@ export const ChangeUserPasswordDialog: DialogComponent<null, null> = observer(
required
>
{translate('authentication_user_current_password')}
</InputFieldNew>
<InputFieldNew
</InputField>
<InputField
type='password'
name='newPassword'
autoComplete='new-password'
@@ -136,8 +136,8 @@ export const ChangeUserPasswordDialog: DialogComponent<null, null> = observer(
required
>
{translate('authentication_user_new_password')}
</InputFieldNew>
<InputFieldNew
</InputField>
<InputField
type='password'
name='repeatedPassword'
state={state}
@@ -147,7 +147,7 @@ export const ChangeUserPasswordDialog: DialogComponent<null, null> = observer(
required
>
{translate('authentication_user_password_repeat')}
</InputFieldNew>
</InputField>
</Group>
</Container>
</SubmittingForm>
@@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite';
import { useState, useCallback, useRef, useEffect } from 'react';
import { css } from 'reshadow';
import { Button, InputFieldNew } from '@cloudbeaver/core-blocks';
import { Button, InputField } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { CommonDialogWrapper, DialogComponent, DialogComponentProps } from '@cloudbeaver/core-dialogs';
import { useTranslate } from '@cloudbeaver/core-localization';
@@ -79,14 +79,14 @@ export const FilterCustomValueDialog: DialogComponent<IPayload, string | number>
noOverflow
onReject={rejectDialog}
>
<InputFieldNew
<InputField
ref={inputRef}
name='customValue'
value={value}
onChange={setValue}
>
{payload.inputTitle}
</InputFieldNew>
</InputField>
</CommonDialogWrapper>
);
}
@@ -10,7 +10,7 @@ import { observable } from 'mobx';
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { BASE_CONTAINERS_STYLES, TabContainerPanelComponent, TabList, TabsState, TextareaNew, UNDERLINE_TAB_STYLES, useObservableRef } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, TabContainerPanelComponent, TabList, TabsState, Textarea, UNDERLINE_TAB_STYLES, useObservableRef } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { composes, useStyles } from '@cloudbeaver/core-theming';
import { CodeEditorLoader } from '@cloudbeaver/plugin-codemirror';
@@ -48,7 +48,7 @@ const styles = composes(
padding: 0 8px;
padding-bottom: 16px;
}
TextareaNew {
Textarea {
flex: 1;
}
CodeEditorLoader {
@@ -170,7 +170,7 @@ export const TextValuePresentation: TabContainerPanelComponent<IDataValuePanelPr
onBeforeChange={(editor, data, value) => handleChange(value)}
/>
) : (
<TextareaNew
<Textarea
name="value"
rows={3}
value={stringValue}
@@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite';
import styled from 'reshadow';
import { DBObjectResource, NavNodeInfoResource, NavTreeResource } from '@cloudbeaver/core-app';
import { ColoredContainer, Loader, TextPlaceholder, useObjectPropertyCategories, GroupTitle, ObjectPropertyInfoFormNew, Group, useMapResource } from '@cloudbeaver/core-blocks';
import { ColoredContainer, Loader, TextPlaceholder, useObjectPropertyCategories, GroupTitle, ObjectPropertyInfoForm, Group, useMapResource } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES } from '@cloudbeaver/core-blocks';
import { ConnectionInfoResource } from '@cloudbeaver/core-connections';
import { useService } from '@cloudbeaver/core-di';
@@ -59,7 +59,7 @@ export const ObjectProperties = observer<Props>(function ObjectProperties({
<ColoredContainer overflow parent gap>
{isUncategorizedExists && (
<Group gap large>
<ObjectPropertyInfoFormNew
<ObjectPropertyInfoForm
properties={properties}
category={null}
small
@@ -70,7 +70,7 @@ export const ObjectProperties = observer<Props>(function ObjectProperties({
{categories.map(category => (
<Group key={category} gap large>
<GroupTitle>{category}</GroupTitle>
<ObjectPropertyInfoFormNew
<ObjectPropertyInfoForm
properties={properties}
category={category}
small
@@ -8,7 +8,7 @@
import { observer } from 'mobx-react-lite';
import { FieldCheckboxNew, InputFieldNew } from '@cloudbeaver/core-blocks';
import { FieldCheckbox, InputField } from '@cloudbeaver/core-blocks';
import type { ObjectPropertyProps } from '../../formControls';
import { additionalProps, filterProperty, getValue, matchType } from '../../helpers';
@@ -25,7 +25,7 @@ export const ObjectProperty = observer<ObjectPropertyProps>(function ObjectPrope
<>
{matchType(objectProperty.dataType) === 'checkbox'
? (
<FieldCheckboxNew
<FieldCheckbox
className={className}
title={objectProperty.description}
name={objectProperty.id}
@@ -34,10 +34,10 @@ export const ObjectProperty = observer<ObjectPropertyProps>(function ObjectPrope
{...additionalProps(objectProperty)}
>
{objectProperty.displayName}
</FieldCheckboxNew>
</FieldCheckbox>
)
: (
<InputFieldNew
<InputField
className={className}
title={objectProperty.description}
name={objectProperty.id}
@@ -45,7 +45,7 @@ export const ObjectProperty = observer<ObjectPropertyProps>(function ObjectPrope
readOnly
{...additionalProps(objectProperty)}
>{objectProperty.displayName}
</InputFieldNew>
</InputField>
)}
</>
);
@@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { useAppVersion } from '@cloudbeaver/core-app';
import { BASE_CONTAINERS_STYLES, Button, ColoredContainer, FormFieldDescriptionNew, Group, IconOrImage, Link, TextPlaceholder } from '@cloudbeaver/core-blocks';
import { BASE_CONTAINERS_STYLES, Button, ColoredContainer, FormFieldDescription, Group, IconOrImage, Link, TextPlaceholder } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { CommonDialogWrapper, DialogComponentProps } from '@cloudbeaver/core-dialogs';
import { useTranslate } from '@cloudbeaver/core-localization';
@@ -29,7 +29,7 @@ const productInfoDialogStyles = css`
display: flex;
white-space: pre-wrap;
}
FormFieldDescriptionNew {
FormFieldDescription {
white-space: pre-wrap;
}
IconOrImage {
@@ -72,33 +72,33 @@ export const ProductInfoDialog = observer<DialogComponentProps<null>>(
) : (
<>
<IconOrImage icon={logoIcon} />
<FormFieldDescriptionNew label={translate('app_product_info_name')}>
<FormFieldDescription label={translate('app_product_info_name')}>
{productInfo.name}
</FormFieldDescriptionNew>
<FormFieldDescriptionNew label={translate('app_product_info_description')}>
</FormFieldDescription>
<FormFieldDescription label={translate('app_product_info_description')}>
{productInfo.description}
</FormFieldDescriptionNew>
</FormFieldDescription>
{productInfo.licenseInfo && (
<FormFieldDescriptionNew label={translate('app_product_info_license_info')}>
<FormFieldDescription label={translate('app_product_info_license_info')}>
{productInfo.licenseInfo}
</FormFieldDescriptionNew>
</FormFieldDescription>
)}
<FormFieldDescriptionNew label={translate('app_product_info_build_time')}>
<FormFieldDescription label={translate('app_product_info_build_time')}>
{productInfo.buildTime}
</FormFieldDescriptionNew>
<FormFieldDescriptionNew label="Backend version">
</FormFieldDescription>
<FormFieldDescription label="Backend version">
{productInfo.version}
</FormFieldDescriptionNew>
<FormFieldDescriptionNew label="Frontend version">
</FormFieldDescription>
<FormFieldDescription label="Frontend version">
{version.frontendVersion}
</FormFieldDescriptionNew>
<FormFieldDescriptionNew label={translate('app_product_info_contacts')}>
<contacts-info as='div'>You can contact us via our
</FormFieldDescription>
<FormFieldDescription label={translate('app_product_info_contacts')}>
<contacts-info>You can contact us via our
<Link href="https://cloudbeaver.io/contact/" target='_blank' rel='noopener noreferrer'> Site </Link>
or
<Link href="https://github.com/dbeaver/cloudbeaver" target='_blank' rel='noopener noreferrer'> Github</Link>
</contacts-info>
</FormFieldDescriptionNew>
</FormFieldDescription>
</>
)}
</Group>
@@ -11,7 +11,7 @@ import styled, { css } from 'reshadow';
import {
Split, Pane, ResizerControls, splitStyles, TextPlaceholder,
Table, TableHeader, TableColumnHeader, TableBody, TextareaNew
Table, TableHeader, TableColumnHeader, TableBody, Textarea
} from '@cloudbeaver/core-blocks';
import { useTranslate } from '@cloudbeaver/core-localization';
import type { SqlExecutionPlanNode } from '@cloudbeaver/core-sdk';
@@ -46,7 +46,7 @@ const styles = composes(
Pane:last-child {
flex: 0 0 150px;
}
TextareaNew > :global(textarea) {
Textarea > :global(textarea) {
border: none !important;
}
`
@@ -97,7 +97,7 @@ export const ExecutionPlanTreeBlock = observer<Props>(function ExecutionPlanTree
</Pane>
<ResizerControls />
<Pane main>
<TextareaNew
<Textarea
className={className}
name='value'
rows={3}
-20
View File
@@ -9782,11 +9782,6 @@ parse-path@^4.0.0:
qs "^6.9.4"
query-string "^6.13.8"
parse-srcset@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1"
integrity sha1-8r0iH2zJcKk42IVWq8WJyqqiveE=
parse-url@^5.0.0:
version "5.0.7"
resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-5.0.7.tgz#2ca3c32816f1a092c35e1f2afe63bb7924dde261"
@@ -11083,11 +11078,6 @@ react-popper@^2.2.5:
react-fast-compare "^3.0.1"
warning "^4.0.2"
react-sanitized-html@^2.x.x:
version "2.0.0"
resolved "https://registry.yarnpkg.com/react-sanitized-html/-/react-sanitized-html-2.0.0.tgz#2ac300ae60e8e7cb28378b1233b9630e415d0241"
integrity sha512-G1n8smzDSqiHoBtvfJqcyvDKXlWTrvARRgWoSKhqeDVxxb9emO4ourS1OYnzV6yxx/G4jLqzaFSx8b6roL29Kw==
react@>=15, react@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
@@ -11757,16 +11747,6 @@ safe-regex@^1.1.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
sanitize-html@^1.x.x:
version "1.27.5"
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.27.5.tgz#6c8149462adb23e360e1bb71cc0bae7f08c823c7"
integrity sha512-M4M5iXDAUEcZKLXkmk90zSYWEtk5NH3JmojQxKxV371fnMh+x9t1rqdmXaGoyEHw3z/X/8vnFhKjGL5xFGOJ3A==
dependencies:
htmlparser2 "^4.1.0"
lodash "^4.17.15"
parse-srcset "^1.0.2"
postcss "^7.0.27"
sass-graph@2.2.5:
version "2.2.5"
resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.5.tgz#a981c87446b8319d96dce0671e487879bd24c2e8"