Merge remote-tracking branch 'origin/devel' into devel

This commit is contained in:
serge-rider
2025-06-14 16:57:35 +02:00
21 changed files with 147 additions and 268 deletions
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -8,20 +8,21 @@
import { observer } from 'mobx-react-lite';
import { isControlPresented } from '../isControlPresented.js';
import { CheckboxMarkup, type CheckboxMod } from './CheckboxMarkup.js';
import { CheckboxMarkup } from './CheckboxMarkup.js';
import { type CheckboxOnChangeEvent, useCheckboxState } from './useCheckboxState.js';
import type { ControlSize } from '@dbeaver/ui-kit/types/controls';
export interface CheckboxBaseProps {
caption?: string;
mod?: CheckboxMod[];
ripple?: boolean;
indeterminate?: boolean;
inverse?: boolean;
size?: ControlSize;
variant?: 'primary' | 'secondary';
}
export type CheckboxInputProps = Omit<
React.InputHTMLAttributes<HTMLInputElement>,
'onChange' | 'type' | 'value' | 'defaultValue' | 'checked' | 'defaultChecked' | 'style'
'onChange' | 'type' | 'value' | 'defaultValue' | 'checked' | 'defaultChecked' | 'style' | 'size'
> & {
value?: string;
defaultValue?: string;
@@ -54,14 +55,10 @@ export const Checkbox: CheckboxType = observer(function Checkbox({
value,
defaultValue,
state,
label,
checked,
defaultChecked,
children,
inverse,
mod,
ripple,
className,
autoHide,
onChange,
...rest
@@ -81,16 +78,5 @@ export const Checkbox: CheckboxType = observer(function Checkbox({
return null;
}
return (
<CheckboxMarkup
{...rest}
name={name}
checked={checkboxState.checked}
label={label}
className={className}
mod={mod}
ripple={ripple}
onChange={checkboxState.change}
/>
);
return <CheckboxMarkup {...rest} name={name} checked={checkboxState.checked} onChange={checkboxState.change} />;
});
@@ -0,0 +1,88 @@
.checkbox-markup-theme--primary {
--dbv-kit-checkbox-background-checked: var(--theme-primary);
--dbv-kit-checkbox-icon-color: var(--theme-on-primary);
--dbv-kit-checkbox-border-color: color-mix(in srgb, var(--theme-on-secondary), white 20%);
--dbv-kit-checkbox-border-color-checked: transparent;
}
.checkbox-markup-theme--secondary {
--dbv-kit-checkbox-background-checked: var(--theme-on-primary);
--dbv-kit-checkbox-icon-color: var(--theme-primary);
--dbv-kit-checkbox-background: transparent;
--dbv-kit-checkbox-border-color: var(--theme-on-primary);
--dbv-kit-checkbox-border-color-checked: var(--theme-on-primary);
}
.checkbox-markup-theme--tertiary {
--dbv-kit-checkbox-background: var(--theme-surface);
--dbv-kit-checkbox-background-checked: var(--theme-surface);
--dbv-kit-checkbox-foreground: var(--theme-on-surface);
--dbv-kit-checkbox-border-color: var(--theme-on-secondary);
--dbv-kit-checkbox-border-color-checked: var(--theme-on-secondary);
--dbv-kit-checkbox-icon-color: var(--theme-on-secondary);
--dbv-kit-control-outline-color: var(--theme-primary);
}
@layer components {
.theme-dark .checkbox-markup {
--dbv-kit-checkbox-hover-shadow-color: color-mix(in srgb, var(--theme-on-secondary), black 50%);
--dbv-kit-checkbox-border-color: color-mix(in srgb, var(--theme-on-secondary), black 20%);
& .dbv-kit-checkbox {
&[data-disabled='true'] {
& .dbv-kit-checkbox__check {
--dbv-kit-checkbox-background-checked: color-mix(in srgb, var(--theme-on-secondary), black 20%);
}
}
}
}
.checkbox-markup {
--dbv-kit-checkbox-hover-shadow-color: color-mix(in srgb, var(--theme-on-secondary), white 80%);
--dbv-kit-checkbox-border-width: 2px;
--dbv-kit-checkbox-border-radius: 2px;
--dbv-kit-checkbox-small-height: 24px;
--dbv-kit-checkbox-medium-height: 28px;
--dbv-kit-checkbox-large-height: 32px;
--dbv-kit-checkbox-xlarge-height: 36px;
--dbv-kit-checkbox-small-font-size: 14px;
--dbv-kit-checkbox-medium-font-size: 14px;
--dbv-kit-checkbox-large-font-size: 16px;
--dbv-kit-checkbox-xlarge-font-size: 18px;
& .checkbox-markup__label {
color: var(--theme-on-surface);
}
& .checkbox-markup__caption {
font-size: calc(var(--dbv-kit-checkbox-font-size) * 0.875);
color: var(--theme-on-secondary);
}
& .dbv-kit-checkbox {
display: flex;
align-items: center;
&[data-disabled='true'] {
& .dbv-kit-checkbox__check {
--dbv-kit-checkbox-background-checked: color-mix(in srgb, var(--theme-on-secondary), white 30%);
}
}
}
& .dbv-kit-checkbox__text {
line-height: calc(var(--dbv-kit-checkbox-font-size) * 1.4);
display: flex;
flex-direction: column;
}
& .dbv-kit-checkbox__check {
margin: calc(var(--dbv-kit-checkbox-font-size) * 0.5);
}
}
}
@@ -1,74 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.checkbox {
composes: theme-checkbox from global;
box-sizing: content-box !important;
.container {
}
.checkboxInput {
composes: theme-checkbox_native-control from global;
.label {
}
.checkboxBackground {
composes: theme-checkbox__background from global;
box-sizing: border-box !important;
}
.checkboxCheckmark {
composes: theme-checkbox__checkmark from global;
}
.checkboxCheckmarkPath {
composes: theme-checkbox__checkmark-path from global;
}
.checkboxMixedmark {
composes: theme-checkbox__mixedmark from global;
}
.checkboxRipple {
composes: theme-checkbox__ripple from global;
}
.checkboxContainer {
display: flex;
align-items: center;
height: 32px;
}
.checkboxLabel {
composes: theme-typography--body2 from global;
cursor: pointer;
}
.checkboxCaption {
composes: theme-text-text-hint-on-light theme-typography--caption from global;
white-space: normal;
}
.primary {
composes: theme-checkbox_primary from global;
}
.surface {
composes: theme-checkbox_surface from global;
}
.small {
composes: theme-checkbox_small from global;
}
.small {
&.checkboxContainer {
& .checkbox {
width: 14px;
height: 14px;
}
& .checkboxBackground {
width: 14px;
height: 14px;
}
}
}
.disabled {
composes: theme-checkbox--disabled from global;
}
.checked {
composes: theme-checkbox--checked from global;
.caption {
}
@@ -1,83 +1,51 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 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 { useLayoutEffect, useRef } from 'react';
import { s } from '../../s.js';
import { Checkbox as UiKitCheckbox } from '@dbeaver/ui-kit';
import type { ControlSize } from '@dbeaver/ui-kit/types/controls';
import { useS } from '../../useS.js';
import './CheckboxMarkup.css';
import CheckboxMarkupStyles from './CheckboxMarkup.module.css';
import { s } from '../../s.js';
export type CheckboxMod = 'primary' | 'surface' | 'small';
interface ICheckboxMarkupProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'style'> {
export { CheckboxMarkupStyles };
interface ICheckboxMarkupProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'style' | 'size'> {
label?: string;
caption?: string;
indeterminate?: boolean;
ripple?: boolean;
mod?: CheckboxMod[];
size?: ControlSize;
theme?: 'primary' | 'secondary' | 'tertiary';
}
export { CheckboxMarkupStyles };
export const CheckboxMarkup: React.FC<ICheckboxMarkupProps> = function CheckboxMarkup({
id,
label,
indeterminate,
className,
title,
mod = ['primary'],
ripple = true,
readOnly,
caption,
size = 'medium',
theme = 'primary',
title,
readOnly,
children,
...rest
}) {
const styles = useS(CheckboxMarkupStyles);
const checkboxRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (checkboxRef.current) {
checkboxRef.current.indeterminate = indeterminate || false;
}
});
return (
<div className={s(styles, { checkboxContainer: true, small: mod.includes('small') }, className)} title={title}>
<div
className={s(styles, {
checkbox: true,
disabled: rest.disabled,
checked: rest.checked,
primary: mod.includes('primary'),
surface: mod.includes('surface'),
small: mod.includes('small'),
})}
>
<input
ref={checkboxRef}
className={s(styles, { checkboxInput: true })}
type="checkbox"
{...rest}
disabled={rest.disabled || readOnly}
id={id || rest.name}
/>
<div className={s(styles, { checkboxBackground: true })}>
<svg className={s(styles, { checkboxCheckmark: true })} viewBox="0 0 24 24">
<path className={s(styles, { checkboxCheckmarkPath: true })} fill="none" d="M1.73,12.91 8.1,19.28 22.79,4.59" />
</svg>
<div className={s(styles, { checkboxMixedmark: true })} />
</div>
{ripple && <div className={s(styles, { checkboxRipple: true })} />}
</div>
{label && (id || rest.name) && (
<label className={s(styles, { checkboxLabel: true })} htmlFor={id || rest.name}>
{label}
{caption && <div className={s(styles, { checkboxCaption: true })}>{caption}</div>}
</label>
)}
<div className={s(styles, { container: true }, 'checkbox-markup', `checkbox-markup-theme--${theme}`, className)} title={title}>
<UiKitCheckbox id={id || rest.name} indeterminate={indeterminate} disabled={rest.disabled || readOnly} size={size} {...rest}>
{label && <span className={s(styles, { label: true }, 'checkbox-markup__label')}>{label}</span>}
{caption && <span className={s(styles, { caption: true }, 'checkbox-markup__caption')}>{caption}</span>}
</UiKitCheckbox>
</div>
);
};
@@ -19,7 +19,6 @@ import './styles/main/fonts.pure.css';
// TODO: important to keep normalize first
import './styles/main/normalize.pure.css';
import './styles/main/typography.pure.scss';
import './styles/UiCheckbox.css';
import './styles/UiIconButton.css';
import './styles/UiSpinner.css';
import './styles/UiInput.css';
@@ -1,15 +0,0 @@
@layer components {
body {
--dbv-kit-checkbox-background: var(--theme-surface);
--dbv-kit-checkbox-background-checked: var(--theme-surface);
--dbv-kit-checkbox-foreground: var(--theme-on-surface);
--dbv-kit-checkbox-border-color: var(--theme-on-secondary);
--dbv-kit-checkbox-border-color-checked: var(--theme-on-secondary);
--dbv-kit-checkbox-icon-color: var(--theme-on-secondary);
--dbv-kit-control-outline-color: var(--theme-primary);
--dbv-kit-checkbox-border-width: 1px;
--dbv-kit-checkbox-check-size: 0.8;
--dbv-kit-checkbox-small-height: 1.375rem;
}
}
@@ -1,71 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@import '@material/checkbox/mixins';
$mdc-checkbox-icon-size: 16px;
@mixin checkbox-core-styles($query: mdc-feature-all()) {
@include mdc-checkbox-core-styles($query);
.theme-checkbox {
@extend .mdc-checkbox;
}
.theme-checkbox_native-control {
@extend .mdc-checkbox__native-control;
&:disabled {
opacity: 0;
}
}
.theme-checkbox__background {
@extend .mdc-checkbox__background;
}
.theme-checkbox__checkmark {
@extend .mdc-checkbox__checkmark;
}
.theme-checkbox__checkmark-path {
@extend .mdc-checkbox__checkmark-path;
}
.theme-checkbox__mixedmark {
@extend .mdc-checkbox__mixedmark;
}
.theme-checkbox__ripple {
@extend .mdc-checkbox__ripple;
}
.theme-checkbox--checked {
@extend .mdc-checkbox--selected;
}
.theme-checkbox--disabled {
@extend .mdc-checkbox--disabled;
}
.theme-checkbox_primary {
$mdc-checkbox-mark-color: $mdc-theme-on-primary;
@include mdc-checkbox-ink-color($mdc-checkbox-mark-color, $query);
@include mdc-checkbox-disabled-ink-color(rgba($mdc-checkbox-mark-color, 0.5), $query);
@include mdc-checkbox-container-colors($mdc-checkbox-border-color, transparent, $mdc-theme-primary, $mdc-theme-primary);
}
.theme-checkbox_surface {
$mdc-checkbox-mark-color: $mdc-theme-primary;
@include mdc-checkbox-ink-color($mdc-checkbox-mark-color, $query);
@include mdc-checkbox-disabled-ink-color(rgba($mdc-checkbox-mark-color, 0.5), $query);
@include mdc-checkbox-container-colors($mdc-theme-surface, transparent, $mdc-theme-surface, $mdc-theme-surface);
}
.theme-checkbox_on_primary {
$mdc-checkbox-mark-color: $mdc-theme-primary;
@include mdc-checkbox-ink-color($mdc-checkbox-mark-color, $query);
@include mdc-checkbox-disabled-ink-color(rgba($mdc-checkbox-mark-color, 0.5), $query);
@include mdc-checkbox-container-colors($mdc-theme-on-primary, transparent, $mdc-theme-on-primary, $mdc-theme-on-primary);
}
.theme-checkbox_small {
@include mdc-checkbox-density(-3);
}
}
@@ -21,7 +21,6 @@
@import './color';
@import './radio';
@import './switch';
@import './checkbox';
@import './placeholder';
@import './form-controls';
@import './link';
@@ -19,7 +19,6 @@
@include form-controls;
@include radio-core-styles;
@include switch-core-styles;
@include checkbox-core-styles;
@include link;
@include placeholder;
@include delimiter($mdc-theme-secondary);
@@ -19,7 +19,6 @@
@include form-controls;
@include radio-core-styles;
@include switch-core-styles;
@include checkbox-core-styles;
@include link;
@include placeholder;
@include delimiter($mdc-theme-secondary);
@@ -15,7 +15,6 @@
@include theme-ripple;
@include radio-core-styles;
@include switch-core-styles;
@include checkbox-core-styles;
@include form-controls;
@include link;
@include placeholder;
@@ -15,7 +15,6 @@
@include theme-ripple;
@include radio-core-styles;
@include switch-core-styles;
@include checkbox-core-styles;
@include form-controls;
@include link;
@include placeholder;
@@ -72,12 +72,7 @@ export const MenuActionElement = observer<IMenuActionElementProps>(function Menu
focusable
onClick={handleClick}
>
<MenuItemElement
label={actionInfo.label}
icon={<Checkbox checked={checked} mod={['primary', 'small']} ripple={false} />}
tooltip={actionInfo.tooltip}
loading={loading}
/>
<MenuItemElement label={actionInfo.label} icon={<Checkbox checked={checked} size="small" />} tooltip={actionInfo.tooltip} loading={loading} />
</MenuItemCheckbox>
);
}
@@ -89,11 +89,7 @@ export const MenuItemRenderer = observer<IMenuItemRendererProps>(function MenuIt
checked={item.checked}
onClick={() => onClick(false)}
>
<MenuItemElement
label={item.label}
icon={<Checkbox checked={item.checked} mod={['primary', 'small']} ripple={false} />}
tooltip={item.tooltip}
/>
<MenuItemElement label={item.label} icon={<Checkbox checked={item.checked} size="small" />} tooltip={item.tooltip} />
</MenuItemCheckbox>
);
}
@@ -63,13 +63,15 @@ export const User = observer<Props>(function User({ user, displayAuthRole, isMan
<TableColumnValue title={teams} ellipsis>
{teams}
</TableColumnValue>
<TableColumnValue>
<Checkbox
checked={user.enabled}
disabled={usersService.isActiveUser(user.userId) || !isManageable}
title={enabledCheckboxTitle}
onChange={handleEnabledCheckboxChange}
/>
<TableColumnValue centerContent>
<div className="tw:flex tw:items-center tw:justify-center">
<Checkbox
checked={user.enabled}
disabled={usersService.isActiveUser(user.userId) || !isManageable}
title={enabledCheckboxTitle}
onChange={handleEnabledCheckboxChange}
/>
</div>
</TableColumnValue>
<TableColumnValue className={clsx(style['gap'], style['overflow'])} flex ellipsis>
<Loader suspense small inline hideMessage>
@@ -352,7 +352,6 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
name="saveCredentials"
state={optionsPart.state}
disabled={formState.isDisabled || readonly || optionsPart.state.sharedCredentials}
mod={['primary']}
title={translate(
!isSharedProject || serverConfigResource.data?.distributed
? 'connections_connection_authentication_save_credentials_for_user_tooltip'
@@ -0,0 +1,8 @@
@layer components {
.formatter {
composes: checkbox-markup-theme--tertiary from global;
--dbv-kit-checkbox-border-width: 1px;
--dbv-kit-checkbox-check-size: 0.8;
--dbv-kit-checkbox-small-height: 1.375rem;
}
}
@@ -9,18 +9,20 @@ import { observer } from 'mobx-react-lite';
import { useContext } from 'react';
import { BooleanFormatter as GridBooleanFormatter } from '@cloudbeaver/plugin-data-grid';
import { getComputed } from '@cloudbeaver/core-blocks';
import { getComputed, s, useS } from '@cloudbeaver/core-blocks';
import { DatabaseEditChangeType } from '@cloudbeaver/plugin-data-viewer';
import { CellContext } from '../../CellRenderer/CellContext.js';
import { DataGridContext } from '../../DataGridContext.js';
import { TableDataContext } from '../../TableDataContext.js';
import type { ICellFormatterProps } from '../ICellFormatterProps.js';
import styles from './BooleanFormatter.module.css';
export const BooleanFormatter = observer<ICellFormatterProps>(function BooleanFormatter() {
const context = useContext(DataGridContext);
const tableDataContext = useContext(TableDataContext);
const cellContext = useContext(CellContext);
const style = useS(styles);
const cell = cellContext.cell;
@@ -50,5 +52,7 @@ export const BooleanFormatter = observer<ICellFormatterProps>(function BooleanFo
tableDataContext.editor.set(cell, nextValue);
}
return <GridBooleanFormatter value={value as boolean | null} onClick={toggleValue} onKeyDown={toggleValue} />;
return (
<GridBooleanFormatter className={s(style, { formatter: true })} value={value as boolean | null} onClick={toggleValue} onKeyDown={toggleValue} />
);
});
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -1,10 +1,3 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.checkbox {
composes: theme-checkbox_on_primary from global;
.container {
composes: checkbox-markup-theme--secondary from global;
}