@gntik-ai/templates 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +47 -13
- package/dist/index.js +257 -189
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/index.ts +1 -1
- package/src/keyboard-shortcuts/Page.test.tsx +39 -1
- package/src/keyboard-shortcuts/ShortcutSheet.tsx +3 -2
- package/src/keyboard-shortcuts/data.ts +28 -14
- package/src/resource-detail/CustomTabs.tsx +41 -0
- package/src/resource-detail/Page.default.test.tsx +28 -0
- package/src/resource-detail/Page.labels.test.tsx +67 -0
- package/src/resource-detail/Page.shell-less.test.tsx +36 -0
- package/src/resource-detail/Page.tabs.test.tsx +116 -0
- package/src/resource-detail/Page.tsx +80 -34
- package/src/resource-detail/__snapshots__/Page.default.test.tsx.snap +7 -0
- package/src/resource-detail/examples/Labels.tsx +18 -0
- package/src/resource-detail/examples/Spanish.tsx +11 -0
- package/src/resource-detail/examples/embedded-custom-tabs.tsx +44 -0
- package/src/resource-detail/template.meta.ts +1 -1
- package/src/settings-profile/fixtures/editable.snap +1 -1
- package/src/shared/ConsoleShell.test.tsx +13 -0
- package/src/shared/ConsoleShell.tsx +35 -30
- package/src/workflow-builder/Page.test.tsx +103 -2
- package/src/workflow-builder/Page.tsx +34 -8
- package/src/workflow-builder/examples/SaveGraph.tsx +17 -0
- package/src/workflow-builder/template.meta.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { ChartLocaleProvider, Heatmap, MiniBar, RadarChart, chartFmt } from "@gntik-ai/charts";
|
|
3
|
+
import { ActivityFeed, AppSidebarFooter, AppSidebarHeader, AppSidebarNav, AppTopbar, AuthHeader, BulkActionBar, ChartCard, CodePanel, CommentThread, ConfirmDestructive, CreateApiKeyDialog, DEPLOYMENT_COLUMNS, DEPLOYMENT_DETAILS, DEPLOYMENT_EVENTS, DEPLOYMENT_ROWS, DangerZone, DataTable, DateRangeFilter, DescriptionListCard, ErrorPanel, EvaluationScorecard, Faq, FeatureGrid, FileUploadPanel, FilterBar, FirstRunEmpty, FlowBuilder, ForgotPasswordForm, FormSection, Hero, InlineCallout, InviteMembersDialog, InvoiceTable, KPI_ITEMS, KpiRow, ListSkeleton, LogViewer, MembersTable, MfaChallenge, ModelKeysList, NoResultsEmpty, NotificationMatrix, PROJECT_ACTIVITY, PageHeader, PageToolbar, PaymentMethodCard, PendingInvitations, PlanCard, PricingTable, ProfileHeader, PromptEditor, QuotaMeters, RESOURCE_CARDS, ResetPasswordForm, ResourceCardGrid, SectionHeader, SessionsDevices, SettingsRow, SignInForm, SignUpForm, SsoButtons, StatusTimeline, StickyActionBar, SystemBanner, TokenCostCard, TraceWaterfall, TrendDelta, ValidationSummary, apiKeyExpiries, apiKeyScopes, appSidebarNavGroups, appSidebarUser, appSidebarUser as appSidebarUser$1, appSidebarWorkspaces, appTopbarNotifications, builderEdges, builderNodes, cleanFlowGraph, firstRunSteps, formatSpanDuration, generateDemoSecret, memberRoles, noAccessSample, notificationChannels, notificationDefaults, notificationEvents, sampleDeviceSessions, sampleInvitations, sampleInvoices, sampleMembers, samplePaymentMethod, samplePlan, samplePricingTiers, sampleProfile, sampleQuotas, ssoProviders, ssoProviders as ssoProviders$1 } from "@gntik-ai/blocks";
|
|
4
|
+
import { Alert, AuthLayout, Avatar, AvatarGroup, Badge, Blockquote, Breadcrumbs, Button, CanvasLayout, Card, CardBody, CardDescription, CardHeader, CardTitle, Checkbox, CheckboxGroup, ClickableCard, CodeBlock, ContextMenu, ContextMenuContent, ContextMenuTrigger, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DocsLayout, Drawer, DrawerBody, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle, EmptyState, Field, FieldDescription, FieldError, FieldLabel, Grid, GridItem, HStack, Heading, IconButton, Input, InspectorLayout, InspectorToggle, JsonViewer, KanbanBoard, Kbd, KbdCombo, Link, ListInput, LiveAnnouncer, Logo, MegaMenu, MenuItem, MenuSeparator, Meter, MobileNav, NavList, OtpInput, OverflowList, Page, PasswordInput, PowerSearch, Progress, Section, Select, SelectContent, SelectItem, SelectTrigger, SelectableCard, SelectableCardGroup, Separator, SettingsLayout, SidebarLayout, SimpleSelect, Skeleton, Spinner, SplitLayout, Stack, StackedLayout, StatusDot, StatusLayout, StatusTag, Switch, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsList, TabsPanel, TabsTab, Text, Textarea, ThemeSwitcher, Thumbnail, ThumbnailList, Timer, Timestamp, Toggle, ToggleGroup, TokenInput, TooltipProvider, TransferList, TreeList, VisuallyHidden, WizardLayout, cn, emptyPowerSearchQuery, formatPowerSearch, matchPowerSearch, matchText, megaMenuNavItems, moveKanbanCard, parsePowerSearch, useAnnounce, useHasLiveAnnouncer, useI18n, useInspectorLayout, useOs, useTheme } from "@gntik-ai/ui";
|
|
4
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
6
|
import { Fragment as Fragment$1, createElement, useEffect, useEffectEvent, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
6
7
|
import { ChatAnnouncer, ChatComposer, ChatLayout, ChatMessage, CitationList, Markdown, SuggestionChips, ToolCallCard } from "@gntik-ai/chat";
|
|
7
8
|
import { Archive, ArrowLeft, ArrowRight, BarChart3, Bell, BellOff, BellRing, BookOpen, Braces, Building2, CalendarClock, Check, CheckCheck, CircleCheck, Clock, Code2, Columns3, Copy, Cpu, CreditCard, Database, Download, ExternalLink, FileCode, FileDiff, FileJson, FileQuestion, FileSearch, FileText, Folder, FolderKanban, FolderOpen, GitBranch, Globe, GripVertical, Hand, HardDrive, Home, KeyRound, Keyboard, LayoutGrid, LayoutTemplate, LifeBuoy, ListOrdered, ListTodo, Lock, Mail, MailOpen, MapPin, MessageSquare, MessagesSquare, Minus, Palette, Phone, Play, PlayCircle, Plug, Plus, RefreshCw, Rocket, RotateCcw, RotateCw, Rss, Save, Search, SearchX, Send, Server, ServerCrash, Shield, ShieldCheck, Square, SquarePen, Table2, ThumbsDown, ThumbsUp, Trash2, Upload, User, UserPlus, Users, Wrench, X } from "@gntik-ai/icons";
|
|
8
|
-
import { Heatmap, MiniBar, RadarChart, chartFmt } from "@gntik-ai/charts";
|
|
9
9
|
import { DiffEditor } from "@gntik-ai/editor";
|
|
10
10
|
import { flushSync } from "react-dom";
|
|
11
11
|
//#region src/shared/ConsoleShell.tsx
|
|
@@ -16,38 +16,42 @@ import { flushSync } from "react-dom";
|
|
|
16
16
|
* link and user-menu items.
|
|
17
17
|
*/
|
|
18
18
|
function ConsoleShell({ children, nav, currentHref, breadcrumbs, workspaces, currentWorkspaceId, onWorkspaceChange, onCreateWorkspace, user, usage, helpHref, helpLabel, userMenuItems, onSignOut, topbar, storageKey, sidebarLabel, collapseMode }) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
collapsed
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
19
|
+
const { locale } = useI18n();
|
|
20
|
+
return /* @__PURE__ */ jsx(ChartLocaleProvider, {
|
|
21
|
+
locale,
|
|
22
|
+
children: /* @__PURE__ */ jsx(SidebarLayout, {
|
|
23
|
+
fullScreen: true,
|
|
24
|
+
storageKey,
|
|
25
|
+
sidebarLabel,
|
|
26
|
+
collapseMode,
|
|
27
|
+
sidebarHeader: ({ collapsed }) => /* @__PURE__ */ jsx(AppSidebarHeader, {
|
|
28
|
+
collapsed,
|
|
29
|
+
workspaces,
|
|
30
|
+
currentWorkspaceId,
|
|
31
|
+
onWorkspaceChange,
|
|
32
|
+
onCreateWorkspace
|
|
33
|
+
}),
|
|
34
|
+
sidebar: ({ collapsed }) => /* @__PURE__ */ jsx(AppSidebarNav, {
|
|
35
|
+
groups: nav,
|
|
36
|
+
currentHref,
|
|
37
|
+
collapsed
|
|
38
|
+
}),
|
|
39
|
+
sidebarFooter: ({ collapsed }) => /* @__PURE__ */ jsx(AppSidebarFooter, {
|
|
40
|
+
collapsed,
|
|
41
|
+
user,
|
|
42
|
+
usage,
|
|
43
|
+
helpHref,
|
|
44
|
+
helpLabel,
|
|
45
|
+
userMenuItems,
|
|
46
|
+
onSignOut
|
|
47
|
+
}),
|
|
48
|
+
topbar: /* @__PURE__ */ jsx(AppTopbar, {
|
|
49
|
+
breadcrumbs,
|
|
50
|
+
user,
|
|
51
|
+
...topbar
|
|
52
|
+
}),
|
|
53
|
+
children
|
|
54
|
+
})
|
|
51
55
|
});
|
|
52
56
|
}
|
|
53
57
|
//#endregion
|
|
@@ -1938,15 +1942,24 @@ const flowBuilderBreadcrumbs = [{
|
|
|
1938
1942
|
* '@gntik-ai/flow/styles.css' once for the React Flow canvas.
|
|
1939
1943
|
*/
|
|
1940
1944
|
function FlowBuilderPage(props) {
|
|
1941
|
-
const { title = flowBuilderContent.title, status = flowBuilderContent.status, nodes, edges, palette, onRun, consoleEntries, defaultConsoleEntries, onConsoleChange, onConsoleClear, onSave, onPublish, nodeTypes, onConnectEdge, onConnect, isValidConnection, onConnectionRejected, validationIssues, mode, nodeStatus, onNodeSelect, codePanel, breadcrumbs = flowBuilderBreadcrumbs, height = 640, fullScreen = true } = props;
|
|
1945
|
+
const { title = flowBuilderContent.title, status = flowBuilderContent.status, nodes = builderNodes, edges = builderEdges, palette, onRun, consoleEntries, defaultConsoleEntries, onConsoleChange, onConsoleClear, onSave, onPublish, nodeTypes, onConnectEdge, onConnect, isValidConnection, onConnectionRejected, validationIssues, mode, nodeStatus, onNodeSelect, graph, onGraphChange, codePanel, breadcrumbs = flowBuilderBreadcrumbs, height = 640, fullScreen = true } = props;
|
|
1942
1946
|
const [saving, setSaving] = useState(false);
|
|
1943
|
-
const [
|
|
1947
|
+
const [initialGraph] = useState(() => ({
|
|
1948
|
+
nodes,
|
|
1949
|
+
edges
|
|
1950
|
+
}));
|
|
1951
|
+
const [latestGraph, setLatestGraph] = useState();
|
|
1952
|
+
const [saveState, setSaveState] = useState("initial");
|
|
1953
|
+
const revision = useRef(0);
|
|
1954
|
+
const { t } = useI18n();
|
|
1955
|
+
const savedNote = saveState === "initial" ? flowBuilderContent.lastSaved : t(saveState === "unsaved" ? "actionBar.unsaved" : "actionBar.saved");
|
|
1944
1956
|
const save = async () => {
|
|
1945
1957
|
setSaving(true);
|
|
1958
|
+
const savedRevision = revision.current;
|
|
1946
1959
|
try {
|
|
1947
|
-
await onSave?.();
|
|
1948
|
-
|
|
1949
|
-
} finally {
|
|
1960
|
+
await onSave?.(cleanFlowGraph(graph ?? latestGraph ?? initialGraph));
|
|
1961
|
+
if (revision.current === savedRevision) setSaveState("saved");
|
|
1962
|
+
} catch {} finally {
|
|
1950
1963
|
setSaving(false);
|
|
1951
1964
|
}
|
|
1952
1965
|
};
|
|
@@ -1994,6 +2007,13 @@ function FlowBuilderPage(props) {
|
|
|
1994
2007
|
title,
|
|
1995
2008
|
nodes,
|
|
1996
2009
|
edges,
|
|
2010
|
+
graph,
|
|
2011
|
+
onGraphChange: (next, change) => {
|
|
2012
|
+
revision.current += 1;
|
|
2013
|
+
setLatestGraph(next);
|
|
2014
|
+
setSaveState("unsaved");
|
|
2015
|
+
onGraphChange?.(next, change);
|
|
2016
|
+
},
|
|
1997
2017
|
palette,
|
|
1998
2018
|
onRun,
|
|
1999
2019
|
consoleEntries,
|
|
@@ -2025,7 +2045,7 @@ const meta$60 = {
|
|
|
2025
2045
|
family: "Builders",
|
|
2026
2046
|
priority: "P3",
|
|
2027
2047
|
status: "experimental",
|
|
2028
|
-
description: "Full-screen workflow editor with optional nodeTypes, onConnectEdge, onConnect, isValidConnection, onConnectionRejected, validationIssues, mode=\"run\", nodeStatus and onNodeSelect passed to FlowBuilder; codePanel passes readOnly, markers, onValidityChange, onMonacoReady and loader to an optional CodePanel (branch, parallel, sequence and worker-backed YAML examples). The app must import '@gntik-ai/flow/styles.css' once for the canvas styles. Optional nodeTypes, onConnectEdge, onConnect, isValidConnection, onConnectionRejected, validationIssues, mode, nodeStatus and onNodeSelect pass to FlowBuilder unchanged (see its branch, parallel and sequence examples). mode=\"run\" hides Save, Publish and the saved notice, and preserves focus and node selection. Optional codePanel renders a companion CodePanel and passes all its extensions: readOnly, markers, onValidityChange, onMonacoReady and loader; run mode forces its readOnly to true. For example, WorkflowBuilderPage mode=\"run\" nodeStatus={{step:\"running\"}} onNodeSelect={openDetails}; codePanel={{files,problems:[],loader:yamlLoader,markers}} uses consumer-owned same-origin YAML workers and inline schemas.",
|
|
2048
|
+
description: "onSave(graph) receives the graph on screen (controlled graph, latest reported edit, or initial starter graph), without selected, dragging or measured node fields. Zero-argument handlers remain valid. Optional graph and onGraphChange pass through to FlowBuilder. Committed edits show actionBar.unsaved, a resolved save shows actionBar.saved, and a rejected save retains unsaved status and releases loading. Edits during a pending save remain unsaved. examples/SaveGraph.tsx shows a controlled graph and onSave={(graph) => localStorage.setItem(\"workflow-builder-example\", JSON.stringify(graph))}; hosts own persistence. Full-screen workflow editor with optional nodeTypes, onConnectEdge, onConnect, isValidConnection, onConnectionRejected, validationIssues, mode=\"run\", nodeStatus and onNodeSelect passed to FlowBuilder; codePanel passes readOnly, markers, onValidityChange, onMonacoReady and loader to an optional CodePanel (branch, parallel, sequence and worker-backed YAML examples). The app must import '@gntik-ai/flow/styles.css' once for the canvas styles. Optional nodeTypes, onConnectEdge, onConnect, isValidConnection, onConnectionRejected, validationIssues, mode, nodeStatus and onNodeSelect pass to FlowBuilder unchanged (see its branch, parallel and sequence examples). mode=\"run\" hides Save, Publish and the saved notice, and preserves focus and node selection. Optional codePanel renders a companion CodePanel and passes all its extensions: readOnly, markers, onValidityChange, onMonacoReady and loader; run mode forces its readOnly to true. For example, WorkflowBuilderPage mode=\"run\" nodeStatus={{step:\"running\"}} onNodeSelect={openDetails}; codePanel={{files,problems:[],loader:yamlLoader,markers}} uses consumer-owned same-origin YAML workers and inline schemas.",
|
|
2029
2049
|
layout: "CanvasLayout",
|
|
2030
2050
|
blocks: ["flow-builder", "code-panel"]
|
|
2031
2051
|
};
|
|
@@ -2983,6 +3003,33 @@ const meta$29 = {
|
|
|
2983
3003
|
blocks: ["reset-password-form"]
|
|
2984
3004
|
};
|
|
2985
3005
|
//#endregion
|
|
3006
|
+
//#region src/resource-detail/CustomTabs.tsx
|
|
3007
|
+
function CustomTabs({ tabs, defaultTab, onTabChange, label }) {
|
|
3008
|
+
const [selected, setSelected] = useState(defaultTab);
|
|
3009
|
+
const value = tabs.find((tab) => tab.value === selected)?.value ?? tabs[0]?.value ?? null;
|
|
3010
|
+
if (tabs.length === 0) return null;
|
|
3011
|
+
return /* @__PURE__ */ jsxs(Tabs, {
|
|
3012
|
+
value,
|
|
3013
|
+
onValueChange: (next) => {
|
|
3014
|
+
const tab = tabs.find((tab) => tab.value === next);
|
|
3015
|
+
if (tab) {
|
|
3016
|
+
setSelected(tab.value);
|
|
3017
|
+
onTabChange?.(tab.value);
|
|
3018
|
+
}
|
|
3019
|
+
},
|
|
3020
|
+
children: [/* @__PURE__ */ jsx(TabsList, {
|
|
3021
|
+
"aria-label": label,
|
|
3022
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsx(TabsTab, {
|
|
3023
|
+
value: tab.value,
|
|
3024
|
+
children: tab.label
|
|
3025
|
+
}, tab.value))
|
|
3026
|
+
}), tabs.map((tab) => /* @__PURE__ */ jsx(TabsPanel, {
|
|
3027
|
+
value: tab.value,
|
|
3028
|
+
children: tab.content
|
|
3029
|
+
}, tab.value))]
|
|
3030
|
+
});
|
|
3031
|
+
}
|
|
3032
|
+
//#endregion
|
|
2986
3033
|
//#region src/resource-detail/data.ts
|
|
2987
3034
|
const detailResource = {
|
|
2988
3035
|
name: "orders-api",
|
|
@@ -3034,23 +3081,23 @@ const detailDangerActions = [{
|
|
|
3034
3081
|
//#endregion
|
|
3035
3082
|
//#region src/resource-detail/Page.tsx
|
|
3036
3083
|
const TABS = [
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
},
|
|
3041
|
-
{
|
|
3042
|
-
value: "activity",
|
|
3043
|
-
label: "Activity"
|
|
3044
|
-
},
|
|
3045
|
-
{
|
|
3046
|
-
value: "settings",
|
|
3047
|
-
label: "Settings"
|
|
3048
|
-
}
|
|
3084
|
+
"overview",
|
|
3085
|
+
"activity",
|
|
3086
|
+
"settings"
|
|
3049
3087
|
];
|
|
3050
|
-
/**
|
|
3088
|
+
/**
|
|
3089
|
+
* Resource detail: editable tabs by default, or explicit-only Overview when readOnly is true.
|
|
3090
|
+
* Pass tabs to replace the built-in sections with caller labels, values and content; readOnly
|
|
3091
|
+
* does not filter custom tabs. An omitted or unknown defaultTab selects the first custom tab.
|
|
3092
|
+
* shell={null} renders only Page and its header. The host owns the main landmark and must
|
|
3093
|
+
* provide ChartLocaleProvider when its custom chart content needs a locale. Breadcrumbs
|
|
3094
|
+
* render in the header in this mode: pass a trail or [] to avoid the editable sample trail.
|
|
3095
|
+
* Omitted or object shells and omitted tabs preserve the existing default output.
|
|
3096
|
+
*/
|
|
3051
3097
|
function ResourceDetailPage(props) {
|
|
3098
|
+
const { t } = useI18n();
|
|
3052
3099
|
const readOnly = props.readOnly ?? false;
|
|
3053
|
-
const { name = readOnly ? "" : detailResource.name, description = readOnly ? "" : detailResource.description, status = readOnly ? "" : detailResource.status, breadcrumbs = readOnly ? [] : detailBreadcrumbs, meta: metaProp, actions: actionsProp, details: detailsProp, overviewTitle = "Configuration", overviewDescription = readOnly ? "" : "Settings of this resource.", historyTitle = "Status history", events = readOnly ? [] : detailEvents, activity = readOnly ? [] : detailActivity, dangerActions = readOnly ? [] : detailDangerActions, defaultTab = "overview",
|
|
3100
|
+
const { name = readOnly ? "" : detailResource.name, description = readOnly ? "" : detailResource.description, status = readOnly ? "" : detailResource.status, breadcrumbs = readOnly ? [] : detailBreadcrumbs, meta: metaProp, actions: actionsProp, details: detailsProp, overviewTitle = "Configuration", overviewDescription = readOnly ? "" : "Settings of this resource.", historyTitle = "Status history", events = readOnly ? [] : detailEvents, activity = readOnly ? [] : detailActivity, dangerActions = readOnly ? [] : detailDangerActions, defaultTab = "overview", onEditDetails, onSaveSettings, onDangerAction, shell, labels } = props;
|
|
3054
3101
|
const meta = metaProp ?? (readOnly ? [] : detailMeta);
|
|
3055
3102
|
const actions = actionsProp ?? (readOnly ? [] : [{
|
|
3056
3103
|
label: "View logs",
|
|
@@ -3073,140 +3120,150 @@ function ResourceDetailPage(props) {
|
|
|
3073
3120
|
description
|
|
3074
3121
|
});
|
|
3075
3122
|
const dirty = settings.name !== saved.name || settings.description !== saved.description;
|
|
3076
|
-
const tabs = readOnly ? TABS.filter((
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
/* @__PURE__ */ jsx(
|
|
3108
|
-
value:
|
|
3109
|
-
children:
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
events: historyEvents,
|
|
3131
|
-
maxVisible: readOnly ? void 0 : 4
|
|
3132
|
-
})
|
|
3133
|
-
})]
|
|
3134
|
-
})
|
|
3135
|
-
}),
|
|
3136
|
-
!readOnly && /* @__PURE__ */ jsx(TabsPanel, {
|
|
3137
|
-
value: "activity",
|
|
3138
|
-
children: /* @__PURE__ */ jsx(Section, {
|
|
3123
|
+
const tabs = (readOnly ? TABS.filter((value) => value === "overview") : TABS).map((value) => ({
|
|
3124
|
+
value,
|
|
3125
|
+
label: labels?.[value] ?? t(`resourceDetail.${value}`)
|
|
3126
|
+
}));
|
|
3127
|
+
const content = /* @__PURE__ */ jsx(Page, {
|
|
3128
|
+
width: "wide",
|
|
3129
|
+
header: /* @__PURE__ */ jsx(PageHeader, {
|
|
3130
|
+
as: shell === null ? "div" : void 0,
|
|
3131
|
+
breadcrumbs: shell === null ? breadcrumbs : null,
|
|
3132
|
+
title: name,
|
|
3133
|
+
description,
|
|
3134
|
+
status,
|
|
3135
|
+
meta,
|
|
3136
|
+
actions,
|
|
3137
|
+
tabs: null
|
|
3138
|
+
}),
|
|
3139
|
+
children: props.tabs !== void 0 ? /* @__PURE__ */ jsx(CustomTabs, {
|
|
3140
|
+
tabs: props.tabs,
|
|
3141
|
+
defaultTab: props.defaultTab,
|
|
3142
|
+
onTabChange: props.onTabChange,
|
|
3143
|
+
label: labels?.sections ?? t("resourceDetail.sections")
|
|
3144
|
+
}) : /* @__PURE__ */ jsxs(Tabs, {
|
|
3145
|
+
value: readOnly ? "overview" : tab,
|
|
3146
|
+
onValueChange: (v) => {
|
|
3147
|
+
const next = tabs.find((t) => t.value === v)?.value ?? "overview";
|
|
3148
|
+
setTab(next);
|
|
3149
|
+
if (props.tabs === void 0) props.onTabChange?.(next);
|
|
3150
|
+
},
|
|
3151
|
+
children: [
|
|
3152
|
+
/* @__PURE__ */ jsx(TabsList, {
|
|
3153
|
+
"aria-label": labels?.sections ?? t("resourceDetail.sections"),
|
|
3154
|
+
children: tabs.map((t) => /* @__PURE__ */ jsx(TabsTab, {
|
|
3155
|
+
value: t.value,
|
|
3156
|
+
children: t.label
|
|
3157
|
+
}, t.value))
|
|
3158
|
+
}),
|
|
3159
|
+
/* @__PURE__ */ jsx(TabsPanel, {
|
|
3160
|
+
value: "overview",
|
|
3161
|
+
children: /* @__PURE__ */ jsxs(Grid, {
|
|
3162
|
+
cols: historyEvents === void 0 ? 1 : {
|
|
3163
|
+
base: 1,
|
|
3164
|
+
lg: 5
|
|
3165
|
+
},
|
|
3166
|
+
gap: 6,
|
|
3167
|
+
align: "start",
|
|
3168
|
+
children: [/* @__PURE__ */ jsx(DescriptionListCard, {
|
|
3169
|
+
className: historyEvents === void 0 ? void 0 : "lg:col-span-3",
|
|
3170
|
+
titleAs: "h2",
|
|
3171
|
+
title: overviewTitle,
|
|
3172
|
+
description: overviewDescription,
|
|
3173
|
+
items: details,
|
|
3174
|
+
onEdit: onEditDetails
|
|
3175
|
+
}), historyEvents !== void 0 && /* @__PURE__ */ jsx(Section, {
|
|
3176
|
+
role: readOnly ? "group" : void 0,
|
|
3139
3177
|
variant: "card",
|
|
3140
3178
|
padding: "md",
|
|
3141
|
-
title:
|
|
3142
|
-
|
|
3143
|
-
children: /* @__PURE__ */ jsx(
|
|
3144
|
-
|
|
3145
|
-
|
|
3179
|
+
title: historyTitle,
|
|
3180
|
+
className: "lg:col-span-2",
|
|
3181
|
+
children: /* @__PURE__ */ jsx(StatusTimeline, {
|
|
3182
|
+
events: historyEvents,
|
|
3183
|
+
maxVisible: readOnly ? void 0 : 4
|
|
3146
3184
|
})
|
|
3185
|
+
})]
|
|
3186
|
+
})
|
|
3187
|
+
}),
|
|
3188
|
+
!readOnly && /* @__PURE__ */ jsx(TabsPanel, {
|
|
3189
|
+
value: "activity",
|
|
3190
|
+
children: /* @__PURE__ */ jsx(Section, {
|
|
3191
|
+
variant: "card",
|
|
3192
|
+
padding: "md",
|
|
3193
|
+
title: "Activity",
|
|
3194
|
+
description: "Changes made to this resource by people and automations.",
|
|
3195
|
+
children: /* @__PURE__ */ jsx(ActivityFeed, {
|
|
3196
|
+
items: activity,
|
|
3197
|
+
label: "Activity, newest first"
|
|
3147
3198
|
})
|
|
3148
|
-
})
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
...s,
|
|
3185
|
-
name: v
|
|
3186
|
-
}))
|
|
3187
|
-
}),
|
|
3188
|
-
/* @__PURE__ */ jsx(FieldDescription, { children: "Lowercase letters, numbers and dashes." })
|
|
3189
|
-
] }), /* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsx(FieldLabel, { children: "Description" }), /* @__PURE__ */ jsx(Textarea, {
|
|
3190
|
-
rows: 3,
|
|
3191
|
-
value: settings.description,
|
|
3199
|
+
})
|
|
3200
|
+
}),
|
|
3201
|
+
!readOnly && /* @__PURE__ */ jsx(TabsPanel, {
|
|
3202
|
+
value: "settings",
|
|
3203
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
3204
|
+
gap: 8,
|
|
3205
|
+
children: [/* @__PURE__ */ jsx("form", {
|
|
3206
|
+
noValidate: true,
|
|
3207
|
+
onSubmit: (e) => {
|
|
3208
|
+
e.preventDefault();
|
|
3209
|
+
setSaved(settings);
|
|
3210
|
+
onSaveSettings?.(settings);
|
|
3211
|
+
},
|
|
3212
|
+
children: /* @__PURE__ */ jsx(FormSection, {
|
|
3213
|
+
title: "General",
|
|
3214
|
+
description: "Name and description shown across the console.",
|
|
3215
|
+
actions: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Button, {
|
|
3216
|
+
variant: "ghost",
|
|
3217
|
+
disabled: !dirty,
|
|
3218
|
+
onClick: () => setSettings(saved),
|
|
3219
|
+
children: "Discard"
|
|
3220
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
3221
|
+
type: "submit",
|
|
3222
|
+
disabled: !dirty,
|
|
3223
|
+
children: "Save changes"
|
|
3224
|
+
})] }),
|
|
3225
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
3226
|
+
gap: 4,
|
|
3227
|
+
children: [/* @__PURE__ */ jsxs(Field, { children: [
|
|
3228
|
+
/* @__PURE__ */ jsx(FieldLabel, {
|
|
3229
|
+
required: true,
|
|
3230
|
+
children: "Name"
|
|
3231
|
+
}),
|
|
3232
|
+
/* @__PURE__ */ jsx(Input, {
|
|
3233
|
+
required: true,
|
|
3234
|
+
value: settings.name,
|
|
3192
3235
|
onValueChange: (v) => setSettings((s) => ({
|
|
3193
3236
|
...s,
|
|
3194
|
-
|
|
3237
|
+
name: v
|
|
3195
3238
|
}))
|
|
3196
|
-
})
|
|
3197
|
-
|
|
3239
|
+
}),
|
|
3240
|
+
/* @__PURE__ */ jsx(FieldDescription, { children: "Lowercase letters, numbers and dashes." })
|
|
3241
|
+
] }), /* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsx(FieldLabel, { children: "Description" }), /* @__PURE__ */ jsx(Textarea, {
|
|
3242
|
+
rows: 3,
|
|
3243
|
+
value: settings.description,
|
|
3244
|
+
onValueChange: (v) => setSettings((s) => ({
|
|
3245
|
+
...s,
|
|
3246
|
+
description: v
|
|
3247
|
+
}))
|
|
3248
|
+
})] })]
|
|
3198
3249
|
})
|
|
3199
|
-
})
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
})
|
|
3250
|
+
})
|
|
3251
|
+
}), /* @__PURE__ */ jsx(DangerZone, {
|
|
3252
|
+
description: "These actions affect everyone who uses this resource.",
|
|
3253
|
+
actions: dangerActions,
|
|
3254
|
+
onConfirm: onDangerAction
|
|
3255
|
+
})]
|
|
3205
3256
|
})
|
|
3206
|
-
|
|
3207
|
-
|
|
3257
|
+
})
|
|
3258
|
+
]
|
|
3208
3259
|
})
|
|
3209
3260
|
});
|
|
3261
|
+
return shell === null ? content : /* @__PURE__ */ jsx(ConsoleShell, {
|
|
3262
|
+
currentHref: "/deployments",
|
|
3263
|
+
breadcrumbs,
|
|
3264
|
+
...shell,
|
|
3265
|
+
children: content
|
|
3266
|
+
});
|
|
3210
3267
|
}
|
|
3211
3268
|
//#endregion
|
|
3212
3269
|
//#region src/resource-detail/template.meta.ts
|
|
@@ -3215,7 +3272,7 @@ const meta$30 = {
|
|
|
3215
3272
|
family: "Resources",
|
|
3216
3273
|
priority: "P1",
|
|
3217
3274
|
status: "beta",
|
|
3218
|
-
description: "Resource detail with editable Overview, Activity and Settings tabs by default; optional readOnly (boolean, default false) uses only explicit header and detail props and one Overview tab, with optional history (readonly StatusEvent[], default undefined): omitted hides the history card, [] shows the named empty state, and events render exactly as supplied without invented actors. Read-only ignores activity, events, dangerActions, defaultTab, onSaveSettings and onDangerAction; explicit actions and onEditDetails are honored. The Resource sections tablist retains Tab, arrow, Home/End and Enter/Space keyboard navigation; history is a named group containing the Status history list or empty-state region. Uses token styling in dark (default), light and high_contrast. Examples: runtime-with-transition maps state and lastTransitionAt to one actor-free event, runtime-without-transition maps null to [], and realtime-configuration and postgres-table-detail omit history. ConsoleShell retains sample frame defaults
|
|
3275
|
+
description: "Resource detail with editable Overview, Activity and Settings tabs by default; optional readOnly (boolean, default false) uses only explicit header and detail props and one Overview tab, with optional history (readonly StatusEvent[], default undefined): omitted hides the history card, [] shows the named empty state, and events render exactly as supplied without invented actors. Read-only ignores activity, events, dangerActions, defaultTab, onSaveSettings and onDangerAction; explicit actions and onEditDetails are honored. The Resource sections tablist retains Tab, arrow, Home/End and Enter/Space keyboard navigation; history is a named group containing the Status history list or empty-state region. Uses token styling in dark (default), light and high_contrast. Examples: runtime-with-transition maps state and lastTransitionAt to one actor-free event, runtime-without-transition maps null to [], and realtime-configuration and postgres-table-detail omit history. Optional labels?: Partial<ResourceDetailLabels> overrides overview, activity, settings and sections (all strings). Unset keys use I18nProvider (en/es); no provider keeps English. Only the tabs and tablist are localized by this template; fixtures and other section text are unchanged. readOnly keeps only the localized overview tab. See the Catalog labels live preview. ConsoleShell retains sample frame defaults when shell is omitted or an object. shell={null} renders only Page and PageHeader, with breadcrumbs in the header; pass breadcrumbs or [] to avoid the editable sample trail. The host owns main and provides ChartLocaleProvider for custom chart locales. Optional tabs?: { value: string; label: string; content: ReactNode }[] replaces the built-in tabs in caller order, even with readOnly; [] hides the tab set. With custom tabs, defaultTab and onTabChange use string values; an omitted or unknown defaultTab selects the first tab. Without tabs they retain ResourceDetailTab values. Custom tabs use the same Base UI keyboard navigation and panel mounting. See the embedded-custom-tabs live preview for shell-less composition inside a host main.",
|
|
3219
3276
|
layout: "SidebarLayout + Page",
|
|
3220
3277
|
blocks: [
|
|
3221
3278
|
"app-sidebar",
|
|
@@ -13264,7 +13321,7 @@ const shortcutGroups = [
|
|
|
13264
13321
|
{
|
|
13265
13322
|
id: "palette",
|
|
13266
13323
|
description: "Open the command palette",
|
|
13267
|
-
keys: ["
|
|
13324
|
+
keys: ["mod", "K"]
|
|
13268
13325
|
},
|
|
13269
13326
|
{
|
|
13270
13327
|
id: "help",
|
|
@@ -13274,13 +13331,13 @@ const shortcutGroups = [
|
|
|
13274
13331
|
{
|
|
13275
13332
|
id: "sidebar",
|
|
13276
13333
|
description: "Collapse or expand the sidebar",
|
|
13277
|
-
keys: ["
|
|
13334
|
+
keys: ["mod", "B"]
|
|
13278
13335
|
},
|
|
13279
13336
|
{
|
|
13280
13337
|
id: "theme",
|
|
13281
13338
|
description: "Switch theme",
|
|
13282
13339
|
keys: [
|
|
13283
|
-
"
|
|
13340
|
+
"mod",
|
|
13284
13341
|
"⇧",
|
|
13285
13342
|
"L"
|
|
13286
13343
|
]
|
|
@@ -13355,12 +13412,12 @@ const shortcutGroups = [
|
|
|
13355
13412
|
{
|
|
13356
13413
|
id: "save",
|
|
13357
13414
|
description: "Save changes",
|
|
13358
|
-
keys: ["
|
|
13415
|
+
keys: ["mod", "S"]
|
|
13359
13416
|
},
|
|
13360
13417
|
{
|
|
13361
13418
|
id: "submit",
|
|
13362
13419
|
description: "Submit a form or comment",
|
|
13363
|
-
keys: ["
|
|
13420
|
+
keys: ["mod", "↵"]
|
|
13364
13421
|
},
|
|
13365
13422
|
{
|
|
13366
13423
|
id: "cancel",
|
|
@@ -13370,18 +13427,28 @@ const shortcutGroups = [
|
|
|
13370
13427
|
{
|
|
13371
13428
|
id: "undo",
|
|
13372
13429
|
description: "Undo",
|
|
13373
|
-
keys: ["
|
|
13430
|
+
keys: ["mod", "Z"]
|
|
13374
13431
|
}
|
|
13375
13432
|
]
|
|
13376
13433
|
}
|
|
13377
13434
|
];
|
|
13378
|
-
/** Groups
|
|
13379
|
-
function filterShortcuts(groups, query, locale) {
|
|
13435
|
+
/** Groups matching descriptions, titles or keys; mod accepts both Command and Ctrl spellings. */
|
|
13436
|
+
function filterShortcuts(groups, query, locale, os = "undetermined") {
|
|
13380
13437
|
const q = query.trim().toLowerCase();
|
|
13381
13438
|
if (!q) return [...groups];
|
|
13439
|
+
const modifier = os === "macos" || os === "ios" ? "⌘" : "Ctrl";
|
|
13440
|
+
const alias = modifier === "⌘" ? "Ctrl" : "⌘";
|
|
13441
|
+
const matchesKeys = (shortcut) => {
|
|
13442
|
+
const keys = [...shortcut.keys, ...shortcut.then ?? []];
|
|
13443
|
+
return [
|
|
13444
|
+
"mod",
|
|
13445
|
+
modifier,
|
|
13446
|
+
alias
|
|
13447
|
+
].some((mod) => keys.map((key) => key === "mod" ? mod : key).join(" ").toLowerCase() === q);
|
|
13448
|
+
};
|
|
13382
13449
|
return groups.map((g) => ({
|
|
13383
13450
|
...g,
|
|
13384
|
-
shortcuts: g.shortcuts.filter((s) => matchText(s.description, query, { locale }) || matchText(g.title, query, { locale }) ||
|
|
13451
|
+
shortcuts: g.shortcuts.filter((s) => matchText(s.description, query, { locale }) || matchText(g.title, query, { locale }) || matchesKeys(s))
|
|
13385
13452
|
})).filter((g) => g.shortcuts.length > 0);
|
|
13386
13453
|
}
|
|
13387
13454
|
//#endregion
|
|
@@ -13389,9 +13456,10 @@ function filterShortcuts(groups, query, locale) {
|
|
|
13389
13456
|
/** Searchable shortcut sheet shared by the page and the dialog. */
|
|
13390
13457
|
function ShortcutSheet({ groups, headingLevel = 2, columns = 2, autoFocus }) {
|
|
13391
13458
|
const { locale } = useI18n();
|
|
13459
|
+
const os = useOs();
|
|
13392
13460
|
const [query, setQuery] = useState("");
|
|
13393
13461
|
const countId = useId();
|
|
13394
|
-
const visible = filterShortcuts(groups, query, locale);
|
|
13462
|
+
const visible = filterShortcuts(groups, query, locale, os);
|
|
13395
13463
|
const total = visible.reduce((n, g) => n + g.shortcuts.length, 0);
|
|
13396
13464
|
return /* @__PURE__ */ jsxs(Stack, {
|
|
13397
13465
|
gap: 5,
|