diff --git a/.codegraph/daemon.pid b/.codegraph/daemon.pid index 3090f63..e32141d 100644 --- a/.codegraph/daemon.pid +++ b/.codegraph/daemon.pid @@ -1,6 +1,6 @@ { - "pid": 39884, + "pid": 43636, "version": "0.9.9", "socketPath": "\\\\.\\pipe\\codegraph-97b92efdcc5351da", - "startedAt": 1783489774882 + "startedAt": 1783570299043 } diff --git a/apps/web/src/components/access/api-key-create-dialog.tsx b/apps/web/src/components/access/api-key-create-dialog.tsx index 8f3e6e3..750ec86 100644 --- a/apps/web/src/components/access/api-key-create-dialog.tsx +++ b/apps/web/src/components/access/api-key-create-dialog.tsx @@ -11,15 +11,9 @@ import { } from '@evobgp/ui/components/dialog' import { Input } from '@evobgp/ui/components/input' import { Label } from '@evobgp/ui/components/label' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@evobgp/ui/components/select' import { LoadingButton } from '@/components/loading-button' +import { SelectField } from '@/components/select-field' import { API_KEY_ROLE_ITEMS } from '@/lib/access/api-key-labels' import { useCreateApiKeyMutation } from '@/queries/api-keys' import type { ApiKeyCreate, ApiKeyCreated, ApiKeyRole } from '@/types/api' @@ -89,25 +83,14 @@ export function ApiKeyCreateDialog({ open, onOpenChange, onCreated }: ApiKeyCrea placeholder="CI / оператор UI" /> -
- - -
+ v && setRole(v as ApiKeyRole)} + />
+ - + ) } diff --git a/apps/web/src/components/examples/c-select-4.tsx b/apps/web/src/components/examples/c-select-4.tsx new file mode 100644 index 0000000..6d24acc --- /dev/null +++ b/apps/web/src/components/examples/c-select-4.tsx @@ -0,0 +1,19 @@ +import { Field } from '@evobgp/ui/components/field' + +import { SelectMenu } from '@/components/select-field' + +const items = [ + { label: 'Select an item', value: 'placeholder' as const }, + ...Array.from({ length: 100 }).map((_, i) => ({ + label: `Item ${i}`, + value: `item-${i}` as const, + })), +] + +export function Pattern() { + return ( + + + + ) +} diff --git a/apps/web/src/components/modules/community-select.tsx b/apps/web/src/components/modules/community-select.tsx index 6b05c3f..02162ab 100644 --- a/apps/web/src/components/modules/community-select.tsx +++ b/apps/web/src/components/modules/community-select.tsx @@ -1,14 +1,8 @@ import { useMemo } from 'react' -import { Label } from '@evobgp/ui/components/label' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@evobgp/ui/components/select' +import { Field, FieldLabel } from '@evobgp/ui/components/field' +import { SelectMenu } from '@/components/select-field' import { NONE_OPTION, communityOptionLabel, @@ -49,28 +43,27 @@ export function CommunitySelect({ const selectValue = nullable ? nullableSelectValue(value) : (value ?? '') + const select = ( + { + if (!v) return + onValueChange(nullable ? fromNullableSelect(v) : v) + }} + /> + ) + + if (!label) { + return select + } + return ( -
- {label ? : null} - -
+ + {label} + {select} + ) } diff --git a/apps/web/src/components/modules/module-cdn-source-dialog.tsx b/apps/web/src/components/modules/module-cdn-source-dialog.tsx index c0b7de4..d607417 100644 --- a/apps/web/src/components/modules/module-cdn-source-dialog.tsx +++ b/apps/web/src/components/modules/module-cdn-source-dialog.tsx @@ -10,13 +10,8 @@ import { } from '@evobgp/ui/components/dialog' import { Input } from '@evobgp/ui/components/input' import { Label } from '@evobgp/ui/components/label' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@evobgp/ui/components/select' + +import { SelectField } from '@/components/select-field' import { Button } from '@evobgp/ui/components/button' import { LoadingButton } from '@/components/loading-button' @@ -174,25 +169,13 @@ export function ModuleCdnSourceDialog({ onChange={(e) => setForm((s) => ({ ...s, url: e.target.value }))} />
-
- - -
+ v && setForm((s) => ({ ...s, source_kind: v }))} + />
{mergedProps.rowsPerPageLabel}
- + /> )} diff --git a/apps/web/src/components/select-field.tsx b/apps/web/src/components/select-field.tsx new file mode 100644 index 0000000..b3995ec --- /dev/null +++ b/apps/web/src/components/select-field.tsx @@ -0,0 +1,100 @@ +import type { ComponentProps, ReactNode } from 'react' + +import { Field, FieldDescription, FieldLabel } from '@evobgp/ui/components/field' +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectTrigger, + SelectValue, +} from '@evobgp/ui/components/select' +import { cn } from '@evobgp/ui/lib/utils' + +export type SelectMenuItem = { + value: T + label: ReactNode + disabled?: boolean +} + +type SelectRootProps = ComponentProps + +export interface SelectMenuProps + extends Omit { + items: ReadonlyArray> + value?: T | null + defaultValue?: T | null + onValueChange?: (value: T | null) => void + placeholder?: string + id?: string + triggerClassName?: string + contentClassName?: string + size?: 'sm' | 'default' + side?: ComponentProps['side'] +} + +/** ReUI c-select-4: `items` на Root, опции в `SelectGroup`. */ +export function SelectMenu({ + items, + placeholder, + id, + triggerClassName, + contentClassName, + size = 'default', + side, + value, + defaultValue, + onValueChange, + ...selectProps +}: SelectMenuProps) { + return ( + + ) +} + +export interface SelectFieldProps extends SelectMenuProps { + label?: ReactNode + description?: ReactNode + fieldClassName?: string +} + +export function SelectField({ + label, + description, + fieldClassName, + id, + ...menuProps +}: SelectFieldProps) { + return ( + + {label ? {label} : null} + + {description ? ( + typeof description === 'string' ? ( + {description} + ) : ( + description + ) + ) : null} + + ) +} diff --git a/apps/web/src/routes/_auth/dashboard.tsx b/apps/web/src/routes/_auth/dashboard.tsx index d2c28e0..8d4f2b1 100644 --- a/apps/web/src/routes/_auth/dashboard.tsx +++ b/apps/web/src/routes/_auth/dashboard.tsx @@ -15,20 +15,21 @@ import { useState } from 'react' import { Alert, AlertDescription, AlertTitle } from '@evobgp/ui/components/alert' import { Button } from '@evobgp/ui/components/button' +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@evobgp/ui/components/card' import { Skeleton } from '@evobgp/ui/components/skeleton' +import { DataGridCard } from '@/components/data-grid-shell' import { DashboardNetworkPanel } from '@/components/dashboard/dashboard-network-panel' import { DashboardQuickActions } from '@/components/dashboard/dashboard-quick-actions' import { DashboardRecentJobsGrid } from '@/components/dashboard/dashboard-recent-jobs-grid' import { DashboardRecentRevisionsGrid } from '@/components/dashboard/dashboard-recent-revisions-grid' import { PageHeader } from '@/components/page-header' -import { - Frame, - FrameDescription, - FrameHeader, - FramePanel, - FrameTitle, -} from '@/components/reui/frame' import { SectionCards, type SectionCardItem } from '@/components/section-cards' import { SectionCardsSkeleton } from '@/components/skeletons' @@ -172,58 +173,52 @@ function DashboardComponent() { {initialLoading ? : }
- - - - Недавние задачи - Последние фоновые операции - - {activityLoading ? ( - - ) : ( - - )} - - + + {activityLoading ? ( + + ) : ( + + )} + - - - - Последние ревизии - История конфигураций - - {activityLoading ? ( - - ) : ( - - )} - - + + {activityLoading ? ( + + ) : ( + + )} + - - - - Состояние сети - BGP-сессии и спикеры - + + + Состояние сети + BGP-сессии и спикеры + + {activityLoading ? ( ) : ( )} - - + +
- - - - Быстрые действия - Частые переходы к настройке и деплою - - - - + + + Быстрые действия + Частые переходы к настройке и деплою + + + ) } diff --git a/apps/web/src/routes/_auth/operations.tsx b/apps/web/src/routes/_auth/operations.tsx index e94da12..2b9dfa4 100644 --- a/apps/web/src/routes/_auth/operations.tsx +++ b/apps/web/src/routes/_auth/operations.tsx @@ -7,16 +7,10 @@ import { useState, useMemo } from 'react' import { Alert, AlertDescription, AlertTitle } from '@evobgp/ui/components/alert' import { Button } from '@evobgp/ui/components/button' import { Card, CardContent, CardHeader, CardTitle } from '@evobgp/ui/components/card' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@evobgp/ui/components/select' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@evobgp/ui/components/tabs' import { DataGridCard } from '@/components/data-grid-shell' +import { SelectMenu } from '@/components/select-field' import { OperationsJobsGrid } from '@/components/operations/operations-jobs-grid' import { OperationsRevisionsGrid } from '@/components/operations/operations-revisions-grid' import { PageHeader } from '@/components/page-header' @@ -245,33 +239,21 @@ function DiffTab({ revisions }: { revisions: import('@/types/api').RevisionRow[]
Ревизия A - + v && setA(v)} + />
Ревизия B - + v && setB(v)} + />
diff --git a/apps/web/src/routes/_auth/tenant-settings.tsx b/apps/web/src/routes/_auth/tenant-settings.tsx index d70367f..c56bafa 100644 --- a/apps/web/src/routes/_auth/tenant-settings.tsx +++ b/apps/web/src/routes/_auth/tenant-settings.tsx @@ -8,15 +8,10 @@ import { Alert, AlertDescription, AlertTitle } from '@evobgp/ui/components/alert import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@evobgp/ui/components/card' import { Input } from '@evobgp/ui/components/input' import { Label } from '@evobgp/ui/components/label' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@evobgp/ui/components/select' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@evobgp/ui/components/tabs' +import { SelectField } from '@/components/select-field' + import { SettingsKvGrid } from '@/components/settings/settings-kv-grid' import { PageHeader } from '@/components/page-header' @@ -244,31 +239,20 @@ function TenantSettingsComponent() { > {() => (
-
- - -

- runtime_logs_auto_enabled -

-
+ + v && + setRuntimeLogsForm((s) => ({ + ...s, + runtime_logs_auto_enabled: v, + })) + } + />
-
- - -

- runtime_logs_auto_mode -

-
+ + v && + setRuntimeLogsForm((s) => ({ + ...s, + runtime_logs_auto_mode: v, + })) + } + />
diff --git a/apps/web/tsconfig.tsbuildinfo b/apps/web/tsconfig.tsbuildinfo index 2da9d9c..dd491e2 100644 --- a/apps/web/tsconfig.tsbuildinfo +++ b/apps/web/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/main.tsx","./src/routetree.gen.ts","./src/components/confirm-dialog.tsx","./src/components/data-grid-shell.tsx","./src/components/empty-state.tsx","./src/components/loading-button.tsx","./src/components/mode-toggle.tsx","./src/components/page-header.tsx","./src/components/page-shell.tsx","./src/components/query-state.tsx","./src/components/section-cards.tsx","./src/components/skeletons.tsx","./src/components/status-badge.tsx","./src/components/theme-provider.tsx","./src/components/truncated-text.tsx","./src/components/access/access-api-keys-card.tsx","./src/components/access/access-api-keys-grid.tsx","./src/components/access/api-key-create-dialog.tsx","./src/components/access/api-key-token-dialog.tsx","./src/components/dashboard/dashboard-network-panel.tsx","./src/components/dashboard/dashboard-quick-actions.tsx","./src/components/dashboard/dashboard-recent-jobs-grid.tsx","./src/components/dashboard/dashboard-recent-revisions-grid.tsx","./src/components/directories/directories-communities-grid.tsx","./src/components/directories/directories-doh-grid.tsx","./src/components/firewall/firewall-clients-grid.tsx","./src/components/firewall/firewall-rules-grid.tsx","./src/components/layout/app-shell.tsx","./src/components/modules/community-select.tsx","./src/components/modules/module-as-entry-dialog.tsx","./src/components/modules/module-cdn-source-dialog.tsx","./src/components/modules/module-domain-entry-dialog.tsx","./src/components/modules/module-entries-grid.tsx","./src/components/modules/module-entries-section.tsx","./src/components/modules/module-ip-range-entry-dialog.tsx","./src/components/modules/module-kpi-cards.tsx","./src/components/modules/modules-list-grid.tsx","./src/components/monitoring/monitoring-ready-grid.tsx","./src/components/network/network-peers-grid.tsx","./src/components/network/network-speakers-grid.tsx","./src/components/operations/operations-jobs-grid.tsx","./src/components/operations/operations-revisions-grid.tsx","./src/components/reui/autocomplete.tsx","./src/components/reui/badge.tsx","./src/components/reui/date-selector.tsx","./src/components/reui/filters.tsx","./src/components/reui/frame.tsx","./src/components/reui/number-field.tsx","./src/components/reui/data-grid/data-grid-column-filter.tsx","./src/components/reui/data-grid/data-grid-column-header.tsx","./src/components/reui/data-grid/data-grid-column-visibility.tsx","./src/components/reui/data-grid/data-grid-pagination.tsx","./src/components/reui/data-grid/data-grid-scroll-area.tsx","./src/components/reui/data-grid/data-grid-table-dnd-rows.tsx","./src/components/reui/data-grid/data-grid-table-dnd.tsx","./src/components/reui/data-grid/data-grid-table-virtual.tsx","./src/components/reui/data-grid/data-grid-table.tsx","./src/components/reui/data-grid/data-grid.tsx","./src/components/schedule/schedule-jobs-grid.tsx","./src/components/schedule/schedule-modules-grid.tsx","./src/components/settings/settings-kv-grid.tsx","./src/lib/api-client.ts","./src/lib/data-grid-defaults.ts","./src/lib/queryclient.ts","./src/lib/router.ts","./src/lib/ui-labels.ts","./src/lib/access/api-key-labels.ts","./src/lib/modules/display.ts","./src/lib/modules/helpers.ts","./src/queries/api-keys.ts","./src/queries/auth.ts","./src/queries/directories.ts","./src/queries/firewall.ts","./src/queries/modules.ts","./src/queries/monitoring.ts","./src/queries/network.ts","./src/queries/operations.ts","./src/queries/overview.ts","./src/queries/settings.ts","./src/routes/__root.tsx","./src/routes/_auth.tsx","./src/routes/index.tsx","./src/routes/_auth/access.tsx","./src/routes/_auth/dashboard.tsx","./src/routes/_auth/directories.tsx","./src/routes/_auth/firewall.tsx","./src/routes/_auth/monitoring.tsx","./src/routes/_auth/network.tsx","./src/routes/_auth/operations.tsx","./src/routes/_auth/schedule.tsx","./src/routes/_auth/settings.tsx","./src/routes/_auth/tenant-settings.tsx","./src/routes/_auth/modules/$moduleid.tsx","./src/routes/_auth/modules/index.tsx","./src/routes/_auth/modules/new.tsx","./src/types/api.ts","./vite.config.ts"],"version":"5.9.3"} \ No newline at end of file +{"root":["./src/main.tsx","./src/routetree.gen.ts","./src/components/confirm-dialog.tsx","./src/components/data-grid-shell.tsx","./src/components/empty-state.tsx","./src/components/loading-button.tsx","./src/components/mode-toggle.tsx","./src/components/page-header.tsx","./src/components/page-shell.tsx","./src/components/query-state.tsx","./src/components/section-cards.tsx","./src/components/select-field.tsx","./src/components/skeletons.tsx","./src/components/status-badge.tsx","./src/components/theme-provider.tsx","./src/components/truncated-text.tsx","./src/components/access/access-api-keys-card.tsx","./src/components/access/access-api-keys-grid.tsx","./src/components/access/api-key-create-dialog.tsx","./src/components/access/api-key-token-dialog.tsx","./src/components/dashboard/dashboard-network-panel.tsx","./src/components/dashboard/dashboard-quick-actions.tsx","./src/components/dashboard/dashboard-recent-jobs-grid.tsx","./src/components/dashboard/dashboard-recent-revisions-grid.tsx","./src/components/directories/directories-communities-grid.tsx","./src/components/directories/directories-doh-grid.tsx","./src/components/examples/c-select-4.tsx","./src/components/firewall/firewall-clients-grid.tsx","./src/components/firewall/firewall-rules-grid.tsx","./src/components/layout/app-shell.tsx","./src/components/modules/community-select.tsx","./src/components/modules/module-as-entry-dialog.tsx","./src/components/modules/module-cdn-source-dialog.tsx","./src/components/modules/module-domain-entry-dialog.tsx","./src/components/modules/module-entries-grid.tsx","./src/components/modules/module-entries-section.tsx","./src/components/modules/module-ip-range-entry-dialog.tsx","./src/components/modules/module-kpi-cards.tsx","./src/components/modules/modules-list-grid.tsx","./src/components/monitoring/monitoring-ready-grid.tsx","./src/components/network/network-peers-grid.tsx","./src/components/network/network-speakers-grid.tsx","./src/components/operations/operations-jobs-grid.tsx","./src/components/operations/operations-revisions-grid.tsx","./src/components/reui/autocomplete.tsx","./src/components/reui/badge.tsx","./src/components/reui/date-selector.tsx","./src/components/reui/filters.tsx","./src/components/reui/frame.tsx","./src/components/reui/number-field.tsx","./src/components/reui/data-grid/data-grid-column-filter.tsx","./src/components/reui/data-grid/data-grid-column-header.tsx","./src/components/reui/data-grid/data-grid-column-visibility.tsx","./src/components/reui/data-grid/data-grid-pagination.tsx","./src/components/reui/data-grid/data-grid-scroll-area.tsx","./src/components/reui/data-grid/data-grid-table-dnd-rows.tsx","./src/components/reui/data-grid/data-grid-table-dnd.tsx","./src/components/reui/data-grid/data-grid-table-virtual.tsx","./src/components/reui/data-grid/data-grid-table.tsx","./src/components/reui/data-grid/data-grid.tsx","./src/components/schedule/schedule-jobs-grid.tsx","./src/components/schedule/schedule-modules-grid.tsx","./src/components/settings/settings-kv-grid.tsx","./src/lib/api-client.ts","./src/lib/data-grid-defaults.ts","./src/lib/queryclient.ts","./src/lib/router.ts","./src/lib/ui-labels.ts","./src/lib/access/api-key-labels.ts","./src/lib/modules/display.ts","./src/lib/modules/helpers.ts","./src/queries/api-keys.ts","./src/queries/auth.ts","./src/queries/directories.ts","./src/queries/firewall.ts","./src/queries/modules.ts","./src/queries/monitoring.ts","./src/queries/network.ts","./src/queries/operations.ts","./src/queries/overview.ts","./src/queries/settings.ts","./src/routes/__root.tsx","./src/routes/_auth.tsx","./src/routes/index.tsx","./src/routes/_auth/access.tsx","./src/routes/_auth/dashboard.tsx","./src/routes/_auth/directories.tsx","./src/routes/_auth/firewall.tsx","./src/routes/_auth/monitoring.tsx","./src/routes/_auth/network.tsx","./src/routes/_auth/operations.tsx","./src/routes/_auth/schedule.tsx","./src/routes/_auth/settings.tsx","./src/routes/_auth/tenant-settings.tsx","./src/routes/_auth/modules/$moduleid.tsx","./src/routes/_auth/modules/index.tsx","./src/routes/_auth/modules/new.tsx","./src/types/api.ts","./vite.config.ts"],"version":"5.9.3"} \ No newline at end of file diff --git a/packages/ui/src/components/select.tsx b/packages/ui/src/components/select.tsx index 2ccc7fb..e2d6500 100644 --- a/packages/ui/src/components/select.tsx +++ b/packages/ui/src/components/select.tsx @@ -1,5 +1,3 @@ -"use client" - import * as React from "react" import { Select as SelectPrimitive } from "@base-ui/react/select" @@ -111,15 +109,11 @@ function SelectLabel({ function SelectItem({ className, children, - label, ...props }: SelectPrimitive.Item.Props) { - const resolvedLabel = label ?? (typeof children === "string" ? children : undefined) - return (