@flanksource/clicky-ui 0.2.7 → 0.2.9

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.
Files changed (145) hide show
  1. package/dist/components/Combobox.cjs +89 -49
  2. package/dist/components/Combobox.cjs.map +1 -1
  3. package/dist/components/Combobox.d.ts +3 -0
  4. package/dist/components/Combobox.d.ts.map +1 -1
  5. package/dist/components/Combobox.js +91 -51
  6. package/dist/components/Combobox.js.map +1 -1
  7. package/dist/components/FilterBar.cjs +42 -44
  8. package/dist/components/FilterBar.cjs.map +1 -1
  9. package/dist/components/FilterBar.d.ts +19 -0
  10. package/dist/components/FilterBar.d.ts.map +1 -1
  11. package/dist/components/FilterBar.js +43 -45
  12. package/dist/components/FilterBar.js.map +1 -1
  13. package/dist/components/JsonSchemaForm.cjs +35 -0
  14. package/dist/components/JsonSchemaForm.cjs.map +1 -0
  15. package/dist/components/JsonSchemaForm.d.ts +3 -0
  16. package/dist/components/JsonSchemaForm.d.ts.map +1 -0
  17. package/dist/components/JsonSchemaForm.js +35 -0
  18. package/dist/components/JsonSchemaForm.js.map +1 -0
  19. package/dist/components/json-schema-form-array.cjs +169 -0
  20. package/dist/components/json-schema-form-array.cjs.map +1 -0
  21. package/dist/components/json-schema-form-array.d.ts +8 -0
  22. package/dist/components/json-schema-form-array.d.ts.map +1 -0
  23. package/dist/components/json-schema-form-array.js +169 -0
  24. package/dist/components/json-schema-form-array.js.map +1 -0
  25. package/dist/components/json-schema-form-fields.cjs +365 -0
  26. package/dist/components/json-schema-form-fields.cjs.map +1 -0
  27. package/dist/components/json-schema-form-fields.d.ts +19 -0
  28. package/dist/components/json-schema-form-fields.d.ts.map +1 -0
  29. package/dist/components/json-schema-form-fields.js +365 -0
  30. package/dist/components/json-schema-form-fields.js.map +1 -0
  31. package/dist/components/json-schema-form-render.cjs +154 -0
  32. package/dist/components/json-schema-form-render.cjs.map +1 -0
  33. package/dist/components/json-schema-form-render.d.ts +40 -0
  34. package/dist/components/json-schema-form-render.d.ts.map +1 -0
  35. package/dist/components/json-schema-form-render.js +154 -0
  36. package/dist/components/json-schema-form-render.js.map +1 -0
  37. package/dist/components/json-schema-form-resolve.cjs +121 -0
  38. package/dist/components/json-schema-form-resolve.cjs.map +1 -0
  39. package/dist/components/json-schema-form-resolve.d.ts +19 -0
  40. package/dist/components/json-schema-form-resolve.d.ts.map +1 -0
  41. package/dist/components/json-schema-form-resolve.js +121 -0
  42. package/dist/components/json-schema-form-resolve.js.map +1 -0
  43. package/dist/components/json-schema-form-types.d.ts +108 -0
  44. package/dist/components/json-schema-form-types.d.ts.map +1 -0
  45. package/dist/components.cjs +7 -0
  46. package/dist/components.cjs.map +1 -1
  47. package/dist/components.d.ts +3 -0
  48. package/dist/components.d.ts.map +1 -1
  49. package/dist/components.js +8 -1
  50. package/dist/components.js.map +1 -1
  51. package/dist/data/Clicky.cjs +1 -1
  52. package/dist/data/Clicky.cjs.map +1 -1
  53. package/dist/data/Clicky.js +1 -1
  54. package/dist/data/Clicky.js.map +1 -1
  55. package/dist/data/DataTable.cjs +16 -15
  56. package/dist/data/DataTable.cjs.map +1 -1
  57. package/dist/data/DataTable.d.ts +2 -1
  58. package/dist/data/DataTable.d.ts.map +1 -1
  59. package/dist/data/DataTable.js +16 -15
  60. package/dist/data/DataTable.js.map +1 -1
  61. package/dist/data/Icon.cjs +11 -0
  62. package/dist/data/Icon.cjs.map +1 -1
  63. package/dist/data/Icon.d.ts +12 -1
  64. package/dist/data/Icon.d.ts.map +1 -1
  65. package/dist/data/Icon.js +12 -1
  66. package/dist/data/Icon.js.map +1 -1
  67. package/dist/data/LogDetails.cjs +277 -0
  68. package/dist/data/LogDetails.cjs.map +1 -0
  69. package/dist/data/LogDetails.d.ts +5 -0
  70. package/dist/data/LogDetails.d.ts.map +1 -0
  71. package/dist/data/LogDetails.js +277 -0
  72. package/dist/data/LogDetails.js.map +1 -0
  73. package/dist/data/LogsTable.cjs +6 -202
  74. package/dist/data/LogsTable.cjs.map +1 -1
  75. package/dist/data/LogsTable.d.ts.map +1 -1
  76. package/dist/data/LogsTable.js +4 -200
  77. package/dist/data/LogsTable.js.map +1 -1
  78. package/dist/data/MatrixTable.cjs +17 -9
  79. package/dist/data/MatrixTable.cjs.map +1 -1
  80. package/dist/data/MatrixTable.d.ts +3 -1
  81. package/dist/data/MatrixTable.d.ts.map +1 -1
  82. package/dist/data/MatrixTable.js +17 -9
  83. package/dist/data/MatrixTable.js.map +1 -1
  84. package/dist/data/Properties.cjs +2 -2
  85. package/dist/data/Properties.cjs.map +1 -1
  86. package/dist/data/Properties.js +2 -2
  87. package/dist/data/Properties.js.map +1 -1
  88. package/dist/data/cells/TagList.cjs +19 -3
  89. package/dist/data/cells/TagList.cjs.map +1 -1
  90. package/dist/data/cells/TagList.d.ts +11 -1
  91. package/dist/data/cells/TagList.d.ts.map +1 -1
  92. package/dist/data/cells/TagList.js +19 -3
  93. package/dist/data/cells/TagList.js.map +1 -1
  94. package/dist/data/cells/Timestamp.cjs +17 -2
  95. package/dist/data/cells/Timestamp.cjs.map +1 -1
  96. package/dist/data/cells/Timestamp.d.ts +2 -0
  97. package/dist/data/cells/Timestamp.d.ts.map +1 -1
  98. package/dist/data/cells/Timestamp.js +17 -2
  99. package/dist/data/cells/Timestamp.js.map +1 -1
  100. package/dist/data/log-utils.cjs +7 -0
  101. package/dist/data/log-utils.cjs.map +1 -0
  102. package/dist/data/log-utils.d.ts +2 -0
  103. package/dist/data/log-utils.d.ts.map +1 -0
  104. package/dist/data/log-utils.js +7 -0
  105. package/dist/data/log-utils.js.map +1 -0
  106. package/dist/data.cjs +3 -0
  107. package/dist/data.cjs.map +1 -1
  108. package/dist/data.d.ts +2 -2
  109. package/dist/data.d.ts.map +1 -1
  110. package/dist/data.js +5 -2
  111. package/dist/index.cjs +13 -0
  112. package/dist/index.cjs.map +1 -1
  113. package/dist/index.js +15 -2
  114. package/dist/index.js.map +1 -1
  115. package/dist/rpc/EntityExplorerApp.cjs +3 -2
  116. package/dist/rpc/EntityExplorerApp.cjs.map +1 -1
  117. package/dist/rpc/EntityExplorerApp.js +3 -2
  118. package/dist/rpc/EntityExplorerApp.js.map +1 -1
  119. package/dist/rpc/OperationActionDialog.cjs +1 -1
  120. package/dist/rpc/OperationActionDialog.cjs.map +1 -1
  121. package/dist/rpc/OperationActionDialog.js +1 -1
  122. package/dist/rpc/OperationActionDialog.js.map +1 -1
  123. package/dist/rpc/OperationCommandPage.cjs +21 -14
  124. package/dist/rpc/OperationCommandPage.cjs.map +1 -1
  125. package/dist/rpc/OperationCommandPage.d.ts.map +1 -1
  126. package/dist/rpc/OperationCommandPage.js +21 -14
  127. package/dist/rpc/OperationCommandPage.js.map +1 -1
  128. package/dist/rpc/apiClient.cjs +316 -0
  129. package/dist/rpc/apiClient.cjs.map +1 -0
  130. package/dist/rpc/apiClient.d.ts +44 -0
  131. package/dist/rpc/apiClient.d.ts.map +1 -0
  132. package/dist/rpc/apiClient.js +316 -0
  133. package/dist/rpc/apiClient.js.map +1 -0
  134. package/dist/rpc/useOperations.cjs.map +1 -1
  135. package/dist/rpc/useOperations.d.ts +2 -1
  136. package/dist/rpc/useOperations.d.ts.map +1 -1
  137. package/dist/rpc/useOperations.js.map +1 -1
  138. package/dist/rpc.cjs +3 -0
  139. package/dist/rpc.cjs.map +1 -1
  140. package/dist/rpc.d.ts +1 -0
  141. package/dist/rpc.d.ts.map +1 -1
  142. package/dist/rpc.js +3 -0
  143. package/dist/rpc.js.map +1 -1
  144. package/dist/styles.css +1 -1
  145. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"EntityExplorerApp.cjs","sources":["../../src/rpc/EntityExplorerApp.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { ThemeSwitcher } from \"../components/theme-switcher\";\nimport type { ClickyCommandRuntime, ClickyResolvedCommand } from \"../data/Clicky\";\nimport {\n findSurfaceListOperation,\n getClickySurfaces,\n makeSurfaceDefinition,\n} from \"./clickyMetadata\";\nimport type { RenderLink } from \"./EndpointList\";\nimport { OperationCatalog } from \"./OperationCatalog\";\nimport { OperationCommandPage } from \"./OperationCommandPage\";\nimport { OperationEntityPage } from \"./OperationEntityPage\";\nimport type { ClickySurface } from \"./types\";\nimport type { OperationsApiClient } from \"./useOperations\";\nimport { useOperations } from \"./useOperations\";\n\nexport type EntityExplorerAppProps = {\n client: OperationsApiClient;\n pathname: string;\n renderLink: RenderLink;\n basePath?: string;\n showApiExplorer?: boolean;\n // surfaceIcons maps a ClickySurface.parent slug to a ReactNode rendered next\n // to the group label. Lets the host app drop in brand SVGs (e.g. Xero,\n // Takealot) without coupling clicky-ui to any specific iconography.\n surfaceIcons?: Record<string, ReactNode>;\n};\n\n// SURFACE_GROUP_STATE_KEY persists open/closed state of sidebar groups across\n// reloads. Single localStorage entry, not per-user — operator UI only.\nconst SURFACE_GROUP_STATE_KEY = \"clicky-ui:sidebar:groupCollapsed\";\n\nexport function EntityExplorerApp({\n client,\n pathname,\n renderLink,\n basePath = \"\",\n showApiExplorer = true,\n surfaceIcons,\n}: EntityExplorerAppProps) {\n const { operations, spec } = useOperations(client);\n const surfaces = useMemo(() => getClickySurfaces(spec), [spec]);\n const surfaceGroups = useMemo(() => groupSurfacesByParent(surfaces), [surfaces]);\n const listHrefBySurface = useMemo(() => {\n const out: Record<string, string> = {};\n for (const surface of surfaces) {\n const listOp = findSurfaceListOperation(operations, surface.key);\n if (!listOp?.operation.operationId) continue;\n const href = buildCommandHref(basePath, {\n operation: listOp,\n request: { command: listOp.operation.operationId, autoRun: true },\n });\n if (href) out[surface.key] = href;\n }\n return out;\n }, [basePath, operations, surfaces]);\n const [collapsedGroups, setCollapsedGroups] = useState<Record<string, boolean>>(() =>\n readCollapsedGroups(),\n );\n const toggleGroup = useCallback((parent: string) => {\n setCollapsedGroups((prev) => {\n const next = { ...prev, [parent]: !prev[parent] };\n writeCollapsedGroups(next);\n return next;\n });\n }, []);\n const defaultSurface = useMemo(\n () => surfaces.find((surface) => !surface.admin) ?? surfaces[0],\n [surfaces],\n );\n const relativePath = useMemo(() => stripBasePath(pathname, basePath), [basePath, pathname]);\n const route = useMemo(() => parseExplorerRoute(relativePath), [relativePath]);\n const resolvedRoute = useMemo(() => resolveRouteSurface(route, surfaces), [route, surfaces]);\n const commandRuntime = useMemo<ClickyCommandRuntime>(\n () => ({\n client,\n hrefForCommand: (resolved) => buildCommandHref(basePath, resolved),\n onNavigate: (resolved) => {\n const href = buildCommandHref(basePath, resolved);\n if (!href || typeof window === \"undefined\") return;\n window.history.pushState(window.history.state, \"\", href);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n },\n }),\n [basePath, client],\n );\n const { initialValues: commandInitialValues, autoRun: commandAutoRun } = useMemo(\n () =>\n resolvedRoute.kind === \"command\"\n ? readCommandQueryParams()\n : { initialValues: {}, autoRun: false },\n [resolvedRoute.kind, pathname],\n );\n const explorerDefinition = useMemo(\n () => ({\n key: \"explorer\",\n title: \"API Explorer\",\n description: \"Every operation exposed by the current OpenAPI spec.\",\n }),\n [],\n );\n\n useEffect(() => {\n if (\n typeof window === \"undefined\" ||\n defaultSurface == null ||\n relativePath !== \"/\" ||\n window.location.pathname !== withBasePath(basePath, \"/\")\n ) {\n return;\n }\n\n const target = withBasePath(basePath, `/${defaultSurface.key}`);\n window.history.replaceState(window.history.state, \"\", target);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }, [basePath, defaultSurface, relativePath]);\n\n return (\n <div className=\"flex h-full\">\n <aside className=\"flex w-64 shrink-0 flex-col border-r border-border bg-muted/30 p-4\">\n <div className=\"mb-6\">\n <div className=\"text-sm font-semibold\">{spec?.info.title ?? \"Clicky Explorer\"}</div>\n <div className=\"text-xs text-muted-foreground\">Metadata-driven entity explorer</div>\n </div>\n <nav className=\"flex flex-col gap-2\">\n {surfaceGroups.map((group) => {\n const collapsed = collapsedGroups[group.parent] ?? false;\n return (\n <div key={group.parent} className=\"flex flex-col\">\n <button\n type=\"button\"\n onClick={() => toggleGroup(group.parent)}\n aria-expanded={!collapsed}\n className=\"flex items-center gap-2 rounded-md px-2 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground transition-colors hover:bg-accent/40\"\n >\n {surfaceIcons?.[group.parent] != null && (\n <span className=\"flex h-4 w-4 items-center justify-center text-current\">\n {surfaceIcons[group.parent]}\n </span>\n )}\n <span className=\"flex-1 text-left\">{group.label}</span>\n <span aria-hidden className=\"text-[0.65rem] opacity-60\">\n {collapsed ? \"▸\" : \"▾\"}\n </span>\n </button>\n {!collapsed && (\n <div className=\"ml-2 mt-1 flex flex-col gap-1 border-l border-border/60 pl-2\">\n {group.surfaces.map((surface) =>\n renderLink({\n key: surface.key,\n to:\n listHrefBySurface[surface.key] ??\n withBasePath(basePath, `/${surface.key}`),\n className: navLinkClassName(\n isSurfaceRouteActive(resolvedRoute, surface.key),\n ),\n children: surface.title,\n }),\n )}\n </div>\n )}\n </div>\n );\n })}\n {showApiExplorer &&\n renderLink({\n key: explorerDefinition.key,\n to: withBasePath(basePath, \"/explorer\"),\n className: navLinkClassName(\n resolvedRoute.kind === \"explorer\" || resolvedRoute.kind === \"command\",\n ),\n children: explorerDefinition.title,\n })}\n </nav>\n <div className=\"mt-auto pt-4\">\n <ThemeSwitcher />\n </div>\n </aside>\n\n <main className=\"flex-1 overflow-auto p-6\">\n {resolvedRoute.kind === \"surface\" ? (\n resolvedRoute.surface ? (\n <OperationCatalog\n definition={makeSurfaceDefinition(resolvedRoute.surface)}\n entities={[resolvedRoute.surface.entity]}\n client={client}\n renderLink={renderLink}\n surfaceKey={resolvedRoute.surface.key}\n commandRuntime={commandRuntime}\n />\n ) : (\n <UnknownSurface surfaceKey={resolvedRoute.surfaceKey} />\n )\n ) : resolvedRoute.kind === \"entity\" ? (\n resolvedRoute.surface ? (\n <OperationEntityPage\n definition={makeSurfaceDefinition(resolvedRoute.surface)}\n entities={[resolvedRoute.surface.entity]}\n client={client}\n renderLink={renderLink}\n surfaceKey={resolvedRoute.surface.key}\n backHref={withBasePath(basePath, `/${resolvedRoute.surface.key}`)}\n backLabel={`Back to ${resolvedRoute.surface.title}`}\n commandRuntime={commandRuntime}\n {...(resolvedRoute.id ? { id: resolvedRoute.id } : {})}\n />\n ) : (\n <UnknownSurface surfaceKey={resolvedRoute.surfaceKey} />\n )\n ) : resolvedRoute.kind === \"command\" ? (\n <OperationCommandPage\n client={client}\n backHref={withBasePath(basePath, \"/explorer\")}\n backLabel=\"Back to API Explorer\"\n renderLink={renderLink}\n commandRuntime={commandRuntime}\n initialValues={commandInitialValues}\n autoRun={commandAutoRun}\n {...(resolvedRoute.operationId ? { operationId: resolvedRoute.operationId } : {})}\n />\n ) : resolvedRoute.kind === \"explorer\" ? (\n <OperationCatalog\n definition={explorerDefinition}\n entities={[]}\n allOperations\n client={client}\n renderLink={renderLink}\n commandRuntime={commandRuntime}\n />\n ) : defaultSurface == null ? (\n <div className=\"text-sm text-muted-foreground\">Loading surfaces…</div>\n ) : (\n <div className=\"text-sm text-muted-foreground\">Redirecting…</div>\n )}\n </main>\n </div>\n );\n}\n\ntype ExplorerRoute =\n | { kind: \"root\" }\n | { kind: \"explorer\" }\n | { kind: \"command\"; operationId?: string }\n | { kind: \"surface\"; surfaceKey: string; surface?: ClickySurface }\n | {\n kind: \"entity\";\n surfaceKey: string;\n surface?: ClickySurface;\n id?: string;\n };\n\nfunction parseExplorerRoute(pathname: string): ExplorerRoute {\n const normalized = trimTrailingSlash(pathname) || \"/\";\n if (normalized === \"/\") {\n return { kind: \"root\" };\n }\n\n const segments = normalized.replace(/^\\/+/, \"\").split(\"/\");\n if (segments[0] === \"explorer\") {\n return { kind: \"explorer\" };\n }\n if (segments[0] === \"commands\") {\n return segments[1] ? { kind: \"command\", operationId: segments[1] } : { kind: \"command\" };\n }\n const surfaceKey = segments[0] ?? \"\";\n if (segments[1]) {\n return {\n kind: \"entity\",\n surfaceKey,\n id: decodeURIComponent(segments[1]),\n };\n }\n return { kind: \"surface\", surfaceKey };\n}\n\nfunction resolveRouteSurface(route: ExplorerRoute, surfaces: ClickySurface[]): ExplorerRoute {\n if (route.kind !== \"surface\" && route.kind !== \"entity\") {\n return route;\n }\n const surface = surfaces.find((item) => item.key === route.surfaceKey);\n return surface ? { ...route, surface } : route;\n}\n\nfunction isSurfaceRouteActive(route: ExplorerRoute, surfaceKey: string) {\n return (\n (route.kind === \"surface\" && route.surfaceKey === surfaceKey) ||\n (route.kind === \"entity\" && route.surfaceKey === surfaceKey)\n );\n}\n\nfunction navLinkClassName(active: boolean) {\n return [\n \"rounded-md px-2 py-1.5 text-sm transition-colors\",\n active ? \"bg-accent text-accent-foreground\" : \"text-foreground hover:bg-accent\",\n ].join(\" \");\n}\n\nfunction stripBasePath(pathname: string, basePath: string) {\n const base = trimTrailingSlash(basePath);\n if (!base || base === \"/\") {\n return trimTrailingSlash(pathname) || \"/\";\n }\n if (pathname === base) {\n return \"/\";\n }\n if (pathname.startsWith(`${base}/`)) {\n return trimTrailingSlash(pathname.slice(base.length)) || \"/\";\n }\n return trimTrailingSlash(pathname) || \"/\";\n}\n\nfunction withBasePath(basePath: string, pathname: string) {\n const base = trimTrailingSlash(basePath);\n if (!base || base === \"/\") {\n return pathname;\n }\n return `${base}${pathname}`;\n}\n\nfunction trimTrailingSlash(value: string) {\n if (!value) return \"\";\n return value.length > 1 ? value.replace(/\\/+$/, \"\") : value;\n}\n\nfunction UnknownSurface({ surfaceKey }: { surfaceKey: string }) {\n return (\n <div className=\"p-6 text-sm text-muted-foreground\">\n Unknown surface: <code>{surfaceKey}</code>\n </div>\n );\n}\n\nconst AUTORUN_QUERY_PARAM = \"__autoRun\";\nconst ARG_QUERY_PREFIX = \"__arg\";\n\nfunction buildCommandHref(basePath: string, resolved: ClickyResolvedCommand): string | undefined {\n const commandId = resolved.operation?.operation.operationId ?? resolved.request.command;\n if (!commandId) return undefined;\n\n const meta = resolved.operation?.operation[\"x-clicky\"];\n const args = resolved.request.args ?? [];\n const flags = resolved.request.flags ?? {};\n\n // Entity `get` commands route to the surface detail URL: /<surface>/<id>?<flags>\n if (meta?.verb === \"get\" && meta?.scope === \"entity\" && meta.surface && args[0]) {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(flags)) {\n if (value !== undefined && value !== \"\") {\n search.set(key, value);\n }\n }\n const query = search.toString();\n const suffix = query ? `?${query}` : \"\";\n return withBasePath(\n basePath,\n `/${encodeURIComponent(meta.surface)}/${encodeURIComponent(args[0])}${suffix}`,\n );\n }\n\n const search = new URLSearchParams();\n args.forEach((value, index) => {\n if (value !== undefined && value !== \"\") {\n search.set(`${ARG_QUERY_PREFIX}${index}`, value);\n }\n });\n for (const [key, value] of Object.entries(flags)) {\n if (value !== undefined && value !== \"\") {\n search.set(key, value);\n }\n }\n if (resolved.request.autoRun) {\n search.set(AUTORUN_QUERY_PARAM, \"1\");\n }\n\n const query = search.toString();\n const suffix = query ? `?${query}` : \"\";\n return withBasePath(basePath, `/commands/${encodeURIComponent(commandId)}${suffix}`);\n}\n\ntype SurfaceGroup = {\n parent: string; // the slug; \"\" for surfaces that declared no parent\n label: string; // display name in the sidebar\n surfaces: ClickySurface[];\n};\n\n// groupSurfacesByParent buckets surfaces by their ClickySurface.parent slug,\n// preserving the order surfaces appeared in the spec. Surfaces with no parent\n// fall into a trailing \"\" bucket labelled \"Other\".\nfunction groupSurfacesByParent(surfaces: ClickySurface[]): SurfaceGroup[] {\n const order: string[] = [];\n const buckets = new Map<string, ClickySurface[]>();\n for (const surface of surfaces) {\n const parent = surface.parent ?? \"\";\n if (!buckets.has(parent)) {\n buckets.set(parent, []);\n order.push(parent);\n }\n buckets.get(parent)!.push(surface);\n }\n return order.map((parent) => ({\n parent,\n label: parent === \"\" ? \"Other\" : titleCase(parent),\n surfaces: buckets.get(parent)!,\n }));\n}\n\nfunction titleCase(value: string): string {\n if (!value) return value;\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nfunction readCollapsedGroups(): Record<string, boolean> {\n if (typeof window === \"undefined\") return {};\n try {\n const raw = window.localStorage.getItem(SURFACE_GROUP_STATE_KEY);\n if (!raw) return {};\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? (parsed as Record<string, boolean>) : {};\n } catch {\n return {};\n }\n}\n\nfunction writeCollapsedGroups(state: Record<string, boolean>) {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(SURFACE_GROUP_STATE_KEY, JSON.stringify(state));\n } catch {\n // Quota / private-mode failures are safe to swallow — sidebar state is\n // purely a UX nicety, not a correctness signal.\n }\n}\n\nfunction readCommandQueryParams(): { initialValues: Record<string, string>; autoRun: boolean } {\n if (typeof window === \"undefined\") {\n return { initialValues: {}, autoRun: false };\n }\n const search = new URLSearchParams(window.location.search);\n const initialValues: Record<string, string> = {};\n let autoRun = false;\n const positional: string[] = [];\n\n for (const [key, value] of search.entries()) {\n if (key === AUTORUN_QUERY_PARAM) {\n autoRun = value === \"1\" || value === \"true\";\n continue;\n }\n if (key.startsWith(ARG_QUERY_PREFIX)) {\n const index = Number.parseInt(key.slice(ARG_QUERY_PREFIX.length), 10);\n if (Number.isFinite(index) && index >= 0) {\n positional[index] = value;\n }\n continue;\n }\n initialValues[key] = value;\n }\n\n const packedArgs = positional.filter((value) => value !== undefined).join(\" \");\n if (packedArgs !== \"\") {\n initialValues.args = packedArgs;\n }\n\n return { initialValues, autoRun };\n}\n"],"names":["useOperations","useMemo","getClickySurfaces","findSurfaceListOperation","useState","useCallback","useEffect","jsxs","jsx","ThemeSwitcher","OperationCatalog","makeSurfaceDefinition","OperationEntityPage","OperationCommandPage","search","query","suffix"],"mappings":"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"}
1
+ {"version":3,"file":"EntityExplorerApp.cjs","sources":["../../src/rpc/EntityExplorerApp.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { ThemeSwitcher } from \"../components/theme-switcher\";\nimport type { ClickyCommandRuntime, ClickyResolvedCommand } from \"../data/Clicky\";\nimport {\n findSurfaceListOperation,\n getClickySurfaces,\n makeSurfaceDefinition,\n} from \"./clickyMetadata\";\nimport type { RenderLink } from \"./EndpointList\";\nimport { OperationCatalog } from \"./OperationCatalog\";\nimport { OperationCommandPage } from \"./OperationCommandPage\";\nimport { OperationEntityPage } from \"./OperationEntityPage\";\nimport type { ClickySurface } from \"./types\";\nimport type { OperationsApiClient } from \"./useOperations\";\nimport { useOperations } from \"./useOperations\";\n\nexport type EntityExplorerAppProps = {\n client: OperationsApiClient;\n pathname: string;\n renderLink: RenderLink;\n basePath?: string;\n showApiExplorer?: boolean;\n // surfaceIcons maps a ClickySurface.parent slug to a ReactNode rendered next\n // to the group label. Lets the host app drop in brand SVGs (e.g. Xero,\n // Takealot) without coupling clicky-ui to any specific iconography.\n surfaceIcons?: Record<string, ReactNode>;\n};\n\n// SURFACE_GROUP_STATE_KEY persists open/closed state of sidebar groups across\n// reloads. Single localStorage entry, not per-user — operator UI only.\nconst SURFACE_GROUP_STATE_KEY = \"clicky-ui:sidebar:groupCollapsed\";\n\nexport function EntityExplorerApp({\n client,\n pathname,\n renderLink,\n basePath = \"\",\n showApiExplorer = true,\n surfaceIcons,\n}: EntityExplorerAppProps) {\n const { operations, spec } = useOperations(client);\n const surfaces = useMemo(() => getClickySurfaces(spec), [spec]);\n const surfaceGroups = useMemo(() => groupSurfacesByParent(surfaces), [surfaces]);\n const listHrefBySurface = useMemo(() => {\n const out: Record<string, string> = {};\n for (const surface of surfaces) {\n const listOp = findSurfaceListOperation(operations, surface.key);\n if (!listOp?.operation.operationId) continue;\n const href = buildCommandHref(basePath, {\n operation: listOp,\n request: { command: listOp.operation.operationId, autoRun: true },\n });\n if (href) out[surface.key] = href;\n }\n return out;\n }, [basePath, operations, surfaces]);\n const [collapsedGroups, setCollapsedGroups] = useState<Record<string, boolean>>(() =>\n readCollapsedGroups(),\n );\n const toggleGroup = useCallback((parent: string) => {\n setCollapsedGroups((prev) => {\n const next = { ...prev, [parent]: !prev[parent] };\n writeCollapsedGroups(next);\n return next;\n });\n }, []);\n const defaultSurface = useMemo(\n () => surfaces.find((surface) => !surface.admin) ?? surfaces[0],\n [surfaces],\n );\n const relativePath = useMemo(() => stripBasePath(pathname, basePath), [basePath, pathname]);\n const route = useMemo(() => parseExplorerRoute(relativePath), [relativePath]);\n const resolvedRoute = useMemo(() => resolveRouteSurface(route, surfaces), [route, surfaces]);\n const commandRuntime = useMemo<ClickyCommandRuntime>(\n () => ({\n client,\n hrefForCommand: (resolved) => buildCommandHref(basePath, resolved),\n onNavigate: (resolved) => {\n const href = buildCommandHref(basePath, resolved);\n if (!href || typeof window === \"undefined\") return;\n window.history.pushState(window.history.state, \"\", href);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n },\n }),\n [basePath, client],\n );\n const { initialValues: commandInitialValues, autoRun: commandAutoRun } = useMemo(\n () =>\n resolvedRoute.kind === \"command\"\n ? readCommandQueryParams()\n : { initialValues: {}, autoRun: false },\n [resolvedRoute.kind, pathname],\n );\n const explorerDefinition = useMemo(\n () => ({\n key: \"explorer\",\n title: \"API Explorer\",\n description: \"Every operation exposed by the current OpenAPI spec.\",\n }),\n [],\n );\n\n useEffect(() => {\n if (\n typeof window === \"undefined\" ||\n defaultSurface == null ||\n relativePath !== \"/\" ||\n window.location.pathname !== withBasePath(basePath, \"/\")\n ) {\n return;\n }\n\n const target = withBasePath(basePath, `/${defaultSurface.key}`);\n window.history.replaceState(window.history.state, \"\", target);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }, [basePath, defaultSurface, relativePath]);\n\n return (\n <div className=\"flex h-full\">\n <aside className=\"flex w-64 shrink-0 flex-col border-r border-border bg-muted/30 p-4\">\n <div className=\"mb-6\">\n <div className=\"text-sm font-semibold\">{spec?.info.title ?? \"Clicky Explorer\"}</div>\n <div className=\"text-xs text-muted-foreground\">Metadata-driven entity explorer</div>\n </div>\n <nav className=\"flex flex-col gap-2\">\n {surfaceGroups.map((group) => {\n const collapsed = collapsedGroups[group.parent] ?? false;\n return (\n <div key={group.parent} className=\"flex flex-col\">\n <button\n type=\"button\"\n onClick={() => toggleGroup(group.parent)}\n aria-expanded={!collapsed}\n className=\"flex items-center gap-2 rounded-md px-2 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground transition-colors hover:bg-accent/40\"\n >\n {surfaceIcons?.[group.parent] != null && (\n <span className=\"flex h-4 w-4 items-center justify-center text-current\">\n {surfaceIcons[group.parent]}\n </span>\n )}\n <span className=\"flex-1 text-left\">{group.label}</span>\n <span aria-hidden className=\"text-[0.65rem] opacity-60\">\n {collapsed ? \"▸\" : \"▾\"}\n </span>\n </button>\n {!collapsed && (\n <div className=\"ml-2 mt-1 flex flex-col gap-1 border-l border-border/60 pl-2\">\n {group.surfaces.map((surface) =>\n renderLink({\n key: surface.key,\n to:\n listHrefBySurface[surface.key] ??\n withBasePath(basePath, `/${surface.key}`),\n className: navLinkClassName(\n isSurfaceRouteActive(resolvedRoute, surface.key),\n ),\n children: surface.title,\n }),\n )}\n </div>\n )}\n </div>\n );\n })}\n {showApiExplorer &&\n renderLink({\n key: explorerDefinition.key,\n to: withBasePath(basePath, \"/explorer\"),\n className: navLinkClassName(\n resolvedRoute.kind === \"explorer\" || resolvedRoute.kind === \"command\",\n ),\n children: explorerDefinition.title,\n })}\n </nav>\n <div className=\"mt-auto pt-4\">\n <ThemeSwitcher />\n </div>\n </aside>\n\n <main className=\"flex-1 overflow-auto p-6\">\n {resolvedRoute.kind === \"surface\" ? (\n resolvedRoute.surface ? (\n <OperationCatalog\n definition={makeSurfaceDefinition(resolvedRoute.surface)}\n entities={[resolvedRoute.surface.entity]}\n client={client}\n renderLink={renderLink}\n surfaceKey={resolvedRoute.surface.key}\n commandRuntime={commandRuntime}\n />\n ) : (\n <UnknownSurface surfaceKey={resolvedRoute.surfaceKey} />\n )\n ) : resolvedRoute.kind === \"entity\" ? (\n resolvedRoute.surface ? (\n <OperationEntityPage\n definition={makeSurfaceDefinition(resolvedRoute.surface)}\n entities={[resolvedRoute.surface.entity]}\n client={client}\n renderLink={renderLink}\n surfaceKey={resolvedRoute.surface.key}\n backHref={withBasePath(basePath, `/${resolvedRoute.surface.key}`)}\n backLabel={`Back to ${resolvedRoute.surface.title}`}\n commandRuntime={commandRuntime}\n {...(resolvedRoute.id ? { id: resolvedRoute.id } : {})}\n />\n ) : (\n <UnknownSurface surfaceKey={resolvedRoute.surfaceKey} />\n )\n ) : resolvedRoute.kind === \"command\" ? (\n <OperationCommandPage\n client={client}\n backHref={withBasePath(basePath, \"/explorer\")}\n backLabel=\"Back to API Explorer\"\n renderLink={renderLink}\n commandRuntime={commandRuntime}\n initialValues={commandInitialValues}\n autoRun={commandAutoRun}\n {...(resolvedRoute.operationId ? { operationId: resolvedRoute.operationId } : {})}\n />\n ) : resolvedRoute.kind === \"explorer\" ? (\n <OperationCatalog\n definition={explorerDefinition}\n entities={[]}\n allOperations\n client={client}\n renderLink={renderLink}\n commandRuntime={commandRuntime}\n />\n ) : defaultSurface == null ? (\n <div className=\"text-sm text-muted-foreground\">Loading surfaces…</div>\n ) : (\n <div className=\"text-sm text-muted-foreground\">Redirecting…</div>\n )}\n </main>\n </div>\n );\n}\n\ntype ExplorerRoute =\n | { kind: \"root\" }\n | { kind: \"explorer\" }\n | { kind: \"command\"; operationId?: string }\n | { kind: \"surface\"; surfaceKey: string; surface?: ClickySurface }\n | {\n kind: \"entity\";\n surfaceKey: string;\n surface?: ClickySurface;\n id?: string;\n };\n\nfunction parseExplorerRoute(pathname: string): ExplorerRoute {\n const normalized = trimTrailingSlash(pathname) || \"/\";\n if (normalized === \"/\") {\n return { kind: \"root\" };\n }\n\n const segments = normalized.replace(/^\\/+/, \"\").split(\"/\");\n if (segments[0] === \"explorer\") {\n return { kind: \"explorer\" };\n }\n if (segments[0] === \"commands\") {\n return segments[1] ? { kind: \"command\", operationId: segments[1] } : { kind: \"command\" };\n }\n const surfaceKey = segments[0] ?? \"\";\n if (segments[1]) {\n return {\n kind: \"entity\",\n surfaceKey,\n id: decodeURIComponent(segments[1]),\n };\n }\n return { kind: \"surface\", surfaceKey };\n}\n\nfunction resolveRouteSurface(route: ExplorerRoute, surfaces: ClickySurface[]): ExplorerRoute {\n if (route.kind !== \"surface\" && route.kind !== \"entity\") {\n return route;\n }\n const surface = surfaces.find((item) => item.key === route.surfaceKey);\n return surface ? { ...route, surface } : route;\n}\n\nfunction isSurfaceRouteActive(route: ExplorerRoute, surfaceKey: string) {\n return (\n (route.kind === \"surface\" && route.surfaceKey === surfaceKey) ||\n (route.kind === \"entity\" && route.surfaceKey === surfaceKey)\n );\n}\n\nfunction navLinkClassName(active: boolean) {\n return [\n \"rounded-md px-2 py-1.5 text-sm transition-colors\",\n active ? \"bg-accent text-accent-foreground\" : \"text-foreground hover:bg-accent\",\n ].join(\" \");\n}\n\nfunction stripBasePath(pathname: string, basePath: string) {\n const base = trimTrailingSlash(basePath);\n if (!base || base === \"/\") {\n return trimTrailingSlash(pathname) || \"/\";\n }\n if (pathname === base) {\n return \"/\";\n }\n if (pathname.startsWith(`${base}/`)) {\n return trimTrailingSlash(pathname.slice(base.length)) || \"/\";\n }\n return trimTrailingSlash(pathname) || \"/\";\n}\n\nfunction withBasePath(basePath: string, pathname: string) {\n const base = trimTrailingSlash(basePath);\n if (!base || base === \"/\") {\n return pathname;\n }\n return `${base}${pathname}`;\n}\n\nfunction trimTrailingSlash(value: string) {\n if (!value) return \"\";\n return value.length > 1 ? value.replace(/\\/+$/, \"\") : value;\n}\n\nfunction UnknownSurface({ surfaceKey }: { surfaceKey: string }) {\n return (\n <div className=\"p-6 text-sm text-muted-foreground\">\n Unknown surface: <code>{surfaceKey}</code>\n </div>\n );\n}\n\nconst AUTORUN_QUERY_PARAM = \"autoRun\";\nconst LEGACY_AUTORUN_QUERY_PARAM = \"__autoRun\";\nconst ARG_QUERY_PREFIX = \"__arg\";\n\nfunction buildCommandHref(basePath: string, resolved: ClickyResolvedCommand): string | undefined {\n const commandId = resolved.operation?.operation.operationId ?? resolved.request.command;\n if (!commandId) return undefined;\n\n const meta = resolved.operation?.operation[\"x-clicky\"];\n const args = resolved.request.args ?? [];\n const flags = resolved.request.flags ?? {};\n\n // Entity `get` commands route to the surface detail URL: /<surface>/<id>?<flags>\n if (meta?.verb === \"get\" && meta?.scope === \"entity\" && meta.surface && args[0]) {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(flags)) {\n if (value !== undefined && value !== \"\") {\n search.set(key, value);\n }\n }\n const query = search.toString();\n const suffix = query ? `?${query}` : \"\";\n return withBasePath(\n basePath,\n `/${encodeURIComponent(meta.surface)}/${encodeURIComponent(args[0])}${suffix}`,\n );\n }\n\n const search = new URLSearchParams();\n args.forEach((value, index) => {\n if (value !== undefined && value !== \"\") {\n search.set(`${ARG_QUERY_PREFIX}${index}`, value);\n }\n });\n for (const [key, value] of Object.entries(flags)) {\n if (value !== undefined && value !== \"\") {\n search.set(key, value);\n }\n }\n if (resolved.request.autoRun) {\n search.set(AUTORUN_QUERY_PARAM, \"1\");\n }\n\n const query = search.toString();\n const suffix = query ? `?${query}` : \"\";\n return withBasePath(basePath, `/commands/${encodeURIComponent(commandId)}${suffix}`);\n}\n\ntype SurfaceGroup = {\n parent: string; // the slug; \"\" for surfaces that declared no parent\n label: string; // display name in the sidebar\n surfaces: ClickySurface[];\n};\n\n// groupSurfacesByParent buckets surfaces by their ClickySurface.parent slug,\n// preserving the order surfaces appeared in the spec. Surfaces with no parent\n// fall into a trailing \"\" bucket labelled \"Other\".\nfunction groupSurfacesByParent(surfaces: ClickySurface[]): SurfaceGroup[] {\n const order: string[] = [];\n const buckets = new Map<string, ClickySurface[]>();\n for (const surface of surfaces) {\n const parent = surface.parent ?? \"\";\n if (!buckets.has(parent)) {\n buckets.set(parent, []);\n order.push(parent);\n }\n buckets.get(parent)!.push(surface);\n }\n return order.map((parent) => ({\n parent,\n label: parent === \"\" ? \"Other\" : titleCase(parent),\n surfaces: buckets.get(parent)!,\n }));\n}\n\nfunction titleCase(value: string): string {\n if (!value) return value;\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nfunction readCollapsedGroups(): Record<string, boolean> {\n if (typeof window === \"undefined\") return {};\n try {\n const raw = window.localStorage.getItem(SURFACE_GROUP_STATE_KEY);\n if (!raw) return {};\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? (parsed as Record<string, boolean>) : {};\n } catch {\n return {};\n }\n}\n\nfunction writeCollapsedGroups(state: Record<string, boolean>) {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(SURFACE_GROUP_STATE_KEY, JSON.stringify(state));\n } catch {\n // Quota / private-mode failures are safe to swallow — sidebar state is\n // purely a UX nicety, not a correctness signal.\n }\n}\n\nfunction readCommandQueryParams(): { initialValues: Record<string, string>; autoRun: boolean } {\n if (typeof window === \"undefined\") {\n return { initialValues: {}, autoRun: false };\n }\n const search = new URLSearchParams(window.location.search);\n const initialValues: Record<string, string> = {};\n let autoRun = false;\n const positional: string[] = [];\n\n for (const [key, value] of search.entries()) {\n if (key === AUTORUN_QUERY_PARAM || key === LEGACY_AUTORUN_QUERY_PARAM) {\n autoRun = value === \"1\" || value === \"true\";\n continue;\n }\n if (key.startsWith(ARG_QUERY_PREFIX)) {\n const index = Number.parseInt(key.slice(ARG_QUERY_PREFIX.length), 10);\n if (Number.isFinite(index) && index >= 0) {\n positional[index] = value;\n }\n continue;\n }\n initialValues[key] = value;\n }\n\n const packedArgs = positional.filter((value) => value !== undefined).join(\" \");\n if (packedArgs !== \"\") {\n initialValues.args = packedArgs;\n }\n\n return { initialValues, autoRun };\n}\n"],"names":["useOperations","useMemo","getClickySurfaces","findSurfaceListOperation","useState","useCallback","useEffect","jsxs","jsx","ThemeSwitcher","OperationCatalog","makeSurfaceDefinition","OperationEntityPage","OperationCommandPage","search","query","suffix"],"mappings":"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"}
@@ -244,7 +244,8 @@ function UnknownSurface({ surfaceKey }) {
244
244
  /* @__PURE__ */ jsx("code", { children: surfaceKey })
245
245
  ] });
246
246
  }
247
- const AUTORUN_QUERY_PARAM = "__autoRun";
247
+ const AUTORUN_QUERY_PARAM = "autoRun";
248
+ const LEGACY_AUTORUN_QUERY_PARAM = "__autoRun";
248
249
  const ARG_QUERY_PREFIX = "__arg";
249
250
  function buildCommandHref(basePath, resolved) {
250
251
  var _a, _b;
@@ -333,7 +334,7 @@ function readCommandQueryParams() {
333
334
  let autoRun = false;
334
335
  const positional = [];
335
336
  for (const [key, value] of search.entries()) {
336
- if (key === AUTORUN_QUERY_PARAM) {
337
+ if (key === AUTORUN_QUERY_PARAM || key === LEGACY_AUTORUN_QUERY_PARAM) {
337
338
  autoRun = value === "1" || value === "true";
338
339
  continue;
339
340
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EntityExplorerApp.js","sources":["../../src/rpc/EntityExplorerApp.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { ThemeSwitcher } from \"../components/theme-switcher\";\nimport type { ClickyCommandRuntime, ClickyResolvedCommand } from \"../data/Clicky\";\nimport {\n findSurfaceListOperation,\n getClickySurfaces,\n makeSurfaceDefinition,\n} from \"./clickyMetadata\";\nimport type { RenderLink } from \"./EndpointList\";\nimport { OperationCatalog } from \"./OperationCatalog\";\nimport { OperationCommandPage } from \"./OperationCommandPage\";\nimport { OperationEntityPage } from \"./OperationEntityPage\";\nimport type { ClickySurface } from \"./types\";\nimport type { OperationsApiClient } from \"./useOperations\";\nimport { useOperations } from \"./useOperations\";\n\nexport type EntityExplorerAppProps = {\n client: OperationsApiClient;\n pathname: string;\n renderLink: RenderLink;\n basePath?: string;\n showApiExplorer?: boolean;\n // surfaceIcons maps a ClickySurface.parent slug to a ReactNode rendered next\n // to the group label. Lets the host app drop in brand SVGs (e.g. Xero,\n // Takealot) without coupling clicky-ui to any specific iconography.\n surfaceIcons?: Record<string, ReactNode>;\n};\n\n// SURFACE_GROUP_STATE_KEY persists open/closed state of sidebar groups across\n// reloads. Single localStorage entry, not per-user — operator UI only.\nconst SURFACE_GROUP_STATE_KEY = \"clicky-ui:sidebar:groupCollapsed\";\n\nexport function EntityExplorerApp({\n client,\n pathname,\n renderLink,\n basePath = \"\",\n showApiExplorer = true,\n surfaceIcons,\n}: EntityExplorerAppProps) {\n const { operations, spec } = useOperations(client);\n const surfaces = useMemo(() => getClickySurfaces(spec), [spec]);\n const surfaceGroups = useMemo(() => groupSurfacesByParent(surfaces), [surfaces]);\n const listHrefBySurface = useMemo(() => {\n const out: Record<string, string> = {};\n for (const surface of surfaces) {\n const listOp = findSurfaceListOperation(operations, surface.key);\n if (!listOp?.operation.operationId) continue;\n const href = buildCommandHref(basePath, {\n operation: listOp,\n request: { command: listOp.operation.operationId, autoRun: true },\n });\n if (href) out[surface.key] = href;\n }\n return out;\n }, [basePath, operations, surfaces]);\n const [collapsedGroups, setCollapsedGroups] = useState<Record<string, boolean>>(() =>\n readCollapsedGroups(),\n );\n const toggleGroup = useCallback((parent: string) => {\n setCollapsedGroups((prev) => {\n const next = { ...prev, [parent]: !prev[parent] };\n writeCollapsedGroups(next);\n return next;\n });\n }, []);\n const defaultSurface = useMemo(\n () => surfaces.find((surface) => !surface.admin) ?? surfaces[0],\n [surfaces],\n );\n const relativePath = useMemo(() => stripBasePath(pathname, basePath), [basePath, pathname]);\n const route = useMemo(() => parseExplorerRoute(relativePath), [relativePath]);\n const resolvedRoute = useMemo(() => resolveRouteSurface(route, surfaces), [route, surfaces]);\n const commandRuntime = useMemo<ClickyCommandRuntime>(\n () => ({\n client,\n hrefForCommand: (resolved) => buildCommandHref(basePath, resolved),\n onNavigate: (resolved) => {\n const href = buildCommandHref(basePath, resolved);\n if (!href || typeof window === \"undefined\") return;\n window.history.pushState(window.history.state, \"\", href);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n },\n }),\n [basePath, client],\n );\n const { initialValues: commandInitialValues, autoRun: commandAutoRun } = useMemo(\n () =>\n resolvedRoute.kind === \"command\"\n ? readCommandQueryParams()\n : { initialValues: {}, autoRun: false },\n [resolvedRoute.kind, pathname],\n );\n const explorerDefinition = useMemo(\n () => ({\n key: \"explorer\",\n title: \"API Explorer\",\n description: \"Every operation exposed by the current OpenAPI spec.\",\n }),\n [],\n );\n\n useEffect(() => {\n if (\n typeof window === \"undefined\" ||\n defaultSurface == null ||\n relativePath !== \"/\" ||\n window.location.pathname !== withBasePath(basePath, \"/\")\n ) {\n return;\n }\n\n const target = withBasePath(basePath, `/${defaultSurface.key}`);\n window.history.replaceState(window.history.state, \"\", target);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }, [basePath, defaultSurface, relativePath]);\n\n return (\n <div className=\"flex h-full\">\n <aside className=\"flex w-64 shrink-0 flex-col border-r border-border bg-muted/30 p-4\">\n <div className=\"mb-6\">\n <div className=\"text-sm font-semibold\">{spec?.info.title ?? \"Clicky Explorer\"}</div>\n <div className=\"text-xs text-muted-foreground\">Metadata-driven entity explorer</div>\n </div>\n <nav className=\"flex flex-col gap-2\">\n {surfaceGroups.map((group) => {\n const collapsed = collapsedGroups[group.parent] ?? false;\n return (\n <div key={group.parent} className=\"flex flex-col\">\n <button\n type=\"button\"\n onClick={() => toggleGroup(group.parent)}\n aria-expanded={!collapsed}\n className=\"flex items-center gap-2 rounded-md px-2 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground transition-colors hover:bg-accent/40\"\n >\n {surfaceIcons?.[group.parent] != null && (\n <span className=\"flex h-4 w-4 items-center justify-center text-current\">\n {surfaceIcons[group.parent]}\n </span>\n )}\n <span className=\"flex-1 text-left\">{group.label}</span>\n <span aria-hidden className=\"text-[0.65rem] opacity-60\">\n {collapsed ? \"▸\" : \"▾\"}\n </span>\n </button>\n {!collapsed && (\n <div className=\"ml-2 mt-1 flex flex-col gap-1 border-l border-border/60 pl-2\">\n {group.surfaces.map((surface) =>\n renderLink({\n key: surface.key,\n to:\n listHrefBySurface[surface.key] ??\n withBasePath(basePath, `/${surface.key}`),\n className: navLinkClassName(\n isSurfaceRouteActive(resolvedRoute, surface.key),\n ),\n children: surface.title,\n }),\n )}\n </div>\n )}\n </div>\n );\n })}\n {showApiExplorer &&\n renderLink({\n key: explorerDefinition.key,\n to: withBasePath(basePath, \"/explorer\"),\n className: navLinkClassName(\n resolvedRoute.kind === \"explorer\" || resolvedRoute.kind === \"command\",\n ),\n children: explorerDefinition.title,\n })}\n </nav>\n <div className=\"mt-auto pt-4\">\n <ThemeSwitcher />\n </div>\n </aside>\n\n <main className=\"flex-1 overflow-auto p-6\">\n {resolvedRoute.kind === \"surface\" ? (\n resolvedRoute.surface ? (\n <OperationCatalog\n definition={makeSurfaceDefinition(resolvedRoute.surface)}\n entities={[resolvedRoute.surface.entity]}\n client={client}\n renderLink={renderLink}\n surfaceKey={resolvedRoute.surface.key}\n commandRuntime={commandRuntime}\n />\n ) : (\n <UnknownSurface surfaceKey={resolvedRoute.surfaceKey} />\n )\n ) : resolvedRoute.kind === \"entity\" ? (\n resolvedRoute.surface ? (\n <OperationEntityPage\n definition={makeSurfaceDefinition(resolvedRoute.surface)}\n entities={[resolvedRoute.surface.entity]}\n client={client}\n renderLink={renderLink}\n surfaceKey={resolvedRoute.surface.key}\n backHref={withBasePath(basePath, `/${resolvedRoute.surface.key}`)}\n backLabel={`Back to ${resolvedRoute.surface.title}`}\n commandRuntime={commandRuntime}\n {...(resolvedRoute.id ? { id: resolvedRoute.id } : {})}\n />\n ) : (\n <UnknownSurface surfaceKey={resolvedRoute.surfaceKey} />\n )\n ) : resolvedRoute.kind === \"command\" ? (\n <OperationCommandPage\n client={client}\n backHref={withBasePath(basePath, \"/explorer\")}\n backLabel=\"Back to API Explorer\"\n renderLink={renderLink}\n commandRuntime={commandRuntime}\n initialValues={commandInitialValues}\n autoRun={commandAutoRun}\n {...(resolvedRoute.operationId ? { operationId: resolvedRoute.operationId } : {})}\n />\n ) : resolvedRoute.kind === \"explorer\" ? (\n <OperationCatalog\n definition={explorerDefinition}\n entities={[]}\n allOperations\n client={client}\n renderLink={renderLink}\n commandRuntime={commandRuntime}\n />\n ) : defaultSurface == null ? (\n <div className=\"text-sm text-muted-foreground\">Loading surfaces…</div>\n ) : (\n <div className=\"text-sm text-muted-foreground\">Redirecting…</div>\n )}\n </main>\n </div>\n );\n}\n\ntype ExplorerRoute =\n | { kind: \"root\" }\n | { kind: \"explorer\" }\n | { kind: \"command\"; operationId?: string }\n | { kind: \"surface\"; surfaceKey: string; surface?: ClickySurface }\n | {\n kind: \"entity\";\n surfaceKey: string;\n surface?: ClickySurface;\n id?: string;\n };\n\nfunction parseExplorerRoute(pathname: string): ExplorerRoute {\n const normalized = trimTrailingSlash(pathname) || \"/\";\n if (normalized === \"/\") {\n return { kind: \"root\" };\n }\n\n const segments = normalized.replace(/^\\/+/, \"\").split(\"/\");\n if (segments[0] === \"explorer\") {\n return { kind: \"explorer\" };\n }\n if (segments[0] === \"commands\") {\n return segments[1] ? { kind: \"command\", operationId: segments[1] } : { kind: \"command\" };\n }\n const surfaceKey = segments[0] ?? \"\";\n if (segments[1]) {\n return {\n kind: \"entity\",\n surfaceKey,\n id: decodeURIComponent(segments[1]),\n };\n }\n return { kind: \"surface\", surfaceKey };\n}\n\nfunction resolveRouteSurface(route: ExplorerRoute, surfaces: ClickySurface[]): ExplorerRoute {\n if (route.kind !== \"surface\" && route.kind !== \"entity\") {\n return route;\n }\n const surface = surfaces.find((item) => item.key === route.surfaceKey);\n return surface ? { ...route, surface } : route;\n}\n\nfunction isSurfaceRouteActive(route: ExplorerRoute, surfaceKey: string) {\n return (\n (route.kind === \"surface\" && route.surfaceKey === surfaceKey) ||\n (route.kind === \"entity\" && route.surfaceKey === surfaceKey)\n );\n}\n\nfunction navLinkClassName(active: boolean) {\n return [\n \"rounded-md px-2 py-1.5 text-sm transition-colors\",\n active ? \"bg-accent text-accent-foreground\" : \"text-foreground hover:bg-accent\",\n ].join(\" \");\n}\n\nfunction stripBasePath(pathname: string, basePath: string) {\n const base = trimTrailingSlash(basePath);\n if (!base || base === \"/\") {\n return trimTrailingSlash(pathname) || \"/\";\n }\n if (pathname === base) {\n return \"/\";\n }\n if (pathname.startsWith(`${base}/`)) {\n return trimTrailingSlash(pathname.slice(base.length)) || \"/\";\n }\n return trimTrailingSlash(pathname) || \"/\";\n}\n\nfunction withBasePath(basePath: string, pathname: string) {\n const base = trimTrailingSlash(basePath);\n if (!base || base === \"/\") {\n return pathname;\n }\n return `${base}${pathname}`;\n}\n\nfunction trimTrailingSlash(value: string) {\n if (!value) return \"\";\n return value.length > 1 ? value.replace(/\\/+$/, \"\") : value;\n}\n\nfunction UnknownSurface({ surfaceKey }: { surfaceKey: string }) {\n return (\n <div className=\"p-6 text-sm text-muted-foreground\">\n Unknown surface: <code>{surfaceKey}</code>\n </div>\n );\n}\n\nconst AUTORUN_QUERY_PARAM = \"__autoRun\";\nconst ARG_QUERY_PREFIX = \"__arg\";\n\nfunction buildCommandHref(basePath: string, resolved: ClickyResolvedCommand): string | undefined {\n const commandId = resolved.operation?.operation.operationId ?? resolved.request.command;\n if (!commandId) return undefined;\n\n const meta = resolved.operation?.operation[\"x-clicky\"];\n const args = resolved.request.args ?? [];\n const flags = resolved.request.flags ?? {};\n\n // Entity `get` commands route to the surface detail URL: /<surface>/<id>?<flags>\n if (meta?.verb === \"get\" && meta?.scope === \"entity\" && meta.surface && args[0]) {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(flags)) {\n if (value !== undefined && value !== \"\") {\n search.set(key, value);\n }\n }\n const query = search.toString();\n const suffix = query ? `?${query}` : \"\";\n return withBasePath(\n basePath,\n `/${encodeURIComponent(meta.surface)}/${encodeURIComponent(args[0])}${suffix}`,\n );\n }\n\n const search = new URLSearchParams();\n args.forEach((value, index) => {\n if (value !== undefined && value !== \"\") {\n search.set(`${ARG_QUERY_PREFIX}${index}`, value);\n }\n });\n for (const [key, value] of Object.entries(flags)) {\n if (value !== undefined && value !== \"\") {\n search.set(key, value);\n }\n }\n if (resolved.request.autoRun) {\n search.set(AUTORUN_QUERY_PARAM, \"1\");\n }\n\n const query = search.toString();\n const suffix = query ? `?${query}` : \"\";\n return withBasePath(basePath, `/commands/${encodeURIComponent(commandId)}${suffix}`);\n}\n\ntype SurfaceGroup = {\n parent: string; // the slug; \"\" for surfaces that declared no parent\n label: string; // display name in the sidebar\n surfaces: ClickySurface[];\n};\n\n// groupSurfacesByParent buckets surfaces by their ClickySurface.parent slug,\n// preserving the order surfaces appeared in the spec. Surfaces with no parent\n// fall into a trailing \"\" bucket labelled \"Other\".\nfunction groupSurfacesByParent(surfaces: ClickySurface[]): SurfaceGroup[] {\n const order: string[] = [];\n const buckets = new Map<string, ClickySurface[]>();\n for (const surface of surfaces) {\n const parent = surface.parent ?? \"\";\n if (!buckets.has(parent)) {\n buckets.set(parent, []);\n order.push(parent);\n }\n buckets.get(parent)!.push(surface);\n }\n return order.map((parent) => ({\n parent,\n label: parent === \"\" ? \"Other\" : titleCase(parent),\n surfaces: buckets.get(parent)!,\n }));\n}\n\nfunction titleCase(value: string): string {\n if (!value) return value;\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nfunction readCollapsedGroups(): Record<string, boolean> {\n if (typeof window === \"undefined\") return {};\n try {\n const raw = window.localStorage.getItem(SURFACE_GROUP_STATE_KEY);\n if (!raw) return {};\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? (parsed as Record<string, boolean>) : {};\n } catch {\n return {};\n }\n}\n\nfunction writeCollapsedGroups(state: Record<string, boolean>) {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(SURFACE_GROUP_STATE_KEY, JSON.stringify(state));\n } catch {\n // Quota / private-mode failures are safe to swallow — sidebar state is\n // purely a UX nicety, not a correctness signal.\n }\n}\n\nfunction readCommandQueryParams(): { initialValues: Record<string, string>; autoRun: boolean } {\n if (typeof window === \"undefined\") {\n return { initialValues: {}, autoRun: false };\n }\n const search = new URLSearchParams(window.location.search);\n const initialValues: Record<string, string> = {};\n let autoRun = false;\n const positional: string[] = [];\n\n for (const [key, value] of search.entries()) {\n if (key === AUTORUN_QUERY_PARAM) {\n autoRun = value === \"1\" || value === \"true\";\n continue;\n }\n if (key.startsWith(ARG_QUERY_PREFIX)) {\n const index = Number.parseInt(key.slice(ARG_QUERY_PREFIX.length), 10);\n if (Number.isFinite(index) && index >= 0) {\n positional[index] = value;\n }\n continue;\n }\n initialValues[key] = value;\n }\n\n const packedArgs = positional.filter((value) => value !== undefined).join(\" \");\n if (packedArgs !== \"\") {\n initialValues.args = packedArgs;\n }\n\n return { initialValues, autoRun };\n}\n"],"names":["search","query","suffix"],"mappings":"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"}
1
+ {"version":3,"file":"EntityExplorerApp.js","sources":["../../src/rpc/EntityExplorerApp.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { ThemeSwitcher } from \"../components/theme-switcher\";\nimport type { ClickyCommandRuntime, ClickyResolvedCommand } from \"../data/Clicky\";\nimport {\n findSurfaceListOperation,\n getClickySurfaces,\n makeSurfaceDefinition,\n} from \"./clickyMetadata\";\nimport type { RenderLink } from \"./EndpointList\";\nimport { OperationCatalog } from \"./OperationCatalog\";\nimport { OperationCommandPage } from \"./OperationCommandPage\";\nimport { OperationEntityPage } from \"./OperationEntityPage\";\nimport type { ClickySurface } from \"./types\";\nimport type { OperationsApiClient } from \"./useOperations\";\nimport { useOperations } from \"./useOperations\";\n\nexport type EntityExplorerAppProps = {\n client: OperationsApiClient;\n pathname: string;\n renderLink: RenderLink;\n basePath?: string;\n showApiExplorer?: boolean;\n // surfaceIcons maps a ClickySurface.parent slug to a ReactNode rendered next\n // to the group label. Lets the host app drop in brand SVGs (e.g. Xero,\n // Takealot) without coupling clicky-ui to any specific iconography.\n surfaceIcons?: Record<string, ReactNode>;\n};\n\n// SURFACE_GROUP_STATE_KEY persists open/closed state of sidebar groups across\n// reloads. Single localStorage entry, not per-user — operator UI only.\nconst SURFACE_GROUP_STATE_KEY = \"clicky-ui:sidebar:groupCollapsed\";\n\nexport function EntityExplorerApp({\n client,\n pathname,\n renderLink,\n basePath = \"\",\n showApiExplorer = true,\n surfaceIcons,\n}: EntityExplorerAppProps) {\n const { operations, spec } = useOperations(client);\n const surfaces = useMemo(() => getClickySurfaces(spec), [spec]);\n const surfaceGroups = useMemo(() => groupSurfacesByParent(surfaces), [surfaces]);\n const listHrefBySurface = useMemo(() => {\n const out: Record<string, string> = {};\n for (const surface of surfaces) {\n const listOp = findSurfaceListOperation(operations, surface.key);\n if (!listOp?.operation.operationId) continue;\n const href = buildCommandHref(basePath, {\n operation: listOp,\n request: { command: listOp.operation.operationId, autoRun: true },\n });\n if (href) out[surface.key] = href;\n }\n return out;\n }, [basePath, operations, surfaces]);\n const [collapsedGroups, setCollapsedGroups] = useState<Record<string, boolean>>(() =>\n readCollapsedGroups(),\n );\n const toggleGroup = useCallback((parent: string) => {\n setCollapsedGroups((prev) => {\n const next = { ...prev, [parent]: !prev[parent] };\n writeCollapsedGroups(next);\n return next;\n });\n }, []);\n const defaultSurface = useMemo(\n () => surfaces.find((surface) => !surface.admin) ?? surfaces[0],\n [surfaces],\n );\n const relativePath = useMemo(() => stripBasePath(pathname, basePath), [basePath, pathname]);\n const route = useMemo(() => parseExplorerRoute(relativePath), [relativePath]);\n const resolvedRoute = useMemo(() => resolveRouteSurface(route, surfaces), [route, surfaces]);\n const commandRuntime = useMemo<ClickyCommandRuntime>(\n () => ({\n client,\n hrefForCommand: (resolved) => buildCommandHref(basePath, resolved),\n onNavigate: (resolved) => {\n const href = buildCommandHref(basePath, resolved);\n if (!href || typeof window === \"undefined\") return;\n window.history.pushState(window.history.state, \"\", href);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n },\n }),\n [basePath, client],\n );\n const { initialValues: commandInitialValues, autoRun: commandAutoRun } = useMemo(\n () =>\n resolvedRoute.kind === \"command\"\n ? readCommandQueryParams()\n : { initialValues: {}, autoRun: false },\n [resolvedRoute.kind, pathname],\n );\n const explorerDefinition = useMemo(\n () => ({\n key: \"explorer\",\n title: \"API Explorer\",\n description: \"Every operation exposed by the current OpenAPI spec.\",\n }),\n [],\n );\n\n useEffect(() => {\n if (\n typeof window === \"undefined\" ||\n defaultSurface == null ||\n relativePath !== \"/\" ||\n window.location.pathname !== withBasePath(basePath, \"/\")\n ) {\n return;\n }\n\n const target = withBasePath(basePath, `/${defaultSurface.key}`);\n window.history.replaceState(window.history.state, \"\", target);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }, [basePath, defaultSurface, relativePath]);\n\n return (\n <div className=\"flex h-full\">\n <aside className=\"flex w-64 shrink-0 flex-col border-r border-border bg-muted/30 p-4\">\n <div className=\"mb-6\">\n <div className=\"text-sm font-semibold\">{spec?.info.title ?? \"Clicky Explorer\"}</div>\n <div className=\"text-xs text-muted-foreground\">Metadata-driven entity explorer</div>\n </div>\n <nav className=\"flex flex-col gap-2\">\n {surfaceGroups.map((group) => {\n const collapsed = collapsedGroups[group.parent] ?? false;\n return (\n <div key={group.parent} className=\"flex flex-col\">\n <button\n type=\"button\"\n onClick={() => toggleGroup(group.parent)}\n aria-expanded={!collapsed}\n className=\"flex items-center gap-2 rounded-md px-2 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground transition-colors hover:bg-accent/40\"\n >\n {surfaceIcons?.[group.parent] != null && (\n <span className=\"flex h-4 w-4 items-center justify-center text-current\">\n {surfaceIcons[group.parent]}\n </span>\n )}\n <span className=\"flex-1 text-left\">{group.label}</span>\n <span aria-hidden className=\"text-[0.65rem] opacity-60\">\n {collapsed ? \"▸\" : \"▾\"}\n </span>\n </button>\n {!collapsed && (\n <div className=\"ml-2 mt-1 flex flex-col gap-1 border-l border-border/60 pl-2\">\n {group.surfaces.map((surface) =>\n renderLink({\n key: surface.key,\n to:\n listHrefBySurface[surface.key] ??\n withBasePath(basePath, `/${surface.key}`),\n className: navLinkClassName(\n isSurfaceRouteActive(resolvedRoute, surface.key),\n ),\n children: surface.title,\n }),\n )}\n </div>\n )}\n </div>\n );\n })}\n {showApiExplorer &&\n renderLink({\n key: explorerDefinition.key,\n to: withBasePath(basePath, \"/explorer\"),\n className: navLinkClassName(\n resolvedRoute.kind === \"explorer\" || resolvedRoute.kind === \"command\",\n ),\n children: explorerDefinition.title,\n })}\n </nav>\n <div className=\"mt-auto pt-4\">\n <ThemeSwitcher />\n </div>\n </aside>\n\n <main className=\"flex-1 overflow-auto p-6\">\n {resolvedRoute.kind === \"surface\" ? (\n resolvedRoute.surface ? (\n <OperationCatalog\n definition={makeSurfaceDefinition(resolvedRoute.surface)}\n entities={[resolvedRoute.surface.entity]}\n client={client}\n renderLink={renderLink}\n surfaceKey={resolvedRoute.surface.key}\n commandRuntime={commandRuntime}\n />\n ) : (\n <UnknownSurface surfaceKey={resolvedRoute.surfaceKey} />\n )\n ) : resolvedRoute.kind === \"entity\" ? (\n resolvedRoute.surface ? (\n <OperationEntityPage\n definition={makeSurfaceDefinition(resolvedRoute.surface)}\n entities={[resolvedRoute.surface.entity]}\n client={client}\n renderLink={renderLink}\n surfaceKey={resolvedRoute.surface.key}\n backHref={withBasePath(basePath, `/${resolvedRoute.surface.key}`)}\n backLabel={`Back to ${resolvedRoute.surface.title}`}\n commandRuntime={commandRuntime}\n {...(resolvedRoute.id ? { id: resolvedRoute.id } : {})}\n />\n ) : (\n <UnknownSurface surfaceKey={resolvedRoute.surfaceKey} />\n )\n ) : resolvedRoute.kind === \"command\" ? (\n <OperationCommandPage\n client={client}\n backHref={withBasePath(basePath, \"/explorer\")}\n backLabel=\"Back to API Explorer\"\n renderLink={renderLink}\n commandRuntime={commandRuntime}\n initialValues={commandInitialValues}\n autoRun={commandAutoRun}\n {...(resolvedRoute.operationId ? { operationId: resolvedRoute.operationId } : {})}\n />\n ) : resolvedRoute.kind === \"explorer\" ? (\n <OperationCatalog\n definition={explorerDefinition}\n entities={[]}\n allOperations\n client={client}\n renderLink={renderLink}\n commandRuntime={commandRuntime}\n />\n ) : defaultSurface == null ? (\n <div className=\"text-sm text-muted-foreground\">Loading surfaces…</div>\n ) : (\n <div className=\"text-sm text-muted-foreground\">Redirecting…</div>\n )}\n </main>\n </div>\n );\n}\n\ntype ExplorerRoute =\n | { kind: \"root\" }\n | { kind: \"explorer\" }\n | { kind: \"command\"; operationId?: string }\n | { kind: \"surface\"; surfaceKey: string; surface?: ClickySurface }\n | {\n kind: \"entity\";\n surfaceKey: string;\n surface?: ClickySurface;\n id?: string;\n };\n\nfunction parseExplorerRoute(pathname: string): ExplorerRoute {\n const normalized = trimTrailingSlash(pathname) || \"/\";\n if (normalized === \"/\") {\n return { kind: \"root\" };\n }\n\n const segments = normalized.replace(/^\\/+/, \"\").split(\"/\");\n if (segments[0] === \"explorer\") {\n return { kind: \"explorer\" };\n }\n if (segments[0] === \"commands\") {\n return segments[1] ? { kind: \"command\", operationId: segments[1] } : { kind: \"command\" };\n }\n const surfaceKey = segments[0] ?? \"\";\n if (segments[1]) {\n return {\n kind: \"entity\",\n surfaceKey,\n id: decodeURIComponent(segments[1]),\n };\n }\n return { kind: \"surface\", surfaceKey };\n}\n\nfunction resolveRouteSurface(route: ExplorerRoute, surfaces: ClickySurface[]): ExplorerRoute {\n if (route.kind !== \"surface\" && route.kind !== \"entity\") {\n return route;\n }\n const surface = surfaces.find((item) => item.key === route.surfaceKey);\n return surface ? { ...route, surface } : route;\n}\n\nfunction isSurfaceRouteActive(route: ExplorerRoute, surfaceKey: string) {\n return (\n (route.kind === \"surface\" && route.surfaceKey === surfaceKey) ||\n (route.kind === \"entity\" && route.surfaceKey === surfaceKey)\n );\n}\n\nfunction navLinkClassName(active: boolean) {\n return [\n \"rounded-md px-2 py-1.5 text-sm transition-colors\",\n active ? \"bg-accent text-accent-foreground\" : \"text-foreground hover:bg-accent\",\n ].join(\" \");\n}\n\nfunction stripBasePath(pathname: string, basePath: string) {\n const base = trimTrailingSlash(basePath);\n if (!base || base === \"/\") {\n return trimTrailingSlash(pathname) || \"/\";\n }\n if (pathname === base) {\n return \"/\";\n }\n if (pathname.startsWith(`${base}/`)) {\n return trimTrailingSlash(pathname.slice(base.length)) || \"/\";\n }\n return trimTrailingSlash(pathname) || \"/\";\n}\n\nfunction withBasePath(basePath: string, pathname: string) {\n const base = trimTrailingSlash(basePath);\n if (!base || base === \"/\") {\n return pathname;\n }\n return `${base}${pathname}`;\n}\n\nfunction trimTrailingSlash(value: string) {\n if (!value) return \"\";\n return value.length > 1 ? value.replace(/\\/+$/, \"\") : value;\n}\n\nfunction UnknownSurface({ surfaceKey }: { surfaceKey: string }) {\n return (\n <div className=\"p-6 text-sm text-muted-foreground\">\n Unknown surface: <code>{surfaceKey}</code>\n </div>\n );\n}\n\nconst AUTORUN_QUERY_PARAM = \"autoRun\";\nconst LEGACY_AUTORUN_QUERY_PARAM = \"__autoRun\";\nconst ARG_QUERY_PREFIX = \"__arg\";\n\nfunction buildCommandHref(basePath: string, resolved: ClickyResolvedCommand): string | undefined {\n const commandId = resolved.operation?.operation.operationId ?? resolved.request.command;\n if (!commandId) return undefined;\n\n const meta = resolved.operation?.operation[\"x-clicky\"];\n const args = resolved.request.args ?? [];\n const flags = resolved.request.flags ?? {};\n\n // Entity `get` commands route to the surface detail URL: /<surface>/<id>?<flags>\n if (meta?.verb === \"get\" && meta?.scope === \"entity\" && meta.surface && args[0]) {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(flags)) {\n if (value !== undefined && value !== \"\") {\n search.set(key, value);\n }\n }\n const query = search.toString();\n const suffix = query ? `?${query}` : \"\";\n return withBasePath(\n basePath,\n `/${encodeURIComponent(meta.surface)}/${encodeURIComponent(args[0])}${suffix}`,\n );\n }\n\n const search = new URLSearchParams();\n args.forEach((value, index) => {\n if (value !== undefined && value !== \"\") {\n search.set(`${ARG_QUERY_PREFIX}${index}`, value);\n }\n });\n for (const [key, value] of Object.entries(flags)) {\n if (value !== undefined && value !== \"\") {\n search.set(key, value);\n }\n }\n if (resolved.request.autoRun) {\n search.set(AUTORUN_QUERY_PARAM, \"1\");\n }\n\n const query = search.toString();\n const suffix = query ? `?${query}` : \"\";\n return withBasePath(basePath, `/commands/${encodeURIComponent(commandId)}${suffix}`);\n}\n\ntype SurfaceGroup = {\n parent: string; // the slug; \"\" for surfaces that declared no parent\n label: string; // display name in the sidebar\n surfaces: ClickySurface[];\n};\n\n// groupSurfacesByParent buckets surfaces by their ClickySurface.parent slug,\n// preserving the order surfaces appeared in the spec. Surfaces with no parent\n// fall into a trailing \"\" bucket labelled \"Other\".\nfunction groupSurfacesByParent(surfaces: ClickySurface[]): SurfaceGroup[] {\n const order: string[] = [];\n const buckets = new Map<string, ClickySurface[]>();\n for (const surface of surfaces) {\n const parent = surface.parent ?? \"\";\n if (!buckets.has(parent)) {\n buckets.set(parent, []);\n order.push(parent);\n }\n buckets.get(parent)!.push(surface);\n }\n return order.map((parent) => ({\n parent,\n label: parent === \"\" ? \"Other\" : titleCase(parent),\n surfaces: buckets.get(parent)!,\n }));\n}\n\nfunction titleCase(value: string): string {\n if (!value) return value;\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nfunction readCollapsedGroups(): Record<string, boolean> {\n if (typeof window === \"undefined\") return {};\n try {\n const raw = window.localStorage.getItem(SURFACE_GROUP_STATE_KEY);\n if (!raw) return {};\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? (parsed as Record<string, boolean>) : {};\n } catch {\n return {};\n }\n}\n\nfunction writeCollapsedGroups(state: Record<string, boolean>) {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(SURFACE_GROUP_STATE_KEY, JSON.stringify(state));\n } catch {\n // Quota / private-mode failures are safe to swallow — sidebar state is\n // purely a UX nicety, not a correctness signal.\n }\n}\n\nfunction readCommandQueryParams(): { initialValues: Record<string, string>; autoRun: boolean } {\n if (typeof window === \"undefined\") {\n return { initialValues: {}, autoRun: false };\n }\n const search = new URLSearchParams(window.location.search);\n const initialValues: Record<string, string> = {};\n let autoRun = false;\n const positional: string[] = [];\n\n for (const [key, value] of search.entries()) {\n if (key === AUTORUN_QUERY_PARAM || key === LEGACY_AUTORUN_QUERY_PARAM) {\n autoRun = value === \"1\" || value === \"true\";\n continue;\n }\n if (key.startsWith(ARG_QUERY_PREFIX)) {\n const index = Number.parseInt(key.slice(ARG_QUERY_PREFIX.length), 10);\n if (Number.isFinite(index) && index >= 0) {\n positional[index] = value;\n }\n continue;\n }\n initialValues[key] = value;\n }\n\n const packedArgs = positional.filter((value) => value !== undefined).join(\" \");\n if (packedArgs !== \"\") {\n initialValues.args = packedArgs;\n }\n\n return { initialValues, autoRun };\n}\n"],"names":["search","query","suffix"],"mappings":";;;;;;;;AA8BA,MAAM,0BAA0B;AAEzB,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,kBAAkB;AAAA,EAClB;AACF,GAA2B;AACzB,QAAM,EAAE,YAAY,SAAS,cAAc,MAAM;AACjD,QAAM,WAAW,QAAQ,MAAM,kBAAkB,IAAI,GAAG,CAAC,IAAI,CAAC;AAC9D,QAAM,gBAAgB,QAAQ,MAAM,sBAAsB,QAAQ,GAAG,CAAC,QAAQ,CAAC;AAC/E,QAAM,oBAAoB,QAAQ,MAAM;AACtC,UAAM,MAA8B,CAAA;AACpC,eAAW,WAAW,UAAU;AAC9B,YAAM,SAAS,yBAAyB,YAAY,QAAQ,GAAG;AAC/D,UAAI,EAAC,iCAAQ,UAAU,aAAa;AACpC,YAAM,OAAO,iBAAiB,UAAU;AAAA,QACtC,WAAW;AAAA,QACX,SAAS,EAAE,SAAS,OAAO,UAAU,aAAa,SAAS,KAAA;AAAA,MAAK,CACjE;AACD,UAAI,KAAM,KAAI,QAAQ,GAAG,IAAI;AAAA,IAC/B;AACA,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,YAAY,QAAQ,CAAC;AACnC,QAAM,CAAC,iBAAiB,kBAAkB,IAAI;AAAA,IAAkC,MAC9E,oBAAA;AAAA,EAAoB;AAEtB,QAAM,cAAc,YAAY,CAAC,WAAmB;AAClD,uBAAmB,CAAC,SAAS;AAC3B,YAAM,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,KAAK,MAAM,EAAA;AAC9C,2BAAqB,IAAI;AACzB,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAA,CAAE;AACL,QAAM,iBAAiB;AAAA,IACrB,MAAM,SAAS,KAAK,CAAC,YAAY,CAAC,QAAQ,KAAK,KAAK,SAAS,CAAC;AAAA,IAC9D,CAAC,QAAQ;AAAA,EAAA;AAEX,QAAM,eAAe,QAAQ,MAAM,cAAc,UAAU,QAAQ,GAAG,CAAC,UAAU,QAAQ,CAAC;AAC1F,QAAM,QAAQ,QAAQ,MAAM,mBAAmB,YAAY,GAAG,CAAC,YAAY,CAAC;AAC5E,QAAM,gBAAgB,QAAQ,MAAM,oBAAoB,OAAO,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC;AAC3F,QAAM,iBAAiB;AAAA,IACrB,OAAO;AAAA,MACL;AAAA,MACA,gBAAgB,CAAC,aAAa,iBAAiB,UAAU,QAAQ;AAAA,MACjE,YAAY,CAAC,aAAa;AACxB,cAAM,OAAO,iBAAiB,UAAU,QAAQ;AAChD,YAAI,CAAC,QAAQ,OAAO,WAAW,YAAa;AAC5C,eAAO,QAAQ,UAAU,OAAO,QAAQ,OAAO,IAAI,IAAI;AACvD,eAAO,cAAc,IAAI,cAAc,UAAU,CAAC;AAAA,MACpD;AAAA,IAAA;AAAA,IAEF,CAAC,UAAU,MAAM;AAAA,EAAA;AAEnB,QAAM,EAAE,eAAe,sBAAsB,SAAS,mBAAmB;AAAA,IACvE,MACE,cAAc,SAAS,YACnB,uBAAA,IACA,EAAE,eAAe,CAAA,GAAI,SAAS,MAAA;AAAA,IACpC,CAAC,cAAc,MAAM,QAAQ;AAAA,EAAA;AAE/B,QAAM,qBAAqB;AAAA,IACzB,OAAO;AAAA,MACL,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,IAAA;AAAA,IAEf,CAAA;AAAA,EAAC;AAGH,YAAU,MAAM;AACd,QACE,OAAO,WAAW,eAClB,kBAAkB,QAClB,iBAAiB,OACjB,OAAO,SAAS,aAAa,aAAa,UAAU,GAAG,GACvD;AACA;AAAA,IACF;AAEA,UAAM,SAAS,aAAa,UAAU,IAAI,eAAe,GAAG,EAAE;AAC9D,WAAO,QAAQ,aAAa,OAAO,QAAQ,OAAO,IAAI,MAAM;AAC5D,WAAO,cAAc,IAAI,cAAc,UAAU,CAAC;AAAA,EACpD,GAAG,CAAC,UAAU,gBAAgB,YAAY,CAAC;AAE3C,SACE,qBAAC,OAAA,EAAI,WAAU,eACb,UAAA;AAAA,IAAA,qBAAC,SAAA,EAAM,WAAU,sEACf,UAAA;AAAA,MAAA,qBAAC,OAAA,EAAI,WAAU,QACb,UAAA;AAAA,QAAA,oBAAC,SAAI,WAAU,yBAAyB,WAAA,6BAAM,KAAK,UAAS,mBAAkB;AAAA,QAC9E,oBAAC,OAAA,EAAI,WAAU,iCAAgC,UAAA,kCAAA,CAA+B;AAAA,MAAA,GAChF;AAAA,MACA,qBAAC,OAAA,EAAI,WAAU,uBACZ,UAAA;AAAA,QAAA,cAAc,IAAI,CAAC,UAAU;AAC5B,gBAAM,YAAY,gBAAgB,MAAM,MAAM,KAAK;AACnD,iBACE,qBAAC,OAAA,EAAuB,WAAU,iBAChC,UAAA;AAAA,YAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM,YAAY,MAAM,MAAM;AAAA,gBACvC,iBAAe,CAAC;AAAA,gBAChB,WAAU;AAAA,gBAET,UAAA;AAAA,mBAAA,6CAAe,MAAM,YAAW,QAC/B,oBAAC,QAAA,EAAK,WAAU,yDACb,UAAA,aAAa,MAAM,MAAM,EAAA,CAC5B;AAAA,kBAEF,oBAAC,QAAA,EAAK,WAAU,oBAAoB,gBAAM,OAAM;AAAA,kBAChD,oBAAC,UAAK,eAAW,MAAC,WAAU,6BACzB,UAAA,YAAY,MAAM,IAAA,CACrB;AAAA,gBAAA;AAAA,cAAA;AAAA,YAAA;AAAA,YAED,CAAC,aACA,oBAAC,SAAI,WAAU,gEACZ,gBAAM,SAAS;AAAA,cAAI,CAAC,YACnB,WAAW;AAAA,gBACT,KAAK,QAAQ;AAAA,gBACb,IACE,kBAAkB,QAAQ,GAAG,KAC7B,aAAa,UAAU,IAAI,QAAQ,GAAG,EAAE;AAAA,gBAC1C,WAAW;AAAA,kBACT,qBAAqB,eAAe,QAAQ,GAAG;AAAA,gBAAA;AAAA,gBAEjD,UAAU,QAAQ;AAAA,cAAA,CACnB;AAAA,YAAA,EACH,CACF;AAAA,UAAA,EAAA,GA/BM,MAAM,MAiChB;AAAA,QAEJ,CAAC;AAAA,QACA,mBACC,WAAW;AAAA,UACT,KAAK,mBAAmB;AAAA,UACxB,IAAI,aAAa,UAAU,WAAW;AAAA,UACtC,WAAW;AAAA,YACT,cAAc,SAAS,cAAc,cAAc,SAAS;AAAA,UAAA;AAAA,UAE9D,UAAU,mBAAmB;AAAA,QAAA,CAC9B;AAAA,MAAA,GACL;AAAA,0BACC,OAAA,EAAI,WAAU,gBACb,UAAA,oBAAC,iBAAc,EAAA,CACjB;AAAA,IAAA,GACF;AAAA,IAEA,oBAAC,UAAK,WAAU,4BACb,wBAAc,SAAS,YACtB,cAAc,UACZ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,YAAY,sBAAsB,cAAc,OAAO;AAAA,QACvD,UAAU,CAAC,cAAc,QAAQ,MAAM;AAAA,QACvC;AAAA,QACA;AAAA,QACA,YAAY,cAAc,QAAQ;AAAA,QAClC;AAAA,MAAA;AAAA,IAAA,IAGF,oBAAC,gBAAA,EAAe,YAAY,cAAc,WAAA,CAAY,IAEtD,cAAc,SAAS,WACzB,cAAc,UACZ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,YAAY,sBAAsB,cAAc,OAAO;AAAA,QACvD,UAAU,CAAC,cAAc,QAAQ,MAAM;AAAA,QACvC;AAAA,QACA;AAAA,QACA,YAAY,cAAc,QAAQ;AAAA,QAClC,UAAU,aAAa,UAAU,IAAI,cAAc,QAAQ,GAAG,EAAE;AAAA,QAChE,WAAW,WAAW,cAAc,QAAQ,KAAK;AAAA,QACjD;AAAA,QACC,GAAI,cAAc,KAAK,EAAE,IAAI,cAAc,GAAA,IAAO,CAAA;AAAA,MAAC;AAAA,IAAA,wBAGrD,gBAAA,EAAe,YAAY,cAAc,WAAA,CAAY,IAEtD,cAAc,SAAS,YACzB;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,UAAU,aAAa,UAAU,WAAW;AAAA,QAC5C,WAAU;AAAA,QACV;AAAA,QACA;AAAA,QACA,eAAe;AAAA,QACf,SAAS;AAAA,QACR,GAAI,cAAc,cAAc,EAAE,aAAa,cAAc,YAAA,IAAgB,CAAA;AAAA,MAAC;AAAA,IAAA,IAE/E,cAAc,SAAS,aACzB;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,YAAY;AAAA,QACZ,UAAU,CAAA;AAAA,QACV,eAAa;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,IAAA,IAEA,kBAAkB,OACpB,oBAAC,SAAI,WAAU,iCAAgC,UAAA,oBAAA,CAAiB,IAEhE,oBAAC,OAAA,EAAI,WAAU,iCAAgC,0BAAY,EAAA,CAE/D;AAAA,EAAA,GACF;AAEJ;AAcA,SAAS,mBAAmB,UAAiC;AAC3D,QAAM,aAAa,kBAAkB,QAAQ,KAAK;AAClD,MAAI,eAAe,KAAK;AACtB,WAAO,EAAE,MAAM,OAAA;AAAA,EACjB;AAEA,QAAM,WAAW,WAAW,QAAQ,QAAQ,EAAE,EAAE,MAAM,GAAG;AACzD,MAAI,SAAS,CAAC,MAAM,YAAY;AAC9B,WAAO,EAAE,MAAM,WAAA;AAAA,EACjB;AACA,MAAI,SAAS,CAAC,MAAM,YAAY;AAC9B,WAAO,SAAS,CAAC,IAAI,EAAE,MAAM,WAAW,aAAa,SAAS,CAAC,EAAA,IAAM,EAAE,MAAM,UAAA;AAAA,EAC/E;AACA,QAAM,aAAa,SAAS,CAAC,KAAK;AAClC,MAAI,SAAS,CAAC,GAAG;AACf,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,IAAI,mBAAmB,SAAS,CAAC,CAAC;AAAA,IAAA;AAAA,EAEtC;AACA,SAAO,EAAE,MAAM,WAAW,WAAA;AAC5B;AAEA,SAAS,oBAAoB,OAAsB,UAA0C;AAC3F,MAAI,MAAM,SAAS,aAAa,MAAM,SAAS,UAAU;AACvD,WAAO;AAAA,EACT;AACA,QAAM,UAAU,SAAS,KAAK,CAAC,SAAS,KAAK,QAAQ,MAAM,UAAU;AACrE,SAAO,UAAU,EAAE,GAAG,OAAO,YAAY;AAC3C;AAEA,SAAS,qBAAqB,OAAsB,YAAoB;AACtE,SACG,MAAM,SAAS,aAAa,MAAM,eAAe,cACjD,MAAM,SAAS,YAAY,MAAM,eAAe;AAErD;AAEA,SAAS,iBAAiB,QAAiB;AACzC,SAAO;AAAA,IACL;AAAA,IACA,SAAS,qCAAqC;AAAA,EAAA,EAC9C,KAAK,GAAG;AACZ;AAEA,SAAS,cAAc,UAAkB,UAAkB;AACzD,QAAM,OAAO,kBAAkB,QAAQ;AACvC,MAAI,CAAC,QAAQ,SAAS,KAAK;AACzB,WAAO,kBAAkB,QAAQ,KAAK;AAAA,EACxC;AACA,MAAI,aAAa,MAAM;AACrB,WAAO;AAAA,EACT;AACA,MAAI,SAAS,WAAW,GAAG,IAAI,GAAG,GAAG;AACnC,WAAO,kBAAkB,SAAS,MAAM,KAAK,MAAM,CAAC,KAAK;AAAA,EAC3D;AACA,SAAO,kBAAkB,QAAQ,KAAK;AACxC;AAEA,SAAS,aAAa,UAAkB,UAAkB;AACxD,QAAM,OAAO,kBAAkB,QAAQ;AACvC,MAAI,CAAC,QAAQ,SAAS,KAAK;AACzB,WAAO;AAAA,EACT;AACA,SAAO,GAAG,IAAI,GAAG,QAAQ;AAC3B;AAEA,SAAS,kBAAkB,OAAe;AACxC,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,MAAM,SAAS,IAAI,MAAM,QAAQ,QAAQ,EAAE,IAAI;AACxD;AAEA,SAAS,eAAe,EAAE,cAAsC;AAC9D,SACE,qBAAC,OAAA,EAAI,WAAU,qCAAoC,UAAA;AAAA,IAAA;AAAA,IAChC,oBAAC,UAAM,UAAA,WAAA,CAAW;AAAA,EAAA,GACrC;AAEJ;AAEA,MAAM,sBAAsB;AAC5B,MAAM,6BAA6B;AACnC,MAAM,mBAAmB;AAEzB,SAAS,iBAAiB,UAAkB,UAAqD;;AAC/F,QAAM,cAAY,cAAS,cAAT,mBAAoB,UAAU,gBAAe,SAAS,QAAQ;AAChF,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,QAAO,cAAS,cAAT,mBAAoB,UAAU;AAC3C,QAAM,OAAO,SAAS,QAAQ,QAAQ,CAAA;AACtC,QAAM,QAAQ,SAAS,QAAQ,SAAS,CAAA;AAGxC,OAAI,6BAAM,UAAS,UAAS,6BAAM,WAAU,YAAY,KAAK,WAAW,KAAK,CAAC,GAAG;AAC/E,UAAMA,UAAS,IAAI,gBAAA;AACnB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,UAAI,UAAU,UAAa,UAAU,IAAI;AACvCA,gBAAO,IAAI,KAAK,KAAK;AAAA,MACvB;AAAA,IACF;AACA,UAAMC,SAAQD,QAAO,SAAA;AACrB,UAAME,UAASD,SAAQ,IAAIA,MAAK,KAAK;AACrC,WAAO;AAAA,MACL;AAAA,MACA,IAAI,mBAAmB,KAAK,OAAO,CAAC,IAAI,mBAAmB,KAAK,CAAC,CAAC,CAAC,GAAGC,OAAM;AAAA,IAAA;AAAA,EAEhF;AAEA,QAAM,SAAS,IAAI,gBAAA;AACnB,OAAK,QAAQ,CAAC,OAAO,UAAU;AAC7B,QAAI,UAAU,UAAa,UAAU,IAAI;AACvC,aAAO,IAAI,GAAG,gBAAgB,GAAG,KAAK,IAAI,KAAK;AAAA,IACjD;AAAA,EACF,CAAC;AACD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,UAAU,UAAa,UAAU,IAAI;AACvC,aAAO,IAAI,KAAK,KAAK;AAAA,IACvB;AAAA,EACF;AACA,MAAI,SAAS,QAAQ,SAAS;AAC5B,WAAO,IAAI,qBAAqB,GAAG;AAAA,EACrC;AAEA,QAAM,QAAQ,OAAO,SAAA;AACrB,QAAM,SAAS,QAAQ,IAAI,KAAK,KAAK;AACrC,SAAO,aAAa,UAAU,aAAa,mBAAmB,SAAS,CAAC,GAAG,MAAM,EAAE;AACrF;AAWA,SAAS,sBAAsB,UAA2C;AACxE,QAAM,QAAkB,CAAA;AACxB,QAAM,8BAAc,IAAA;AACpB,aAAW,WAAW,UAAU;AAC9B,UAAM,SAAS,QAAQ,UAAU;AACjC,QAAI,CAAC,QAAQ,IAAI,MAAM,GAAG;AACxB,cAAQ,IAAI,QAAQ,EAAE;AACtB,YAAM,KAAK,MAAM;AAAA,IACnB;AACA,YAAQ,IAAI,MAAM,EAAG,KAAK,OAAO;AAAA,EACnC;AACA,SAAO,MAAM,IAAI,CAAC,YAAY;AAAA,IAC5B;AAAA,IACA,OAAO,WAAW,KAAK,UAAU,UAAU,MAAM;AAAA,IACjD,UAAU,QAAQ,IAAI,MAAM;AAAA,EAAA,EAC5B;AACJ;AAEA,SAAS,UAAU,OAAuB;AACxC,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,MAAM,OAAO,CAAC,EAAE,gBAAgB,MAAM,MAAM,CAAC;AACtD;AAEA,SAAS,sBAA+C;AACtD,MAAI,OAAO,WAAW,YAAa,QAAO,CAAA;AAC1C,MAAI;AACF,UAAM,MAAM,OAAO,aAAa,QAAQ,uBAAuB;AAC/D,QAAI,CAAC,IAAK,QAAO,CAAA;AACjB,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAO,UAAU,OAAO,WAAW,WAAY,SAAqC,CAAA;AAAA,EACtF,QAAQ;AACN,WAAO,CAAA;AAAA,EACT;AACF;AAEA,SAAS,qBAAqB,OAAgC;AAC5D,MAAI,OAAO,WAAW,YAAa;AACnC,MAAI;AACF,WAAO,aAAa,QAAQ,yBAAyB,KAAK,UAAU,KAAK,CAAC;AAAA,EAC5E,QAAQ;AAAA,EAGR;AACF;AAEA,SAAS,yBAAsF;AAC7F,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,EAAE,eAAe,IAAI,SAAS,MAAA;AAAA,EACvC;AACA,QAAM,SAAS,IAAI,gBAAgB,OAAO,SAAS,MAAM;AACzD,QAAM,gBAAwC,CAAA;AAC9C,MAAI,UAAU;AACd,QAAM,aAAuB,CAAA;AAE7B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,WAAW;AAC3C,QAAI,QAAQ,uBAAuB,QAAQ,4BAA4B;AACrE,gBAAU,UAAU,OAAO,UAAU;AACrC;AAAA,IACF;AACA,QAAI,IAAI,WAAW,gBAAgB,GAAG;AACpC,YAAM,QAAQ,OAAO,SAAS,IAAI,MAAM,iBAAiB,MAAM,GAAG,EAAE;AACpE,UAAI,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG;AACxC,mBAAW,KAAK,IAAI;AAAA,MACtB;AACA;AAAA,IACF;AACA,kBAAc,GAAG,IAAI;AAAA,EACvB;AAEA,QAAM,aAAa,WAAW,OAAO,CAAC,UAAU,UAAU,MAAS,EAAE,KAAK,GAAG;AAC7E,MAAI,eAAe,IAAI;AACrB,kBAAc,OAAO;AAAA,EACvB;AAEA,SAAO,EAAE,eAAe,QAAA;AAC1B;"}
@@ -78,7 +78,7 @@ function hrefForOperationAction(path, params) {
78
78
  }
79
79
  const search = new URLSearchParams();
80
80
  for (const [key, value] of Object.entries(nextParams)) {
81
- if (value && key !== "autoRun") search.set(key, value);
81
+ if (value && key !== "autoRun" && key !== "__autoRun") search.set(key, value);
82
82
  }
83
83
  const query = search.toString();
84
84
  return query ? `${route}?${query}` : route;
@@ -1 +1 @@
1
- {"version":3,"file":"OperationActionDialog.cjs","sources":["../../src/rpc/OperationActionDialog.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { Button } from \"../components/button\";\nimport { Icon } from \"../data/Icon\";\nimport { UiPlay } from \"../icons\";\nimport { Modal } from \"../overlay/Modal\";\nimport { CommandForm } from \"./CommandForm\";\nimport { CommandOutput } from \"./CommandOutput\";\nimport { InlineError } from \"./InlineError\";\nimport type { ExecutionResponse, ResolvedOperation } from \"./types\";\nimport type { OperationsApiClient } from \"./useOperations\";\n\nexport type OperationActionDialogProps = {\n operation: ResolvedOperation;\n client: OperationsApiClient;\n initialValues: Record<string, string>;\n label: string;\n defaultAccept?: string;\n onNavigateAction?: (href: string) => void;\n};\n\nexport function OperationActionDialog({\n operation,\n client,\n initialValues,\n label,\n defaultAccept = \"application/clicky+json\",\n onNavigateAction,\n}: OperationActionDialogProps) {\n const [open, setOpen] = useState(false);\n const [isExecuting, setIsExecuting] = useState(false);\n const [response, setResponse] = useState<ExecutionResponse | null>(null);\n const [error, setError] = useState<unknown>(null);\n\n async function handleExecute(params: Record<string, string>, headers: Record<string, string>) {\n if (onNavigateAction) {\n const href = hrefForOperationAction(operation.path, params);\n if (!href) return;\n const separator = href.includes(\"?\") ? \"&\" : \"?\";\n onNavigateAction(`${href}${separator}autoRun=1`);\n return;\n }\n\n setIsExecuting(true);\n setError(null);\n setResponse(null);\n try {\n const result = await client.executeCommand(operation.path, operation.method, params, headers);\n setResponse(result);\n } catch (err) {\n setError(err);\n } finally {\n setIsExecuting(false);\n }\n }\n\n return (\n <>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => setOpen(true)}>\n <Icon icon={UiPlay} />\n {label}\n </Button>\n <Modal open={open} onClose={() => setOpen(false)} title={label} size=\"lg\">\n <div className=\"space-y-4\">\n <CommandForm\n parameters={operation.operation.parameters ?? []}\n onExecute={handleExecute}\n isPending={isExecuting}\n method={operation.method}\n path={operation.path}\n accept={defaultAccept}\n initialValues={initialValues}\n />\n\n {error ? (\n <InlineError title={`Failed to execute ${operation.path}`} error={error} />\n ) : response ? (\n <CommandOutput response={response} />\n ) : null}\n </div>\n </Modal>\n </>\n );\n}\n\nfunction hrefForOperationAction(path: string, params: Record<string, string>): string | undefined {\n const nextParams = { ...params };\n const args = parseArgsParam(params.args);\n let route = apiPathToRoutePath(path);\n\n for (const [index, name] of pathParamNames(path).entries()) {\n const value = nextParams[name] || args[index];\n if (!value) return undefined;\n route = route.replace(`:${name}`, encodeURIComponent(value));\n delete nextParams[name];\n if (!nextParams[name] && value === args[index]) {\n delete nextParams.args;\n }\n }\n\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(nextParams)) {\n if (value && key !== \"autoRun\") search.set(key, value);\n }\n const query = search.toString();\n return query ? `${route}?${query}` : route;\n}\n\nfunction apiPathToRoutePath(path: string): string {\n const cliPath = path\n .trim()\n .replace(/^\\/api\\/v1\\/?/, \"\")\n .replace(/^\\/+/, \"\")\n .replace(/\\/+$/, \"\");\n if (!cliPath) return \"/\";\n return `/${cliPath.replace(/\\{([^}]+)\\}/g, \":$1\")}`;\n}\n\nfunction pathParamNames(path: string): string[] {\n return [...path.matchAll(/\\{([^}]+)\\}/g)]\n .map((match) => match[1])\n .filter((name): name is string => Boolean(name));\n}\n\nfunction parseArgsParam(value: string | undefined): string[] {\n if (!value) return [];\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"[]\" || trimmed.toLowerCase() === \"null\") return [];\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) return parsed.map(String).filter(Boolean);\n } catch {\n // Fall back to comma-delimited args below.\n }\n return trimmed\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean);\n}\n"],"names":["useState","jsxs","Fragment","Button","jsx","Icon","UiPlay","Modal","CommandForm","InlineError","CommandOutput"],"mappings":"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"}
1
+ {"version":3,"file":"OperationActionDialog.cjs","sources":["../../src/rpc/OperationActionDialog.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { Button } from \"../components/button\";\nimport { Icon } from \"../data/Icon\";\nimport { UiPlay } from \"../icons\";\nimport { Modal } from \"../overlay/Modal\";\nimport { CommandForm } from \"./CommandForm\";\nimport { CommandOutput } from \"./CommandOutput\";\nimport { InlineError } from \"./InlineError\";\nimport type { ExecutionResponse, ResolvedOperation } from \"./types\";\nimport type { OperationsApiClient } from \"./useOperations\";\n\nexport type OperationActionDialogProps = {\n operation: ResolvedOperation;\n client: OperationsApiClient;\n initialValues: Record<string, string>;\n label: string;\n defaultAccept?: string;\n onNavigateAction?: (href: string) => void;\n};\n\nexport function OperationActionDialog({\n operation,\n client,\n initialValues,\n label,\n defaultAccept = \"application/clicky+json\",\n onNavigateAction,\n}: OperationActionDialogProps) {\n const [open, setOpen] = useState(false);\n const [isExecuting, setIsExecuting] = useState(false);\n const [response, setResponse] = useState<ExecutionResponse | null>(null);\n const [error, setError] = useState<unknown>(null);\n\n async function handleExecute(params: Record<string, string>, headers: Record<string, string>) {\n if (onNavigateAction) {\n const href = hrefForOperationAction(operation.path, params);\n if (!href) return;\n const separator = href.includes(\"?\") ? \"&\" : \"?\";\n onNavigateAction(`${href}${separator}autoRun=1`);\n return;\n }\n\n setIsExecuting(true);\n setError(null);\n setResponse(null);\n try {\n const result = await client.executeCommand(operation.path, operation.method, params, headers);\n setResponse(result);\n } catch (err) {\n setError(err);\n } finally {\n setIsExecuting(false);\n }\n }\n\n return (\n <>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => setOpen(true)}>\n <Icon icon={UiPlay} />\n {label}\n </Button>\n <Modal open={open} onClose={() => setOpen(false)} title={label} size=\"lg\">\n <div className=\"space-y-4\">\n <CommandForm\n parameters={operation.operation.parameters ?? []}\n onExecute={handleExecute}\n isPending={isExecuting}\n method={operation.method}\n path={operation.path}\n accept={defaultAccept}\n initialValues={initialValues}\n />\n\n {error ? (\n <InlineError title={`Failed to execute ${operation.path}`} error={error} />\n ) : response ? (\n <CommandOutput response={response} />\n ) : null}\n </div>\n </Modal>\n </>\n );\n}\n\nfunction hrefForOperationAction(path: string, params: Record<string, string>): string | undefined {\n const nextParams = { ...params };\n const args = parseArgsParam(params.args);\n let route = apiPathToRoutePath(path);\n\n for (const [index, name] of pathParamNames(path).entries()) {\n const value = nextParams[name] || args[index];\n if (!value) return undefined;\n route = route.replace(`:${name}`, encodeURIComponent(value));\n delete nextParams[name];\n if (!nextParams[name] && value === args[index]) {\n delete nextParams.args;\n }\n }\n\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(nextParams)) {\n if (value && key !== \"autoRun\" && key !== \"__autoRun\") search.set(key, value);\n }\n const query = search.toString();\n return query ? `${route}?${query}` : route;\n}\n\nfunction apiPathToRoutePath(path: string): string {\n const cliPath = path\n .trim()\n .replace(/^\\/api\\/v1\\/?/, \"\")\n .replace(/^\\/+/, \"\")\n .replace(/\\/+$/, \"\");\n if (!cliPath) return \"/\";\n return `/${cliPath.replace(/\\{([^}]+)\\}/g, \":$1\")}`;\n}\n\nfunction pathParamNames(path: string): string[] {\n return [...path.matchAll(/\\{([^}]+)\\}/g)]\n .map((match) => match[1])\n .filter((name): name is string => Boolean(name));\n}\n\nfunction parseArgsParam(value: string | undefined): string[] {\n if (!value) return [];\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"[]\" || trimmed.toLowerCase() === \"null\") return [];\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) return parsed.map(String).filter(Boolean);\n } catch {\n // Fall back to comma-delimited args below.\n }\n return trimmed\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean);\n}\n"],"names":["useState","jsxs","Fragment","Button","jsx","Icon","UiPlay","Modal","CommandForm","InlineError","CommandOutput"],"mappings":"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"}
@@ -76,7 +76,7 @@ function hrefForOperationAction(path, params) {
76
76
  }
77
77
  const search = new URLSearchParams();
78
78
  for (const [key, value] of Object.entries(nextParams)) {
79
- if (value && key !== "autoRun") search.set(key, value);
79
+ if (value && key !== "autoRun" && key !== "__autoRun") search.set(key, value);
80
80
  }
81
81
  const query = search.toString();
82
82
  return query ? `${route}?${query}` : route;
@@ -1 +1 @@
1
- {"version":3,"file":"OperationActionDialog.js","sources":["../../src/rpc/OperationActionDialog.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { Button } from \"../components/button\";\nimport { Icon } from \"../data/Icon\";\nimport { UiPlay } from \"../icons\";\nimport { Modal } from \"../overlay/Modal\";\nimport { CommandForm } from \"./CommandForm\";\nimport { CommandOutput } from \"./CommandOutput\";\nimport { InlineError } from \"./InlineError\";\nimport type { ExecutionResponse, ResolvedOperation } from \"./types\";\nimport type { OperationsApiClient } from \"./useOperations\";\n\nexport type OperationActionDialogProps = {\n operation: ResolvedOperation;\n client: OperationsApiClient;\n initialValues: Record<string, string>;\n label: string;\n defaultAccept?: string;\n onNavigateAction?: (href: string) => void;\n};\n\nexport function OperationActionDialog({\n operation,\n client,\n initialValues,\n label,\n defaultAccept = \"application/clicky+json\",\n onNavigateAction,\n}: OperationActionDialogProps) {\n const [open, setOpen] = useState(false);\n const [isExecuting, setIsExecuting] = useState(false);\n const [response, setResponse] = useState<ExecutionResponse | null>(null);\n const [error, setError] = useState<unknown>(null);\n\n async function handleExecute(params: Record<string, string>, headers: Record<string, string>) {\n if (onNavigateAction) {\n const href = hrefForOperationAction(operation.path, params);\n if (!href) return;\n const separator = href.includes(\"?\") ? \"&\" : \"?\";\n onNavigateAction(`${href}${separator}autoRun=1`);\n return;\n }\n\n setIsExecuting(true);\n setError(null);\n setResponse(null);\n try {\n const result = await client.executeCommand(operation.path, operation.method, params, headers);\n setResponse(result);\n } catch (err) {\n setError(err);\n } finally {\n setIsExecuting(false);\n }\n }\n\n return (\n <>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => setOpen(true)}>\n <Icon icon={UiPlay} />\n {label}\n </Button>\n <Modal open={open} onClose={() => setOpen(false)} title={label} size=\"lg\">\n <div className=\"space-y-4\">\n <CommandForm\n parameters={operation.operation.parameters ?? []}\n onExecute={handleExecute}\n isPending={isExecuting}\n method={operation.method}\n path={operation.path}\n accept={defaultAccept}\n initialValues={initialValues}\n />\n\n {error ? (\n <InlineError title={`Failed to execute ${operation.path}`} error={error} />\n ) : response ? (\n <CommandOutput response={response} />\n ) : null}\n </div>\n </Modal>\n </>\n );\n}\n\nfunction hrefForOperationAction(path: string, params: Record<string, string>): string | undefined {\n const nextParams = { ...params };\n const args = parseArgsParam(params.args);\n let route = apiPathToRoutePath(path);\n\n for (const [index, name] of pathParamNames(path).entries()) {\n const value = nextParams[name] || args[index];\n if (!value) return undefined;\n route = route.replace(`:${name}`, encodeURIComponent(value));\n delete nextParams[name];\n if (!nextParams[name] && value === args[index]) {\n delete nextParams.args;\n }\n }\n\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(nextParams)) {\n if (value && key !== \"autoRun\") search.set(key, value);\n }\n const query = search.toString();\n return query ? `${route}?${query}` : route;\n}\n\nfunction apiPathToRoutePath(path: string): string {\n const cliPath = path\n .trim()\n .replace(/^\\/api\\/v1\\/?/, \"\")\n .replace(/^\\/+/, \"\")\n .replace(/\\/+$/, \"\");\n if (!cliPath) return \"/\";\n return `/${cliPath.replace(/\\{([^}]+)\\}/g, \":$1\")}`;\n}\n\nfunction pathParamNames(path: string): string[] {\n return [...path.matchAll(/\\{([^}]+)\\}/g)]\n .map((match) => match[1])\n .filter((name): name is string => Boolean(name));\n}\n\nfunction parseArgsParam(value: string | undefined): string[] {\n if (!value) return [];\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"[]\" || trimmed.toLowerCase() === \"null\") return [];\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) return parsed.map(String).filter(Boolean);\n } catch {\n // Fall back to comma-delimited args below.\n }\n return trimmed\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OperationActionDialog.js","sources":["../../src/rpc/OperationActionDialog.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { Button } from \"../components/button\";\nimport { Icon } from \"../data/Icon\";\nimport { UiPlay } from \"../icons\";\nimport { Modal } from \"../overlay/Modal\";\nimport { CommandForm } from \"./CommandForm\";\nimport { CommandOutput } from \"./CommandOutput\";\nimport { InlineError } from \"./InlineError\";\nimport type { ExecutionResponse, ResolvedOperation } from \"./types\";\nimport type { OperationsApiClient } from \"./useOperations\";\n\nexport type OperationActionDialogProps = {\n operation: ResolvedOperation;\n client: OperationsApiClient;\n initialValues: Record<string, string>;\n label: string;\n defaultAccept?: string;\n onNavigateAction?: (href: string) => void;\n};\n\nexport function OperationActionDialog({\n operation,\n client,\n initialValues,\n label,\n defaultAccept = \"application/clicky+json\",\n onNavigateAction,\n}: OperationActionDialogProps) {\n const [open, setOpen] = useState(false);\n const [isExecuting, setIsExecuting] = useState(false);\n const [response, setResponse] = useState<ExecutionResponse | null>(null);\n const [error, setError] = useState<unknown>(null);\n\n async function handleExecute(params: Record<string, string>, headers: Record<string, string>) {\n if (onNavigateAction) {\n const href = hrefForOperationAction(operation.path, params);\n if (!href) return;\n const separator = href.includes(\"?\") ? \"&\" : \"?\";\n onNavigateAction(`${href}${separator}autoRun=1`);\n return;\n }\n\n setIsExecuting(true);\n setError(null);\n setResponse(null);\n try {\n const result = await client.executeCommand(operation.path, operation.method, params, headers);\n setResponse(result);\n } catch (err) {\n setError(err);\n } finally {\n setIsExecuting(false);\n }\n }\n\n return (\n <>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => setOpen(true)}>\n <Icon icon={UiPlay} />\n {label}\n </Button>\n <Modal open={open} onClose={() => setOpen(false)} title={label} size=\"lg\">\n <div className=\"space-y-4\">\n <CommandForm\n parameters={operation.operation.parameters ?? []}\n onExecute={handleExecute}\n isPending={isExecuting}\n method={operation.method}\n path={operation.path}\n accept={defaultAccept}\n initialValues={initialValues}\n />\n\n {error ? (\n <InlineError title={`Failed to execute ${operation.path}`} error={error} />\n ) : response ? (\n <CommandOutput response={response} />\n ) : null}\n </div>\n </Modal>\n </>\n );\n}\n\nfunction hrefForOperationAction(path: string, params: Record<string, string>): string | undefined {\n const nextParams = { ...params };\n const args = parseArgsParam(params.args);\n let route = apiPathToRoutePath(path);\n\n for (const [index, name] of pathParamNames(path).entries()) {\n const value = nextParams[name] || args[index];\n if (!value) return undefined;\n route = route.replace(`:${name}`, encodeURIComponent(value));\n delete nextParams[name];\n if (!nextParams[name] && value === args[index]) {\n delete nextParams.args;\n }\n }\n\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(nextParams)) {\n if (value && key !== \"autoRun\" && key !== \"__autoRun\") search.set(key, value);\n }\n const query = search.toString();\n return query ? `${route}?${query}` : route;\n}\n\nfunction apiPathToRoutePath(path: string): string {\n const cliPath = path\n .trim()\n .replace(/^\\/api\\/v1\\/?/, \"\")\n .replace(/^\\/+/, \"\")\n .replace(/\\/+$/, \"\");\n if (!cliPath) return \"/\";\n return `/${cliPath.replace(/\\{([^}]+)\\}/g, \":$1\")}`;\n}\n\nfunction pathParamNames(path: string): string[] {\n return [...path.matchAll(/\\{([^}]+)\\}/g)]\n .map((match) => match[1])\n .filter((name): name is string => Boolean(name));\n}\n\nfunction parseArgsParam(value: string | undefined): string[] {\n if (!value) return [];\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"[]\" || trimmed.toLowerCase() === \"null\") return [];\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) return parsed.map(String).filter(Boolean);\n } catch {\n // Fall back to comma-delimited args below.\n }\n return trimmed\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean);\n}\n"],"names":[],"mappings":"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"}
@@ -20,7 +20,7 @@ function OperationCommandPage({
20
20
  operation: providedOperation,
21
21
  operations = providedOperation ? [providedOperation] : [],
22
22
  initialValues = {},
23
- autoRun = false,
23
+ autoRun,
24
24
  backHref,
25
25
  backLabel = "Back",
26
26
  renderLink,
@@ -40,6 +40,7 @@ function OperationCommandPage({
40
40
  const [hasAutoRun, setHasAutoRun] = react.useState(false);
41
41
  const parameters = (operation == null ? void 0 : operation.operation.parameters) ?? [];
42
42
  const isGet = ((operation == null ? void 0 : operation.method) ?? "").toUpperCase() === "GET";
43
+ const effectiveAutoRun = operation ? autoRun ?? isGet : false;
43
44
  const parameterSignature = JSON.stringify(
44
45
  parameters.map((param) => {
45
46
  var _a;
@@ -169,17 +170,26 @@ function OperationCommandPage({
169
170
  setHasAutoRun(false);
170
171
  setResult(null);
171
172
  setError(null);
172
- }, [autoRun, operationKey]);
173
+ lastSubmittedSignature.current = "";
174
+ }, [effectiveAutoRun, operationKey]);
173
175
  react.useEffect(() => {
174
- if (!autoRun || !operation || hasAutoRun) return;
176
+ if (!effectiveAutoRun || !operation || hasAutoRun) return;
175
177
  const missingRequired = parameters.filter((param) => {
176
178
  if (!param.required) return false;
177
179
  return (effectiveInitialValues[param.name] ?? "").trim() === "";
178
180
  });
179
181
  if (missingRequired.length > 0) return;
180
182
  setHasAutoRun(true);
183
+ lastSubmittedSignature.current = JSON.stringify(formMetadata.pruneParameterValues(effectiveInitialValues));
181
184
  void executeOperation(effectiveInitialValues);
182
- }, [accept, autoRun, effectiveInitialValues, hasAutoRun, operationKey, parameterSignature]);
185
+ }, [
186
+ accept,
187
+ effectiveAutoRun,
188
+ effectiveInitialValues,
189
+ hasAutoRun,
190
+ operationKey,
191
+ parameterSignature
192
+ ]);
183
193
  react.useEffect(() => {
184
194
  if (!isGet || !operation || !hasAutoRun) return;
185
195
  const merged = { ...debouncedValues, ...lockedPathValues };
@@ -193,9 +203,6 @@ function OperationCommandPage({
193
203
  lastSubmittedSignature.current = signature;
194
204
  void executeOperation(merged);
195
205
  }, [isGet, hasAutoRun, debouncedValues, lockedPathValues, parameterSignature]);
196
- react.useEffect(() => {
197
- lastSubmittedSignature.current = "";
198
- }, [operationKey]);
199
206
  const getRowDetailHref = react.useCallback(
200
207
  (row) => {
201
208
  if (!detailOperation) return void 0;
@@ -289,18 +296,18 @@ function OperationCommandPage({
289
296
  method.toUpperCase() === "GET" ? parameters.length > 0 ? (
290
297
  // Before a result lands the FilterBar lives here so users can
291
298
  // fill in path params / required inputs and submit. Once a
292
- // result is showing AND autoRun is on (sidebar flow), the same
299
+ // result is showing AND auto-run is on (sidebar flow), the same
293
300
  // filter chips relocate into the DataTable's filter bar via
294
301
  // externalFilters, which is the unified placement the user asked
295
302
  // for. The two branches share `formConfig.filters` so the values
296
303
  // stay in sync.
297
- !result || !autoRun ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
304
+ !result || !effectiveAutoRun ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
298
305
  /* @__PURE__ */ jsxRuntime.jsx(
299
306
  FilterBar.FilterBar,
300
307
  {
301
- autoSubmit: autoRun,
308
+ autoSubmit: effectiveAutoRun,
302
309
  filters: formConfig.filters,
303
- ...!autoRun ? { onApply: () => handleManualSubmit() } : {},
310
+ ...!effectiveAutoRun ? { onApply: () => handleManualSubmit() } : {},
304
311
  applyLabel: "Execute request",
305
312
  isPending: isExecuting,
306
313
  ...formConfig.timeRange ? { timeRange: formConfig.timeRange } : {}
@@ -332,8 +339,8 @@ function OperationCommandPage({
332
339
  onTableRowClick: handleTableRowClick,
333
340
  isTableRowClickable: (row) => Boolean(getRowDetailHref(row))
334
341
  } : {},
335
- ...isGet && autoRun && formConfig.filters.length > 0 ? { externalFilters: formConfig.filters } : {},
336
- ...isGet && autoRun && dataTablePagination ? { pagination: dataTablePagination } : {}
342
+ ...isGet && effectiveAutoRun && formConfig.filters.length > 0 ? { externalFilters: formConfig.filters } : {},
343
+ ...isGet && effectiveAutoRun && dataTablePagination ? { pagination: dataTablePagination } : {}
337
344
  }
338
345
  ) }) : null
339
346
  ] });
@@ -449,7 +456,7 @@ function shellQuote(value) {
449
456
  function stripRunnerParams(values) {
450
457
  const next = {};
451
458
  for (const [key, value] of Object.entries(values)) {
452
- if (key === "autoRun") continue;
459
+ if (key === "autoRun" || key === "__autoRun") continue;
453
460
  next[key] = value;
454
461
  }
455
462
  return next;