fix: CB-1151 optimisations

This commit is contained in:
Wroud
2021-08-19 20:34:50 +03:00
parent f6fce1d7be
commit 05eae2b8d3
15 changed files with 114 additions and 70 deletions
@@ -49,5 +49,5 @@ export function useLogViewer() {
props.logViewerService.clearLog();
this.selectItem(null);
},
}, {});
}, null);
}
@@ -10,6 +10,7 @@ import { observer } from 'mobx-react-lite';
import type { ComponentStyle } from '@cloudbeaver/core-theming';
import { filterLayoutFakeProps } from '../../Containers/filterLayoutFakeProps';
import type { ILayoutSizeProps } from '../../Containers/ILayoutSizeProps';
import { isControlPresented } from '../isControlPresented';
import { CheckboxMarkup, CheckboxMod } from './CheckboxMarkup';
@@ -65,6 +66,7 @@ export const Checkbox: CheckboxType = observer(function Checkbox({
onChange,
...rest
}: CheckboxBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps<any>)) {
rest = filterLayoutFakeProps(rest);
const checkboxState = useCheckboxState({
value,
defaultValue,
@@ -11,6 +11,7 @@ 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';
@@ -117,6 +118,7 @@ export const SwitchNew: SwitchType = observer(function SwitchNew({
name,
onChange,
});
rest = filterLayoutFakeProps(rest);
const styles = useStyles(
baseFormControlStylesNew,
switchStyles,
@@ -130,12 +132,12 @@ export const SwitchNew: SwitchType = observer(function SwitchNew({
}
return styled(styles)(
<field as="div" className={className}>
<switch-body as='div'>
<switch-control as='div'>
<switch-control-track as='div' />
<switch-control-underlay as='div'>
<switch-control-thumb as='div' />
<field className={className}>
<switch-body>
<switch-control>
<switch-control-track />
<switch-control-underlay>
<switch-control-thumb />
<switch-input
as='input'
{...rest}
@@ -151,7 +153,7 @@ export const SwitchNew: SwitchType = observer(function SwitchNew({
</switch-control>
<field-label as="label" htmlFor={value || name}>{children}</field-label>
</switch-body>
<field-description as='div'>{description}</field-description>
<field-description>{description}</field-description>
</field>
);
});
@@ -20,6 +20,7 @@ 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';
@@ -148,6 +149,7 @@ export const ComboboxNew: ComboboxType = observer(function ComboboxNew({
onSwitch,
...rest
}: ControlledProps<any, any> | ObjectProps<any, any, any>) {
rest = filterLayoutFakeProps(rest);
const context = useContext(FormContext);
const ref = useRef<HTMLInputElement>(null);
const menu = useMenuState({
@@ -105,9 +105,11 @@ export const InputFieldNew: InputFieldType = observer(function InputFieldNew({
className,
description,
mod,
fill,
small,
medium,
large,
tiny,
autoHide,
onChange,
...rest
@@ -156,7 +158,7 @@ export const InputFieldNew: InputFieldType = observer(function InputFieldNew({
const showRevealPasswordButton = rest.type === 'password' && !rest.readOnly;
return styled(styles)(
<field className={className} {...use({ small, medium, large })}>
<field className={className} {...use({ small, medium, large, tiny })}>
<field-label title={rest.title}>{children}{required && ' *'}</field-label>
<input-container>
<input
@@ -75,6 +75,8 @@ export const TextareaNew: TextareaType = observer(function TextareaNew({
state,
children,
className,
fill,
tiny,
small,
medium,
large,
@@ -100,7 +102,7 @@ export const TextareaNew: TextareaType = observer(function TextareaNew({
const value = state ? state[name] : controlledValue;
return styled(useStyles(baseFormControlStylesNew, styles, style))(
<field className={className} {...use({ small, medium, large, embedded })}>
<field className={className} {...use({ tiny, small, medium, large, embedded })}>
<field-label as='label'>{children}</field-label>
<textarea
{...rest}
@@ -7,7 +7,7 @@
*/
import { observer } from 'mobx-react-lite';
import { useCallback, useRef } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import {
Dialog,
DialogBackdrop,
@@ -64,15 +64,17 @@ function NestedDialog({
const dialogState = useDialogState({ visible });
const styles = useStyles(dialogStyles);
if (!dialogState.visible
useEffect(() => {
if (!dialogState.visible
&& dialogState.visible !== lastVisibility.current
&& !dialog.options?.persistent
) {
rejectDialog(dialog);
} else {
lastVisibility.current = visible;
dialogState.setVisible(visible);
}
) {
rejectDialog(dialog);
} else {
lastVisibility.current = visible;
dialogState.setVisible(visible);
}
});
const handleReject = useCallback(() => rejectDialog(dialog), [dialog, rejectDialog]);
const handleResolve = useCallback(
@@ -6,7 +6,7 @@
* you may not use this file except in compliance with the License.
*/
import { useObserver } from 'mobx-react-lite';
import { observer } from 'mobx-react-lite';
import styled from 'reshadow';
import { Checkbox, Icon, IconOrImage, Radio } from '@cloudbeaver/core-blocks';
@@ -22,41 +22,32 @@ interface MenuPanelItemProps {
style?: ComponentStyle;
}
export const MenuPanelItem: React.FC<MenuPanelItemProps> = function MenuPanelItem({
export const MenuPanelItem: React.FC<MenuPanelItemProps> = observer(function MenuPanelItem({
menuItem,
style = [],
}) {
const { title, panel, icon, isChecked, controlType, separator } = useObserver(() => ({ // TODO: provide title and panel via props
title: menuItem.title,
panel: menuItem.panel,
icon: menuItem.icon,
isChecked: menuItem.isChecked,
controlType: menuItem.type,
separator: menuItem.separator,
}));
let control = null;
if (controlType === 'radio') {
control = <Radio checked={isChecked} mod={['primary', 'small']} ripple={false} />;
} else if (controlType === 'checkbox') {
control = <Checkbox checked={isChecked} mod={['primary', 'small']} style={style} ripple={false} />;
if (menuItem.type === 'radio') {
control = <Radio checked={menuItem.isChecked} mod={['primary', 'small']} ripple={false} />;
} else if (menuItem.type === 'checkbox') {
control = <Checkbox checked={menuItem.isChecked} mod={['primary', 'small']} style={style} ripple={false} />;
}
return styled(useStyles(menuPanelStyles, style))(
<menu-panel-item {...use({ separator })}>
<menu-panel-item {...use({ separator: menuItem.separator })}>
<menu-item-content>
{icon ? (
<IconOrImage icon={icon} />
{menuItem.icon ? (
<IconOrImage icon={menuItem.icon} />
) : control}
</menu-item-content>
<menu-item-text>
<Translate token={title} />
<Translate token={menuItem.title} />
</menu-item-text>
<menu-item-content>
{panel && <Icon name="arrow" viewBox="0 0 16 16" />}
{menuItem.panel && <Icon name="arrow" viewBox="0 0 16 16" />}
</menu-item-content>
</menu-panel-item>
);
};
});
@@ -7,10 +7,8 @@
*/
import { computed } from 'mobx';
import { observer, useObserver } from 'mobx-react-lite';
import {
forwardRef, Ref, useCallback, useEffect, useMemo
} from 'react';
import { observer } from 'mobx-react-lite';
import { Ref, useCallback, useEffect, useMemo } from 'react';
import {
MenuButton,
Menu, MenuItem, MenuStateReturn, useMenuState, MenuItemCheckbox, MenuItemRadio
@@ -204,7 +202,7 @@ type MenuInnerTriggerProps = Omit<React.ButtonHTMLAttributes<any>, 'style'> & {
style?: Style[];
};
export const MenuInnerTrigger = forwardRef(function MenuInnerTrigger(
export const MenuInnerTrigger = observer(function MenuInnerTrigger(
props: MenuInnerTriggerProps,
ref: Ref<HTMLButtonElement>
) {
@@ -212,7 +210,6 @@ export const MenuInnerTrigger = forwardRef(function MenuInnerTrigger(
menuItem, style = [], ...rest
} = props;
const menu = useMenuState();
const panel = useObserver(() => menuItem.panel);
const handleItemClose = useCallback(() => {
menu.hide();
@@ -226,7 +223,7 @@ export const MenuInnerTrigger = forwardRef(function MenuInnerTrigger(
<MenuPanelItem menuItem={menuItem} style={style} />
</box>
</MenuButton>
<MenuPanel panel={panel!} menu={menu} style={style} onItemClose={handleItemClose} />
<MenuPanel panel={menuItem.panel!} menu={menu} style={style} onItemClose={handleItemClose} />
</>
);
});
}, { forwardRef: true });
+13 -3
View File
@@ -6,8 +6,8 @@
* you may not use this file except in compliance with the License.
*/
import { useObserver } from 'mobx-react-lite';
import { useMemo, useRef, useState } from 'react';
import { autorun } from 'mobx';
import { useEffect, useMemo, useRef, useState } from 'react';
import { create } from 'reshadow';
import { useService } from '@cloudbeaver/core-di';
@@ -36,10 +36,20 @@ export function useStyles(
const [patch, forceUpdate] = useState(0);
const loadedStyles = useRef<BaseStyles[]>([]);
const themeService = useService(ThemeService);
const currentThemeId = useObserver(() => themeService.currentThemeId);
const [currentThemeId, setCurrentThemeId] = useState(themeService.currentThemeId);
const lastThemeRef = useRef<string>(currentThemeId);
const filteredStyles = flat(componentStyles).filter(Boolean) as Style[];
useEffect(() => {
const dispose = autorun(() => {
if (currentThemeId !== themeService.currentThemeId) {
setCurrentThemeId(themeService.currentThemeId);
}
});
return dispose;
}, [currentThemeId, themeService]);
let changed = lastThemeRef.current !== currentThemeId || componentStyles.length !== stylesRef.current.length;
for (let i = 0; !changed && i < componentStyles.length; i++) {
changed = stylesRef.current[i] !== componentStyles[i];
@@ -6,7 +6,7 @@
* you may not use this file except in compliance with the License.
*/
import { observable } from 'mobx';
import { observable, untracked } from 'mobx';
export type MetadataValueGetter<TKey, TValue> = (key: TKey, metadata: MetadataMap<TKey, any>) => TValue;
export type DefaultValueGetter<TKey, TValue> = (key: TKey, metadata: MetadataMap<TKey, TValue>) => TValue;
@@ -59,9 +59,11 @@ export class MetadataMap<TKey, TValue> {
throw new Error('MetadataMap: defaultValue should be provided if defaultValueGetter not set');
}
const value = provider(key, this);
this.data.set(key, value);
this.length++;
untracked(() => {
const value = provider(key, this);
this.data.set(key, value);
this.length++;
});
return this.data.get(key)!;
}
@@ -82,12 +82,18 @@ export class DataPresentationService {
resultIndex: number,
): IDataPresentation[] {
return Array.from(this.dataPresentations.values()).filter(presentation => {
if (
presentation.dataFormat !== undefined
&& supportedDataFormats.includes(presentation.dataFormat)
) {
return false;
}
if (presentation.type !== type || presentation.hidden?.(dataFormat, model, resultIndex)) {
return false;
}
return presentation.dataFormat === undefined
|| supportedDataFormats.includes(presentation.dataFormat);
return true;
});
}
@@ -85,18 +85,34 @@ export class ResultSetSelectAction extends DatabaseDataAction<any, IDatabaseResu
return this.selectedElements.get(ResultSetDataKeysUtils.serialize(row)) || [];
}
set(key: IResultSetPartialKey, selected: boolean): void {
set(key: IResultSetPartialKey, selected: boolean, silent?: boolean): void {
if (key.row === undefined) {
for (const row of this.data.rowKeys) {
this.set({ row, column: key.column }, selected);
this.set({ row, column: key.column }, selected, true);
}
if (!silent) {
this.actions.execute({
type: 'select',
resultId: this.result.id,
key,
selected,
});
}
return;
}
if (key.column === undefined) {
for (const column of this.data.columnKeys) {
this.set({ row: key.row, column }, selected);
this.set({ row: key.row, column }, selected, true);
}
if (!silent) {
this.actions.execute({
type: 'select',
resultId: this.result.id,
key,
selected,
});
}
return;
}
@@ -123,12 +139,14 @@ export class ResultSetSelectAction extends DatabaseDataAction<any, IDatabaseResu
}
}
} finally {
this.actions.execute({
type: 'select',
resultId: this.result.id,
key,
selected,
});
if (!silent) {
this.actions.execute({
type: 'select',
resultId: this.result.id,
key,
selected,
});
}
}
}
@@ -7,13 +7,14 @@
*/
import { observer } from 'mobx-react-lite';
import { useCallback, useRef } from 'react';
import { useCallback, useRef, useState } from 'react';
import styled, { css, use } from 'reshadow';
import { IconOrImage, SubmittingForm, ToolsPanel } from '@cloudbeaver/core-blocks';
import { composes, useStyles } from '@cloudbeaver/core-theming';
import type { IDatabaseDataModel } from '../../DatabaseDataModel/IDatabaseDataModel';
import { getDefaultRowsCount } from '../../getDefaultRowsCount';
import { TableFooterMenu } from './TableFooterMenu/TableFooterMenu';
const tableFooterStyles = composes(
@@ -77,16 +78,19 @@ export const TableFooter = observer(function TableFooter({
model,
}: TableFooterProps) {
const ref = useRef<HTMLInputElement>(null);
const [limit, setLimit] = useState(model.countGain + '');
const handleChange = useCallback(
() => {
if (!ref.current) {
return;
}
const value = parseInt(ref.current.value, 10);
const value = getDefaultRowsCount(parseInt(ref.current.value, 10));
setLimit(value + '');
if (model.countGain !== value) {
model.setCountGain(value)
.reload();
model.setCountGain(value).reload();
}
},
[model]
@@ -104,8 +108,9 @@ export const TableFooter = observer(function TableFooter({
<input
ref={ref}
type="number"
value={model.countGain}
value={limit}
disabled={disabled}
onChange={e => setLimit(e.target.value)}
onBlur={handleChange}
{...use({ mod: 'surface' })}
/>
@@ -13,6 +13,9 @@ const fetchingSettings = {
};
export function getDefaultRowsCount(count?: number): number {
if (typeof count === 'number' && Number.isNaN(count)) {
count = 0;
}
return count !== undefined
? Math.max(
fetchingSettings.fetchMin,