From d56405af7b42006458d126fe16b3fc73164a2618 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Sun, 23 Aug 2026 01:38:56 +0700 Subject: [PATCH] feat(web): upgrade lists to ReUI Table v9 and EventCalendar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Единый kitDataGridTableLayout и ResourcePage/FrameDataGrid на всех списках. Календарь задач переведён на EventCalendar, lookup — на cascader, у операций появился вид доски. Удалены settings-7 и самописные DataGridSection/toolbar. Co-authored-by: Cursor --- apps/web/eslint.config.js | 3 + apps/web/package.json | 5 +- .../access/access-api-keys-card.tsx | 72 +- .../access/access-api-keys-grid.tsx | 66 +- .../analytics/analytics-card-shell.tsx | 4 + .../data-grid-base-7/components/columns.tsx | 324 ++ .../components/data-grid-view.tsx | 355 ++ .../data-grid-base-7/components/data.tsx | 394 +++ .../blocks/data-grid-base-7/page.tsx | 15 + .../components/columns.tsx | 394 +++ .../components/data-grid-view.tsx | 679 ++++ .../data-grid-filtering-2/components/data.tsx | 384 +++ .../blocks/data-grid-filtering-2/page.tsx | 15 + .../empty-state-14/components/empty-state.tsx | 106 + .../components/blocks/empty-state-14/page.tsx | 12 + .../blocks/settings-16/components/data.tsx | 147 + .../components/integration-settings.tsx | 109 + .../components/blocks/settings-16/page.tsx | 15 + .../settings-3/components/color-picker.tsx | 40 + .../blocks/settings-3/components/data.tsx | 109 + .../components/editor-preferences.tsx | 57 + .../components/general-settings.tsx | 267 ++ .../settings-3/components/setting-field.tsx | 69 + .../{settings-7 => settings-3}/page.tsx | 6 +- .../components/account-settings.tsx | 116 - .../settings-7/components/billing-tab.tsx | 180 - .../blocks/settings-7/components/data.tsx | 187 -- .../components/notifications-tab.tsx | 223 -- .../components/profile-avatar-upload.tsx | 103 - .../settings-7/components/profile-tab.tsx | 217 -- .../settings-7/components/security-tab.tsx | 257 -- .../settings-7/components/setting-row.tsx | 2 - .../settings-7/components/settings-card.tsx | 2 - .../components/settings-field-group.tsx | 2 - .../blocks/settings-7/components/utils.ts | 22 - .../blocks/wizard-2/components/data.tsx | 194 ++ .../components/procurement-vendor-steps.tsx | 646 ++++ .../components/procurement-vendor-wizard.tsx | 426 +++ .../src/components/blocks/wizard-2/page.tsx | 9 + .../dashboard/dashboard-modules-grid.tsx | 326 +- .../dashboard/dashboard-recent-jobs-grid.tsx | 40 +- .../dashboard-recent-revisions-grid.tsx | 34 +- apps/web/src/components/data-grid-cell.tsx | 49 +- apps/web/src/components/data-grid-shell.tsx | 125 - apps/web/src/components/data-grid-toolbar.tsx | 77 - .../directories-communities-grid.tsx | 67 +- .../directories/directories-doh-grid.tsx | 67 +- .../src/components/lookup/lookup-add-step.tsx | 148 +- .../components/lookup/lookup-matches-grid.tsx | 116 +- .../modules/module-entries-grid.tsx | 224 +- .../modules/module-entries-section.tsx | 67 +- .../components/modules/modules-list-grid.tsx | 116 +- .../monitoring/monitoring-ready-grid.tsx | 67 +- .../network/network-discovered-peers-card.tsx | 43 +- .../components/network/network-peers-card.tsx | 41 +- .../components/network/network-peers-grid.tsx | 17 +- .../network/network-speakers-card.tsx | 40 +- .../network/network-speakers-grid.tsx | 19 +- .../operations/operations-jobs-card.tsx | 99 +- .../operations/operations-jobs-grid.tsx | 89 +- .../operations/operations-jobs-kanban.tsx | 113 + .../operations/operations-revisions-grid.tsx | 60 +- apps/web/src/components/panel-card.tsx | 3 +- .../reui-kit/data-grid-kit-defaults.test.ts | 29 + .../reui-kit/expandable-resource-grid.tsx | 25 + .../src/components/reui-kit/filter-utils.ts | 145 +- .../components/reui-kit/frame-data-grid.tsx | 465 ++- apps/web/src/components/reui-kit/index.ts | 13 +- .../src/components/reui-kit/resource-page.tsx | 410 ++- .../components/reui-kit/settings-shell.tsx | 5 +- apps/web/src/components/reui/autocomplete.tsx | 5 +- .../reui/cascader/cascader-async.tsx | 864 +++++ .../reui/cascader/cascader-columns.tsx | 263 ++ .../reui/cascader/cascader-context.tsx | 316 ++ .../reui/cascader/cascader-footer.tsx | 731 ++++ .../reui/cascader/cascader-i18n.tsx | 92 + .../reui/cascader/cascader-item.tsx | 1069 ++++++ .../components/reui/cascader/cascader-lib.tsx | 854 +++++ .../components/reui/cascader/cascader-nav.tsx | 637 ++++ .../reui/cascader/cascader-types.tsx | 209 ++ .../reui/cascader/cascader-virtual.tsx | 457 +++ .../src/components/reui/cascader/cascader.tsx | 2932 +++++++++++++++++ .../data-grid/data-grid-column-filter.tsx | 17 +- .../data-grid/data-grid-column-header.tsx | 84 +- .../data-grid/data-grid-column-visibility.tsx | 11 +- .../reui/data-grid/data-grid-pagination.tsx | 24 +- .../reui/data-grid/data-grid-scroll-area.tsx | 134 +- .../data-grid/data-grid-table-dnd-rows.tsx | 615 +++- .../reui/data-grid/data-grid-table-dnd.tsx | 191 +- .../data-grid/data-grid-table-virtual.tsx | 470 ++- .../reui/data-grid/data-grid-table.tsx | 1000 ++++-- .../components/reui/data-grid/data-grid.tsx | 391 ++- .../web/src/components/reui/date-selector.tsx | 8 +- .../event-calendar-agenda-view.tsx | 237 ++ .../event-calendar/event-calendar-content.tsx | 80 + .../event-calendar/event-calendar-dnd.tsx | 1064 ++++++ .../event-calendar/event-calendar-event.tsx | 555 ++++ .../event-calendar/event-calendar-i18n.tsx | 291 ++ .../event-calendar/event-calendar-lib.tsx | 677 ++++ .../event-calendar-month-view.tsx | 1289 ++++++++ .../event-calendar/event-calendar-nav.tsx | 611 ++++ .../event-calendar-recurrence.tsx | 592 ++++ .../event-calendar-resource-view.tsx | 812 +++++ .../event-calendar-time-grid.tsx | 1358 ++++++++ .../event-calendar/event-calendar-types.tsx | 240 ++ .../reui/event-calendar/event-calendar.tsx | 1913 +++++++++++ apps/web/src/components/reui/filters.tsx | 1920 ----------- .../reui/filters/filters-advanced.tsx | 2081 ++++++++++++ .../reui/filters/filters-builder.tsx | 303 ++ .../components/reui/filters/filters-chip.tsx | 1069 ++++++ .../reui/filters/filters-context.tsx | 662 ++++ .../components/reui/filters/filters-date.tsx | 213 ++ .../components/reui/filters/filters-dnd.tsx | 702 ++++ .../components/reui/filters/filters-draft.tsx | 187 ++ .../reui/filters/filters-editors.tsx | 1341 ++++++++ .../components/reui/filters/filters-i18n.tsx | 151 + .../components/reui/filters/filters-lib.tsx | 539 +++ .../reui/filters/filters-operators.tsx | 227 ++ .../components/reui/filters/filters-query.tsx | 701 ++++ .../components/reui/filters/filters-types.tsx | 558 ++++ .../src/components/reui/filters/filters.tsx | 1228 +++++++ apps/web/src/components/reui/frame.tsx | 37 +- apps/web/src/components/reui/kanban.tsx | 948 ++++++ apps/web/src/components/reui/number-field.tsx | 18 +- apps/web/src/components/reui/rating.tsx | 2 - apps/web/src/components/reui/sortable.tsx | 461 +++ apps/web/src/components/reui/timeline.tsx | 2 + .../schedule/schedule-agenda-panel.tsx | 266 +- .../schedule/schedule-calendar-view.tsx | 181 - .../schedule/schedule-jobs-card.tsx | 70 +- .../schedule/schedule-jobs-grid.tsx | 94 +- .../schedule/schedule-modules-grid.tsx | 76 +- .../components/settings/bird-settings-tab.tsx | 30 +- .../components/settings/settings-kv-grid.tsx | 75 +- .../settings/settings-page-shell.tsx | 6 +- .../settings/settings-tabs-data.tsx | 2 +- apps/web/src/components/ui/svgs/supabase.tsx | 8 +- apps/web/src/hooks/use-client-data-grid.ts | 61 - apps/web/src/lib/data-grid-defaults.ts | 60 - apps/web/src/lib/filters-i18n.ts | 161 +- apps/web/src/lib/ui-surface.ts | 2 +- apps/web/src/routes/_auth/dashboard.tsx | 12 +- apps/web/src/routes/_auth/directories.tsx | 24 +- apps/web/src/routes/_auth/modules/index.tsx | 61 +- apps/web/src/routes/_auth/monitoring.tsx | 24 +- apps/web/src/routes/_auth/operations.tsx | 6 +- apps/web/src/routes/_auth/schedule.tsx | 34 +- packages/ui/src/components/calendar.tsx | 2 - packages/ui/src/components/checkbox.tsx | 2 +- packages/ui/src/components/field.tsx | 4 +- packages/ui/src/components/input-group.tsx | 2 + packages/ui/src/components/select.tsx | 2 + packages/ui/src/components/separator.tsx | 2 - packages/ui/src/components/switch.tsx | 2 +- packages/ui/src/components/tabs.tsx | 21 +- packages/ui/src/components/tooltip.tsx | 2 + pnpm-lock.yaml | 70 +- 157 files changed, 39067 insertions(+), 6110 deletions(-) create mode 100644 apps/web/src/components/blocks/data-grid-base-7/components/columns.tsx create mode 100644 apps/web/src/components/blocks/data-grid-base-7/components/data-grid-view.tsx create mode 100644 apps/web/src/components/blocks/data-grid-base-7/components/data.tsx create mode 100644 apps/web/src/components/blocks/data-grid-base-7/page.tsx create mode 100644 apps/web/src/components/blocks/data-grid-filtering-2/components/columns.tsx create mode 100644 apps/web/src/components/blocks/data-grid-filtering-2/components/data-grid-view.tsx create mode 100644 apps/web/src/components/blocks/data-grid-filtering-2/components/data.tsx create mode 100644 apps/web/src/components/blocks/data-grid-filtering-2/page.tsx create mode 100644 apps/web/src/components/blocks/empty-state-14/components/empty-state.tsx create mode 100644 apps/web/src/components/blocks/empty-state-14/page.tsx create mode 100644 apps/web/src/components/blocks/settings-16/components/data.tsx create mode 100644 apps/web/src/components/blocks/settings-16/components/integration-settings.tsx create mode 100644 apps/web/src/components/blocks/settings-16/page.tsx create mode 100644 apps/web/src/components/blocks/settings-3/components/color-picker.tsx create mode 100644 apps/web/src/components/blocks/settings-3/components/data.tsx create mode 100644 apps/web/src/components/blocks/settings-3/components/editor-preferences.tsx create mode 100644 apps/web/src/components/blocks/settings-3/components/general-settings.tsx create mode 100644 apps/web/src/components/blocks/settings-3/components/setting-field.tsx rename apps/web/src/components/blocks/{settings-7 => settings-3}/page.tsx (50%) delete mode 100644 apps/web/src/components/blocks/settings-7/components/account-settings.tsx delete mode 100644 apps/web/src/components/blocks/settings-7/components/billing-tab.tsx delete mode 100644 apps/web/src/components/blocks/settings-7/components/data.tsx delete mode 100644 apps/web/src/components/blocks/settings-7/components/notifications-tab.tsx delete mode 100644 apps/web/src/components/blocks/settings-7/components/profile-avatar-upload.tsx delete mode 100644 apps/web/src/components/blocks/settings-7/components/profile-tab.tsx delete mode 100644 apps/web/src/components/blocks/settings-7/components/security-tab.tsx delete mode 100644 apps/web/src/components/blocks/settings-7/components/setting-row.tsx delete mode 100644 apps/web/src/components/blocks/settings-7/components/settings-card.tsx delete mode 100644 apps/web/src/components/blocks/settings-7/components/settings-field-group.tsx delete mode 100644 apps/web/src/components/blocks/settings-7/components/utils.ts create mode 100644 apps/web/src/components/blocks/wizard-2/components/data.tsx create mode 100644 apps/web/src/components/blocks/wizard-2/components/procurement-vendor-steps.tsx create mode 100644 apps/web/src/components/blocks/wizard-2/components/procurement-vendor-wizard.tsx create mode 100644 apps/web/src/components/blocks/wizard-2/page.tsx delete mode 100644 apps/web/src/components/data-grid-shell.tsx delete mode 100644 apps/web/src/components/data-grid-toolbar.tsx create mode 100644 apps/web/src/components/operations/operations-jobs-kanban.tsx create mode 100644 apps/web/src/components/reui-kit/data-grid-kit-defaults.test.ts create mode 100644 apps/web/src/components/reui-kit/expandable-resource-grid.tsx create mode 100644 apps/web/src/components/reui/cascader/cascader-async.tsx create mode 100644 apps/web/src/components/reui/cascader/cascader-columns.tsx create mode 100644 apps/web/src/components/reui/cascader/cascader-context.tsx create mode 100644 apps/web/src/components/reui/cascader/cascader-footer.tsx create mode 100644 apps/web/src/components/reui/cascader/cascader-i18n.tsx create mode 100644 apps/web/src/components/reui/cascader/cascader-item.tsx create mode 100644 apps/web/src/components/reui/cascader/cascader-lib.tsx create mode 100644 apps/web/src/components/reui/cascader/cascader-nav.tsx create mode 100644 apps/web/src/components/reui/cascader/cascader-types.tsx create mode 100644 apps/web/src/components/reui/cascader/cascader-virtual.tsx create mode 100644 apps/web/src/components/reui/cascader/cascader.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar-agenda-view.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar-content.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar-dnd.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar-event.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar-i18n.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar-lib.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar-month-view.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar-nav.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar-recurrence.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar-resource-view.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar-time-grid.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar-types.tsx create mode 100644 apps/web/src/components/reui/event-calendar/event-calendar.tsx delete mode 100644 apps/web/src/components/reui/filters.tsx create mode 100644 apps/web/src/components/reui/filters/filters-advanced.tsx create mode 100644 apps/web/src/components/reui/filters/filters-builder.tsx create mode 100644 apps/web/src/components/reui/filters/filters-chip.tsx create mode 100644 apps/web/src/components/reui/filters/filters-context.tsx create mode 100644 apps/web/src/components/reui/filters/filters-date.tsx create mode 100644 apps/web/src/components/reui/filters/filters-dnd.tsx create mode 100644 apps/web/src/components/reui/filters/filters-draft.tsx create mode 100644 apps/web/src/components/reui/filters/filters-editors.tsx create mode 100644 apps/web/src/components/reui/filters/filters-i18n.tsx create mode 100644 apps/web/src/components/reui/filters/filters-lib.tsx create mode 100644 apps/web/src/components/reui/filters/filters-operators.tsx create mode 100644 apps/web/src/components/reui/filters/filters-query.tsx create mode 100644 apps/web/src/components/reui/filters/filters-types.tsx create mode 100644 apps/web/src/components/reui/filters/filters.tsx create mode 100644 apps/web/src/components/reui/kanban.tsx create mode 100644 apps/web/src/components/reui/sortable.tsx delete mode 100644 apps/web/src/components/schedule/schedule-calendar-view.tsx delete mode 100644 apps/web/src/hooks/use-client-data-grid.ts diff --git a/apps/web/eslint.config.js b/apps/web/eslint.config.js index 2629a63..0484a51 100644 --- a/apps/web/eslint.config.js +++ b/apps/web/eslint.config.js @@ -28,6 +28,9 @@ export default tseslint.config( }, { files: ['src/components/reui/**/*.{ts,tsx}'], + linterOptions: { + reportUnusedDisableDirectives: 'off', + }, rules: { '@typescript-eslint/no-unused-vars': 'off', 'react-hooks/exhaustive-deps': 'off', diff --git a/apps/web/package.json b/apps/web/package.json index e2dea18..b9961b7 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -16,6 +16,7 @@ }, "dependencies": { "@base-ui/react": "^1.0.0", + "@date-fns/tz": "^1.5.0", "@dnd-kit/core": "^6.3.1", "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", @@ -26,8 +27,8 @@ "@tanstack/react-query-devtools": "^5.90.2", "@tanstack/react-router": "^1.130.2", "@tanstack/react-router-devtools": "^1.130.2", - "@tanstack/react-table": "^8.21.3", - "@tanstack/react-virtual": "^3.14.4", + "@tanstack/react-table": "^9.1.2", + "@tanstack/react-virtual": "^3.14.10", "class-variance-authority": "^0.7.1", "cmdk": "^1.1.1", "date-fns": "^4.4.0", diff --git a/apps/web/src/components/access/access-api-keys-card.tsx b/apps/web/src/components/access/access-api-keys-card.tsx index ba15238..b71bc91 100644 --- a/apps/web/src/components/access/access-api-keys-card.tsx +++ b/apps/web/src/components/access/access-api-keys-card.tsx @@ -2,9 +2,7 @@ import { useState } from 'react' import { Plus, RefreshCw } from 'lucide-react' import { Button } from '@evobgp/ui/components/button' - import { AccessApiKeysGrid } from '@/components/access/access-api-keys-grid' -import { FrameDataGrid } from '@/components/reui-kit' import { ApiKeyCreateDialog } from '@/components/access/api-key-create-dialog' import { ApiKeyTokenDialog } from '@/components/access/api-key-token-dialog' import { QueryState } from '@/components/query-state' @@ -47,46 +45,38 @@ export function AccessApiKeysCard({ return ( <> - - - - - } + } + onRetry={onRetry} > - } - onRetry={onRetry} - > - {(data) => ( - revoke.mutate(id)} - rotatePending={rotate.isPending} - revokePending={revoke.isPending} - /> - )} - - + {(data) => ( + revoke.mutate(id)} + rotatePending={rotate.isPending} + revokePending={revoke.isPending} + actions={ + <> + + + + } + /> + )} + void rotatePending?: boolean revokePending?: boolean + actions?: ReactNode }) { - const columns = useMemo[]>( + const [filterQuery, setFilterQuery] = useState(() => + createTextFilterQuery('search'), + ) + + const columns = useMemo[]>( () => [ { accessorKey: 'name', header: ({ column }) => , cell: ({ row }) => ( - ), @@ -135,24 +147,24 @@ export function AccessApiKeysGrid({ [onRevoke, onRotate, revokePending, rotatePending], ) - const { table, globalFilter, setGlobalFilter, filteredCount } = useClientDataGrid({ - data: items, - columns, - getSearchText: (row) => - `${row.name} ${row.role} ${row.prefix} ${row.revoked_at ? 'отозван' : 'активен'}`, - getRowId: (row) => row.id, - }) - return ( - setFilterQuery(createTextFilterQuery('search'))} + getFilterFieldValue={(row) => + `${row.name} ${row.role} ${row.prefix} ${row.revoked_at ? 'отозван' : 'активен'}` + } + columns={columns} + data={items} + getRowId={(row) => row.id} isLoading={isLoading} - emptyMessage="Нет ключей" - tableLayout={DATA_GRID_DENSE_LAYOUT} - searchValue={globalFilter} - onSearchChange={setGlobalFilter} - searchPlaceholder="Поиск API-ключей…" + primaryAction={actions} + pinLastColumn + emptyState={{ title: 'Нет ключей' }} /> ) } diff --git a/apps/web/src/components/analytics/analytics-card-shell.tsx b/apps/web/src/components/analytics/analytics-card-shell.tsx index 3c414c7..3870071 100644 --- a/apps/web/src/components/analytics/analytics-card-shell.tsx +++ b/apps/web/src/components/analytics/analytics-card-shell.tsx @@ -10,6 +10,10 @@ import { import { PanelCard } from '@/components/panel-card' +/** Chart Frame shell — chart-1 spacing, not Card. + * @see https://reui.io/preview/base/chart-1 + * @see https://reui.io/docs/components/base/frame + */ export function AnalyticsCardShell({ title, description, diff --git a/apps/web/src/components/blocks/data-grid-base-7/components/columns.tsx b/apps/web/src/components/blocks/data-grid-base-7/components/columns.tsx new file mode 100644 index 0000000..0cee6d9 --- /dev/null +++ b/apps/web/src/components/blocks/data-grid-base-7/components/columns.tsx @@ -0,0 +1,324 @@ +import { type ComponentProps } from "react" +import { Badge } from "@/components/reui/badge" +import { type DataGridFeatures } from "@/components/reui/data-grid/data-grid" +import { DataGridColumnHeader } from "@/components/reui/data-grid/data-grid-column-header" +import { type ColumnDef } from "@tanstack/react-table" + +import { cn } from "@evobgp/ui/lib/utils" +import { Button } from "@evobgp/ui/components/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@evobgp/ui/components/dropdown-menu" +import { type ModuleRecord, type ModuleStatus } from "./data" +import { CalendarDaysIcon, FileTextIcon, StarIcon, MoreHorizontalIcon, CopyIcon, ArchiveIcon } from "lucide-react" + +export type ModuleRowAction = "open" | "favorite" | "duplicate" | "archive" + +const moduleStatusVariant: Record< + ModuleStatus, + ComponentProps["variant"] +> = { + Planned: "info-outline", + Backlog: "outline", + "In Progress": "warning-outline", +} + +const moduleStatusDotClass: Record = { + Planned: "bg-sky-500 dark:bg-sky-400", + Backlog: "bg-muted-foreground/50", + "In Progress": "bg-amber-500 dark:bg-amber-400", +} + +function DotSeparator() { + return ( +