From adbf8ac702b1fac695c23b7e8024331c68099a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B5=D0=BC=D0=BA=D0=B5=20=D0=94=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B5=D0=B2=D0=B8?= =?UTF-8?q?=D1=87?= Date: Thu, 13 Jun 2024 16:04:25 +0500 Subject: [PATCH] Add edi-ui & remove custom utils & components --- db-viewer-ui/package.json | 1 + .../Components/Accordion/Accordion.styles.ts | 80 ------ .../src/Components/Accordion/Accordion.tsx | 250 ------------------ .../src/Components/AllowCopyToClipboard.tsx | 28 -- .../DateTimeRangePicker/DatePicker.tsx | 13 +- .../DateTimeRangePicker/DateTimePicker.tsx | 13 +- .../DateTimePickerWithTimeZone.tsx | 34 +-- .../DateTimeRangePicker/TimePicker.tsx | 10 +- .../Components/ErrorHandling/ErrorModal.tsx | 3 +- .../Components/ObjectFilter/ObjectFilter.tsx | 8 +- .../Components/ObjectTypes/ObjectTypes.tsx | 2 +- .../ObjectViewer/ObjectItemRender.tsx | 2 +- .../Components/ObjectViewer/ObjectKeys.tsx | 3 +- .../ObjectViewer/ObjectRenderer.tsx | 134 +++++----- .../Components/ObjectViewer/ObjectViewer.tsx | 53 ++-- .../src/Containers/ObjectDetailsContainer.tsx | 2 +- db-viewer-ui/src/DbViewerApplication.tsx | 76 +++--- .../src/Domain/DataTypes/DateTimeRange.tsx | 1 - db-viewer-ui/src/Domain/DataTypes/Time.ts | 3 - .../Objects/ObjectSearchQueryMapping.ts | 3 +- .../Objects/PropertyMetaInformationUtils.tsx | 2 +- .../src/Domain/Utils/ConvertTimeUtil.tsx | 27 -- db-viewer-ui/src/Domain/Utils/DateUtils.ts | 34 --- db-viewer-ui/src/Domain/Utils/StringUtils.tsx | 29 -- db-viewer-ui/src/Domain/Utils/TimeUtils.ts | 22 -- .../stories/Commons/DatePicker.stories.tsx | 2 +- .../tests/Commons/stampToTicks.test.tsx | 21 -- db-viewer-ui/yarn.lock | 60 ++++- 28 files changed, 232 insertions(+), 684 deletions(-) delete mode 100644 db-viewer-ui/src/Components/Accordion/Accordion.styles.ts delete mode 100644 db-viewer-ui/src/Components/Accordion/Accordion.tsx delete mode 100644 db-viewer-ui/src/Components/AllowCopyToClipboard.tsx delete mode 100644 db-viewer-ui/src/Domain/DataTypes/DateTimeRange.tsx delete mode 100644 db-viewer-ui/src/Domain/DataTypes/Time.ts delete mode 100644 db-viewer-ui/src/Domain/Utils/ConvertTimeUtil.tsx delete mode 100644 db-viewer-ui/src/Domain/Utils/DateUtils.ts delete mode 100644 db-viewer-ui/src/Domain/Utils/StringUtils.tsx delete mode 100644 db-viewer-ui/src/Domain/Utils/TimeUtils.ts delete mode 100644 db-viewer-ui/tests/Commons/stampToTicks.test.tsx diff --git a/db-viewer-ui/package.json b/db-viewer-ui/package.json index 611bd160..023befd9 100644 --- a/db-viewer-ui/package.json +++ b/db-viewer-ui/package.json @@ -47,6 +47,7 @@ "react-router-dom": ">=6 <7" }, "dependencies": { + "@skbkontur/edi-ui": "^0.2.4", "@skbkontur/react-stack-layout": "^1.0.3", "@skbkontur/react-ui-validations": "^1.8.3", "date-fns": "^2.29.1", diff --git a/db-viewer-ui/src/Components/Accordion/Accordion.styles.ts b/db-viewer-ui/src/Components/Accordion/Accordion.styles.ts deleted file mode 100644 index cc2f761d..00000000 --- a/db-viewer-ui/src/Components/Accordion/Accordion.styles.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { css } from "@skbkontur/react-ui/lib/theming/Emotion"; -import { Theme } from "@skbkontur/react-ui/lib/theming/Theme"; - -import { baseSize } from "../Layouts/CommonLayout.styles"; - -export const jsStyles = { - valueWrapper(): string { - return css` - padding-left: ${4 * baseSize}px; - `; - }, - - titleBlockHasTitle(t: Theme): string { - return css` - &:hover a { - color: ${t.linkColor}; - } - `; - }, - - toggleAllLink(): string { - return css` - display: inline-block; - margin-left: ${2 * baseSize}px; - `; - }, - - stringWrapper(t: Theme): string { - return css` - padding: ${baseSize}px 0 ${baseSize}px ${4 * baseSize}px; - - & + .stringWrapper { - border-top: 1px solid ${t.borderColorGrayLight}; - } - `; - }, - - toggleButton(): string { - return css` - color: inherit; - font-size: inherit; - font-family: inherit; - background: none; - border: none; - padding: ${baseSize}px 0; - margin-left: ${-4 * baseSize}px; - cursor: pointer; - outline: none; - text-transform: capitalize; - `; - }, - - toggleButtonText(): string { - return css` - margin-left: ${baseSize}px; - `; - }, - - title(): string { - return css` - text-transform: capitalize; - min-width: 140px; - display: inline-block; - padding-right: ${2 * baseSize}px; - `; - }, - - value(): string { - return css` - min-width: 1%; - word-wrap: break-word; - `; - }, - - mutedKeyword(t: Theme): string { - return css` - color: ${t.textColorDisabled}; - `; - }, -}; diff --git a/db-viewer-ui/src/Components/Accordion/Accordion.tsx b/db-viewer-ui/src/Components/Accordion/Accordion.tsx deleted file mode 100644 index b32476ff..00000000 --- a/db-viewer-ui/src/Components/Accordion/Accordion.tsx +++ /dev/null @@ -1,250 +0,0 @@ -import { ArrowShapeTriangleADownIcon16Regular } from "@skbkontur/icons/ArrowShapeTriangleADownIcon16Regular"; -import { ArrowShapeTriangleARightIcon16Regular } from "@skbkontur/icons/ArrowShapeTriangleARightIcon16Regular"; -import { Fill, Fit, RowStack } from "@skbkontur/react-stack-layout"; -import { ThemeContext, Hint, Link } from "@skbkontur/react-ui"; -import { Theme } from "@skbkontur/react-ui/lib/theming/Theme"; -import isArray from "lodash/isArray"; -import isEqual from "lodash/isEqual"; -import isPlainObject from "lodash/isPlainObject"; -import React from "react"; - -import { jsStyles } from "./Accordion.styles"; - -type CaptionRenderer = (path: string[]) => null | string; -type ValueRenderer = (target: { [key: string]: any }, path: string[]) => null | React.ReactElement; - -export interface TaskAccordionProps { - renderCaption: null | CaptionRenderer; - renderValue: null | ValueRenderer; - value: { [key: string]: any }; - title: null | string; - pathPrefix?: string[]; - defaultCollapsed?: boolean; - showToggleAll?: boolean; - _internalForceCollapsed?: boolean; // internal prop for recursive behaviour -} - -interface TaskAccordionState { - collapsedSelf: boolean; - collapsedRecursive: boolean; - isForced: boolean; -} - -export class Accordion extends React.Component { - public static defaultProps = { - pathPrefix: [], - }; - - private theme!: Theme; - - public constructor(props: TaskAccordionProps) { - super(props); - const canCollapseSelf = props.title != null; - const defaultCollapsedValue = props.defaultCollapsed || false; - const collapsed = canCollapseSelf && defaultCollapsedValue; - - if (props._internalForceCollapsed !== undefined) { - this.state = { - collapsedSelf: props._internalForceCollapsed, - collapsedRecursive: props._internalForceCollapsed, - isForced: props._internalForceCollapsed, - }; - } else { - this.state = { - collapsedSelf: collapsed, - collapsedRecursive: defaultCollapsedValue, - isForced: false, - }; - } - } - - public shouldComponentUpdate(nextProps: TaskAccordionProps, nextState: TaskAccordionState): boolean { - const isValueChanged = !isEqual(this.props.value, nextProps.value); - const isForceCollapsedChanged = this.props._internalForceCollapsed !== nextProps._internalForceCollapsed; - const isDefaultCollapsedChanged = this.props.defaultCollapsed !== nextProps.defaultCollapsed; - const isStateChanged = !isEqual(this.state, nextState); - return isValueChanged || isForceCollapsedChanged || isDefaultCollapsedChanged || isStateChanged; - } - - public componentDidUpdate(prevProps: TaskAccordionProps): void { - const isForcedRecursively = this.props._internalForceCollapsed !== undefined; - if (isForcedRecursively && this.props._internalForceCollapsed !== prevProps._internalForceCollapsed) { - this.setState({ - collapsedSelf: this.props._internalForceCollapsed as boolean, - collapsedRecursive: this.props._internalForceCollapsed as boolean, - isForced: true, - }); - } - if (this.props.defaultCollapsed !== prevProps.defaultCollapsed) { - this.setState({ - collapsedSelf: this.props.defaultCollapsed as boolean, - collapsedRecursive: this.props.defaultCollapsed as boolean, - isForced: true, - }); - } - } - - public render(): React.ReactElement { - return ( - - {theme => { - this.theme = theme; - return this.renderMain(); - }} - - ); - } - - public renderMain(): React.ReactElement { - const { showToggleAll, value, title } = this.props; - const { collapsedSelf, collapsedRecursive } = this.state; - - const isToggleLinkVisible = showToggleAll && this.isThereItemsToToggleAtFirstLevel(); - const showTitleBlock = title != null || isToggleLinkVisible; - return ( -
- {showTitleBlock && ( - - {this.renderTitle()} - {isToggleLinkVisible && ( - - - {collapsedRecursive ? "Развернуть всё" : "Свернуть всё"} - - - )} - - )} - {value && !collapsedSelf && this.renderValue()} -
- ); - } - - public renderValue(): React.ReactElement[] { - const { value, renderCaption, renderValue, pathPrefix = [], defaultCollapsed } = this.props; - const { collapsedRecursive, isForced } = this.state; - const keys = Object.keys(value); - - let defaultCollapsedValue = true; - let forceCollapsedValue: undefined | boolean; - - if (isForced) { - defaultCollapsedValue = collapsedRecursive; - forceCollapsedValue = collapsedRecursive; - } else { - defaultCollapsedValue = defaultCollapsed || false; - forceCollapsedValue = undefined; - } - - return keys.map(key => { - const valueToRender = value[key]; - if (isPlainObject(valueToRender) || isArray(valueToRender)) { - const newValueRender: null | ValueRenderer = - renderValue != null ? (target, path) => renderValue(value, [key, ...path]) : null; - - const newCaptionRenderer: null | CaptionRenderer = - renderCaption != null ? path => renderCaption([key, ...path]) : null; - - return ( - - ); - } - return ( - - - {this.renderItemTitle(key, [key])}: - - - {(renderValue && renderValue(value, [key])) || - (Array.isArray(value[key]) ? value[key].join(", ") : String(value[key]))} - - - ); - }); - } - - private readonly renderItemTitle = (title: string | null, path: string[]) => { - const { renderCaption } = this.props; - const caption = renderCaption?.(path); - if (caption != null) { - return {title}; - } - return title; - }; - - private readonly renderTitle = () => { - const { title, renderCaption } = this.props; - const { collapsedSelf } = this.state; - if (title == null) { - return null; - } - const caption = renderCaption?.([]); - return ( - - - - - {caption && ( - - {caption} - - )} - - ); - }; - - private readonly toggleCollapseManual = () => { - this.setState(state => ({ collapsedSelf: !state.collapsedSelf, isForced: false })); - }; - - private readonly toggleCollapseAll = () => { - const { title } = this.props; - const needToggleFirstLevel = title != null; - this.setState(state => ({ - collapsedSelf: needToggleFirstLevel ? !state.collapsedRecursive : state.collapsedSelf, - collapsedRecursive: !state.collapsedRecursive, - isForced: true, - })); - }; - - private getPath(pathPrefix: string[], key: string): string { - return [...pathPrefix, key].join("_").replace("[", "").replace("]", ""); - } - - private readonly isThereItemsToToggleAtFirstLevel = (): boolean => - Object.values(this.props.value).some(item => isPlainObject(item) || isArray(item)); -} diff --git a/db-viewer-ui/src/Components/AllowCopyToClipboard.tsx b/db-viewer-ui/src/Components/AllowCopyToClipboard.tsx deleted file mode 100644 index 8c2db197..00000000 --- a/db-viewer-ui/src/Components/AllowCopyToClipboard.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { CopyIcon16Regular } from "@skbkontur/icons/CopyIcon16Regular"; -import { Link, Toast } from "@skbkontur/react-ui"; -import React, { PropsWithChildren } from "react"; - -import { StringUtils } from "../Domain/Utils/StringUtils"; - -export class CopyToClipboardToast { - public static copyText(value: string): void { - navigator.clipboard.writeText(value); - Toast.push("Скопировано в буфер"); - } -} - -export const AllowCopyToClipboard = ({ children }: PropsWithChildren<{}>): React.JSX.Element => { - const childrenRef = React.useRef(null); - - const handleCopy = (): void => { - if (childrenRef.current && !StringUtils.isNullOrWhitespace(childrenRef.current.innerText)) { - CopyToClipboardToast.copyText(childrenRef.current.innerText); - } - }; - return ( - - {children} - } onClick={handleCopy} /> - - ); -}; diff --git a/db-viewer-ui/src/Components/DateTimeRangePicker/DatePicker.tsx b/db-viewer-ui/src/Components/DateTimeRangePicker/DatePicker.tsx index 29e4a6e8..ae84f023 100644 --- a/db-viewer-ui/src/Components/DateTimeRangePicker/DatePicker.tsx +++ b/db-viewer-ui/src/Components/DateTimeRangePicker/DatePicker.tsx @@ -1,12 +1,7 @@ +import { RussianDateFormat, Time, TimeZone, TimeUtils, StringUtils, DateUtils } from "@skbkontur/edi-ui"; import { DatePicker as DefaultDatePicker } from "@skbkontur/react-ui"; import React from "react"; -import { RussianDateFormat } from "../../Domain/DataTypes/DateTimeRange"; -import { Time, TimeZone } from "../../Domain/DataTypes/Time"; -import { DateUtils } from "../../Domain/Utils/DateUtils"; -import { StringUtils } from "../../Domain/Utils/StringUtils"; -import { TimeUtils } from "../../Domain/Utils/TimeUtils"; - interface DatePickerProps { value: Nullable; onChange: (value: Nullable) => void; @@ -88,8 +83,8 @@ export class DatePicker extends React.Component { const { timeZone } = this.props; - const date = DateUtils.convertStringToDate(newStringifiedDate); - const ISODate = DateUtils.convertDateToString(date, null, "yyyy-MM-dd"); + const date = DateUtils.parseDate(newStringifiedDate); + const ISODate = DateUtils.formatDate(date, "yyyy-MM-dd"); const time = this.props.defaultTime || defaultTime; const timeZoneOffset = TimeUtils.getTimeZoneOffsetOrDefault(timeZone); return new Date(`${ISODate}T${time}${TimeUtils.timeZoneOffsetToString(timeZoneOffset)}`); @@ -97,6 +92,6 @@ export class DatePicker extends React.Component, timeZone?: number) => { const timeZoneOffset = TimeUtils.getTimeZoneOffsetOrDefault(timeZone); - return date ? DateUtils.convertDateToString(date, timeZoneOffset) : ""; + return date ? DateUtils.formatDate(date, "dd.MM.yyyy", timeZoneOffset) : ""; }; } diff --git a/db-viewer-ui/src/Components/DateTimeRangePicker/DateTimePicker.tsx b/db-viewer-ui/src/Components/DateTimeRangePicker/DateTimePicker.tsx index db1ccc20..191c87bd 100644 --- a/db-viewer-ui/src/Components/DateTimeRangePicker/DateTimePicker.tsx +++ b/db-viewer-ui/src/Components/DateTimeRangePicker/DateTimePicker.tsx @@ -1,9 +1,6 @@ +import { Time, TimeZone, TimeUtils, DateUtils } from "@skbkontur/edi-ui"; import React from "react"; -import { Time, TimeZone } from "../../Domain/DataTypes/Time"; -import { DateUtils } from "../../Domain/Utils/DateUtils"; -import { TimeUtils } from "../../Domain/Utils/TimeUtils"; - import { DatePicker } from "./DatePicker"; import { jsStyles } from "./DateTimePicker.styles"; import { TimePicker } from "./TimePicker"; @@ -28,13 +25,13 @@ export function DateTimePicker({ const [time, setTime] = React.useState>(null); React.useEffect(() => setTimeToState(value, timeZone), [value, timeZone]); - const handleTimeChange = (e: React.SyntheticEvent, newTime: Time): void => { + const handleTimeChange = (newTime: Time): void => { if (value === null || value === undefined) { return; } const timeZoneOffset = TimeUtils.getTimeZoneOffsetOrDefault(timeZone); - const date = DateUtils.convertDateToString(value, timeZoneOffset, "yyyy-MM-dd"); + const date = DateUtils.formatDate(value, "yyyy-MM-dd", timeZoneOffset); const newDateTime = new Date(`${date}T${newTime}${TimeUtils.timeZoneOffsetToString(timeZoneOffset)}`); onChange(newDateTime); }; @@ -45,7 +42,7 @@ export function DateTimePicker({ } const timeZoneOffset = TimeUtils.getTimeZoneOffsetOrDefault(timeZone); - const time = DateUtils.convertDateToString(date, timeZoneOffset, "HH:mm"); + const time = DateUtils.formatDate(date, "HH:mm", timeZoneOffset); setTime(time); }; @@ -70,7 +67,7 @@ export function DateTimePicker({ error={error} defaultTime={defaultTime} disabled={disabled || value === null} - onChange={handleTimeChange} + onChange={(e, time) => handleTimeChange(time)} /> diff --git a/db-viewer-ui/src/Components/DateTimeRangePicker/DateTimePickerWithTimeZone.tsx b/db-viewer-ui/src/Components/DateTimeRangePicker/DateTimePickerWithTimeZone.tsx index d5a23fb4..65588ac0 100644 --- a/db-viewer-ui/src/Components/DateTimeRangePicker/DateTimePickerWithTimeZone.tsx +++ b/db-viewer-ui/src/Components/DateTimeRangePicker/DateTimePickerWithTimeZone.tsx @@ -1,8 +1,6 @@ +import { DateUtils, Time } from "@skbkontur/edi-ui"; import { Select } from "@skbkontur/react-ui"; -import React from "react"; - -import { Time } from "../../Domain/DataTypes/Time"; -import { DateUtils } from "../../Domain/Utils/DateUtils"; +import React, { useState, useEffect } from "react"; import { DatePicker } from "./DatePicker"; import { jsStyles } from "./DateTimePicker.styles"; @@ -17,19 +15,23 @@ interface DateTimePickerWithTimeZone { timeZoneEditable?: boolean; } -export function DateTimePickerWithTimeZone({ +export const DateTimePickerWithTimeZone = ({ error, defaultTime, value, onChange, disabled, timeZoneEditable, -}: DateTimePickerWithTimeZone): React.ReactElement { - const [time, setTime] = React.useState>(null); - const [offset, setOffset] = React.useState>(null); - const [date, setDate] = React.useState>(null); - React.useEffect(() => loadState(value), [value]); - React.useEffect(() => handleDateTimeChange(date, time, offset), [date, time, offset]); +}: DateTimePickerWithTimeZone): React.ReactElement => { + const [time, setTime] = useState>(null); + const [offset, setOffset] = useState>(null); + const [date, setDate] = useState>(null); + useEffect(() => { + loadState(value); + }, [value]); + useEffect(() => { + handleDateTimeChange(date, time, offset); + }, [date, time, offset]); const handleDateTimeChange = ( newDate: Nullable, @@ -40,7 +42,7 @@ export function DateTimePickerWithTimeZone({ onChange(null); return; } - const date = DateUtils.convertDateToString(newDate, 0, "yyyy-MM-dd"); + const date = DateUtils.formatDate(newDate, "yyyy-MM-dd", 0); const newDateTime = `${date}T${newTime ?? defaultTime}${newOffset ?? ""}`; onChange(newDateTime); }; @@ -53,7 +55,7 @@ export function DateTimePickerWithTimeZone({ setOffset(timeOffset); const dateTimeWithoutTimezone = timeOffset ? dateStr.slice(0, -timeOffset.length) : dateStr; setDate(DateUtils.fromLocalToUtc(new Date(dateTimeWithoutTimezone))); - setTime(DateUtils.convertDateToString(dateTimeWithoutTimezone, null, "HH:mm:ss.SSS")); + setTime(DateUtils.formatDate(dateTimeWithoutTimezone, "HH:mm:ss.SSS")); }; const getTimeZoneString = (date: string): Nullable => { @@ -72,7 +74,7 @@ export function DateTimePickerWithTimeZone({ data-tid="Date" value={date} defaultTime={defaultTime} - onChange={newDate => setDate(newDate)} + onChange={setDate} error={error} disabled={disabled} width={110} @@ -85,7 +87,7 @@ export function DateTimePickerWithTimeZone({ error={error} defaultTime={defaultTime} disabled={disabled || !date} - onChange={(_, newTime) => setTime(newTime)} + onChange={(e, time) => setTime(time)} useSeconds /> @@ -104,4 +106,4 @@ export function DateTimePickerWithTimeZone({ ); -} +}; diff --git a/db-viewer-ui/src/Components/DateTimeRangePicker/TimePicker.tsx b/db-viewer-ui/src/Components/DateTimeRangePicker/TimePicker.tsx index 9edd02df..88e59723 100644 --- a/db-viewer-ui/src/Components/DateTimeRangePicker/TimePicker.tsx +++ b/db-viewer-ui/src/Components/DateTimeRangePicker/TimePicker.tsx @@ -1,9 +1,7 @@ +import { Time, TimeUtils } from "@skbkontur/edi-ui"; import { Input } from "@skbkontur/react-ui"; import React from "react"; -import { Time } from "../../Domain/DataTypes/Time"; -import { DateUtils } from "../../Domain/Utils/DateUtils"; - interface TimePickerProps { error?: boolean; value: Nullable