Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions webapp/packages/core-blocks/src/FormControls/Radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import { observer } from 'mobx-react-lite';
import { useContext, useCallback } from 'react';
import styled, { css } from 'reshadow';
import styled, { css, use } from 'reshadow';

import { useStyles, composes } from '@cloudbeaver/core-theming';

Expand Down Expand Up @@ -46,6 +46,9 @@ const radioStyles = composes(
}
label {
cursor: pointer;
&[|disabled] {
cursor: auto;
}
}
`
);
Expand Down Expand Up @@ -90,6 +93,21 @@ const noRippleStyles = composes(
`
);

const radioState = {
disabled: composes(
css`
radio {
composes: theme-radio--disabled from global;
}
`,
css`
input {
opacity: 0 !important;
}
`
),
};

type BaseProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value' | 'checked'> & {
mod?: Array<keyof typeof radioMod>;
ripple?: boolean;
Expand All @@ -99,7 +117,6 @@ type ControlledProps = BaseProps & {
value?: string | number;
checked?: boolean;
onChange?: (value: string | number, name: string) => any;

state?: never;
};

Expand All @@ -108,7 +125,6 @@ type ObjectProps<TKey extends keyof TState, TState> = BaseProps & {
value: TState[TKey];
state: TState;
onChange?: (value: TState[TKey], name: TKey) => any;

checked?: never;
};

Expand Down Expand Up @@ -166,7 +182,12 @@ export const Radio: RadioType = observer(function Radio({
checked = state[name] === value;
}

return styled(useStyles(radioStyles, ...(mod || []).map(mod => radioMod[mod]), !ripple && noRippleStyles))(
return styled(useStyles(
radioStyles,
...(mod || []).map(mod => radioMod[mod]),
!ripple && noRippleStyles,
rest.disabled && radioState.disabled
))(
<field className={className}>
<radio>
<input
Expand All @@ -184,7 +205,7 @@ export const Radio: RadioType = observer(function Radio({
</radio-background>
{ripple && <radio-ripple />}
</radio>
<label htmlFor={id}>{children}</label>
<label {...use({ disabled: rest.disabled })} htmlFor={id}>{children}</label>
</field>
);
});
5 changes: 3 additions & 2 deletions webapp/packages/core-blocks/src/IconOrImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@ import { StaticImage } from './StaticImage';
export interface IconOrImageProps {
icon: string;
className?: string;
title?: string;
onClick?: () => void;
viewBox?: string;
}

export const IconOrImage = function IconOrImage({ icon, className, onClick, viewBox }: IconOrImageProps) {
export const IconOrImage = function IconOrImage({ icon, className, title, onClick, viewBox }: IconOrImageProps) {
const isStaticIcon = useMemo(
() => icon && (icon.startsWith('platform:') || icon.startsWith('/')),
[icon]
);

if (isStaticIcon) {
return <StaticImage icon={icon} className={className} onClick={onClick} />;
return <StaticImage title={title} icon={icon} className={className} onClick={onClick} />;
}

return <Icon name={icon} className={className} viewBox={viewBox || '0 0 32 32'} onClick={onClick} />;
Expand Down
3 changes: 3 additions & 0 deletions webapp/packages/core-theming/src/styles/_radio.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
.theme-radio_ripple {
composes: mdc-radio__ripple;
}
.theme-radio--disabled {
composes: mdc-radio--disabled;
}

.theme-radio_primary {
$mdc-radio-baseline-theme-color: primary;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Cell } from 'react-data-grid';

import { useMouse, useObjectRef } from '@cloudbeaver/core-blocks';
import { EventContext, EventStopPropagationFlag } from '@cloudbeaver/core-events';
import { isBooleanValuePresentationAvaliable, ResultSetFormatAction } from '@cloudbeaver/plugin-data-viewer';
import { isBooleanValuePresentationAvailable, ResultSetFormatAction } from '@cloudbeaver/plugin-data-viewer';

import { EditingContext } from '../../Editing/EditingContext';
import { DataGridContext } from '../DataGridContext';
Expand Down Expand Up @@ -102,27 +102,20 @@ export const CellRenderer: React.FC<CellRendererProps<any>> = observer(function
return;
}

if (
!this.column.editable
|| this.dataGridContext?.model.isDisabled(this.dataGridContext.resultIndex)
|| (
this.resultColumn
&& isBooleanValuePresentationAvaliable(
this.editor?.getCell(this.rowIdx, Number(this.column.key)),
this.resultColumn
)
)
) {
return;
}
const format = this.dataGridContext?.model.source.getAction(
this.dataGridContext.resultIndex,
ResultSetFormatAction
);
const columnIndex = this.tableDataContext?.getDataColumnIndexFromKey(this.column.key) ?? null;
const handleByBooleanFormatter = this.resultColumn && isBooleanValuePresentationAvailable(
this.editor?.getCell(this.rowIdx, Number(this.column.key)),
this.resultColumn
);

if (
columnIndex === null
!this.column.editable
|| handleByBooleanFormatter
|| columnIndex === null
|| format?.isReadOnly({
row: this.rowIdx,
column: columnIndex,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { injectable } from '@cloudbeaver/core-di';
import { isBooleanValuePresentationAvaliable, ResultSetDataAction, ResultSetFormatAction } from '@cloudbeaver/plugin-data-viewer';
import { isBooleanValuePresentationAvailable, ResultSetDataAction, ResultSetFormatAction } from '@cloudbeaver/plugin-data-viewer';

import { DataGridContextMenuService } from './DataGridContextMenuService';

Expand All @@ -34,7 +34,8 @@ export class DataGridContextMenuCellEditingService {
isHidden(context) {
const format = context.data.model.source.getAction(context.data.resultIndex, ResultSetFormatAction);
return format.isReadOnly({ column: context.data.column, row: context.data.row })
|| context.data.model.isDisabled(context.data.resultIndex);
|| context.data.model.isDisabled(context.data.resultIndex)
|| context.data.model.isReadonly();
},
order: 4,
title: 'data_grid_table_editing',
Expand All @@ -59,7 +60,7 @@ export class DataGridContextMenuCellEditingService {
return true;
}

return isBooleanValuePresentationAvaliable(cellValue, column);
return isBooleanValuePresentationAvailable(cellValue, column);
},
order: 0,
title: 'data_grid_table_editing_open_inline_editor',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const DataGridTable: React.FC<IDataPresentationProps<any, IDatabaseResult

const gridSelectionContext = useGridSelectionContext(tableData, selectionAction);
const editingContext = useEditing({
readonly: model.isReadonly(),
readonly: model.isReadonly() || model.isDisabled(resultIndex),
onEdit: (position, key) => {
const editor = model.source.getEditor(resultIndex);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite';
import { useContext, useRef } from 'react';
import type { FormatterProps } from 'react-data-grid';

import { isBooleanValuePresentationAvaliable, ResultSetFormatAction } from '@cloudbeaver/plugin-data-viewer';
import { isBooleanValuePresentationAvailable, ResultSetFormatAction } from '@cloudbeaver/plugin-data-viewer';

import { DataGridContext } from '../DataGridContext';
import { TableDataContext } from '../TableDataContext';
Expand All @@ -34,7 +34,7 @@ export const CellFormatterFactory: React.FC<IProps> = observer(function CellForm
const formatter = context.model.source.getAction(context.resultIndex, ResultSetFormatAction);
const rawValue = formatter.get(props.row[props.column.key]);

if (resultColumn && isBooleanValuePresentationAvaliable(rawValue, resultColumn)) {
if (resultColumn && isBooleanValuePresentationAvailable(rawValue, resultColumn)) {
formatterRef.current = BooleanFormatter;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ import styled, { use, css } from 'reshadow';

import { ResultSetFormatAction } from '@cloudbeaver/plugin-data-viewer';

import { EditingContext } from '../../../Editing/EditingContext';
import { DataGridContext } from '../../DataGridContext';
import { TableDataContext } from '../../TableDataContext';

const styles = css`
boolean-formatter {
cursor: pointer;
}
boolean-formatter[|disabled] {
cursor: auto;
}
boolean-formatter[|boolean] {
font-family: monospace;
white-space: pre;
Expand All @@ -28,41 +32,36 @@ const styles = css`
}
`;

function getClasses(rawValue: any) {
const classes = [];
if (rawValue === null) {
classes.push('cell-null');
}
return classes.join(' ');
}

export const BooleanFormatter: React.FC<FormatterProps> = observer(function BooleanFormatter({ column, row, rowIdx }) {
const context = useContext(DataGridContext);
const tableDataContext = useContext(TableDataContext);
const editingContext = useContext(EditingContext);

const formatter = context?.model.source.getAction(context.resultIndex, ResultSetFormatAction);
const resultColumn = tableDataContext?.getColumnInfo(column.key);
const rawValue = formatter?.get(row[column.key]) ?? row[column.key];
const value = typeof rawValue === 'string' ? rawValue.toLowerCase() === 'true' : rawValue;
const stringifiedValue = formatter?.toDisplayString(value) ?? String(value);
const valueRepresentation = value === null ? stringifiedValue : `[${value ? 'v' : ' '}]`;
const classes = getClasses(rawValue);
const disabled = !column.editable || !!editingContext?.readonly;

const getNextValue = useCallback((prev: boolean | null) => {
if (!resultColumn?.required && prev === false) {
return null;
const toggleValue = useCallback(() => {
if (disabled) {
return;
}

return !prev;
}, [resultColumn]);
const nextValue = !resultColumn?.required && value === false ? null : !value;

context?.model.source.getEditor(context.resultIndex).setCell(rowIdx, Number(column.key), nextValue);
}, [context, resultColumn, column.key, rowIdx, value, disabled]);

return styled(styles)(
<boolean-formatter
className={classes}
className={value === null ? 'cell-null' : undefined}
as='span'
title={stringifiedValue}
onClick={() => context?.model.source.getEditor(context.resultIndex)
.setCell(rowIdx, Number(column.key), getNextValue(value))}
{...use({ boolean: value !== null })}
onClick={toggleValue}
{...use({ disabled, boolean: value !== null })}
>
{valueRepresentation}
</boolean-formatter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const TextFormatter: React.FC<FormatterProps> = observer(function TextFor
<IconOrImage icon='external-link' viewBox='0 0 24 24' />
</a>
)}
<div className='text-formatter_value'>{value}</div>
<div className='text-formatter__value'>{value}</div>
</div>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const styles = css`
cursor: pointer;
}
IconOrImage {
cursor: auto;
width: 10px;
position: absolute;
right: 2px;
Expand All @@ -41,7 +42,7 @@ export const TableIndexColumnHeader: React.FC<HeaderRendererProps<any>> = functi

return styled(styles)(
<container as='div' title={translate('data_grid_table_index_column_tooltip')} onClick={() => selectionContext.selectTable()}>
{tableDataContext.isReadOnly() && <IconOrImage icon='/icons/lock.png' />}
{tableDataContext.isReadOnly() && <IconOrImage title={translate('data_grid_table_readonly_tooltip')} icon='/icons/lock.png' />}
{props.column.name}
</container>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { createContext } from 'react';

export interface IEditingContext {
readonly readonly: boolean;
edit: (position: CellPosition, key?: string) => void;
closeEditor: (position: CellPosition) => void;
close: () => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function useEditing(options: IEditingOptions): IEditingContext {
}, { options }, { editingCells: observable });

const [context] = useState<IEditingContext>({
readonly: !!optionsRef.readonly,
edit(position: CellPosition, key?: string) {
if (optionsRef.readonly) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ export default [
['data_grid_table_context_menu_filter_dialog_title', 'Edit value'],
['data_grid_table_context_menu_filter_clipboard_permission', 'Give access to clipboard'],
['data_grid_table_index_column_tooltip', 'Select whole table'],
['data_grid_table_readonly_tooltip', 'Read-only'],
];
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ export default [
['data_grid_table_context_menu_filter_dialog_title', 'Редактировать значение'],
['data_grid_table_context_menu_filter_clipboard_permission', 'Дать доступ к буферу обмена'],
['data_grid_table_index_column_tooltip', 'Выбрать всю таблицу'],
['data_grid_table_readonly_tooltip', 'Доступно только для чтения'],
];
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
}
}

.text-formatter_value {
.text-formatter__value {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
Expand Down
Loading