@flanksource/clicky-ui 0.2.9 → 0.2.11

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 (105) hide show
  1. package/dist/components/Combobox.cjs +4 -1
  2. package/dist/components/Combobox.cjs.map +1 -1
  3. package/dist/components/Combobox.d.ts +6 -0
  4. package/dist/components/Combobox.d.ts.map +1 -1
  5. package/dist/components/Combobox.js +4 -1
  6. package/dist/components/Combobox.js.map +1 -1
  7. package/dist/components/JsonSchemaForm.cjs +24 -5
  8. package/dist/components/JsonSchemaForm.cjs.map +1 -1
  9. package/dist/components/JsonSchemaForm.d.ts +1 -1
  10. package/dist/components/JsonSchemaForm.d.ts.map +1 -1
  11. package/dist/components/JsonSchemaForm.js +24 -5
  12. package/dist/components/JsonSchemaForm.js.map +1 -1
  13. package/dist/components/json-schema-form-array.cjs +117 -37
  14. package/dist/components/json-schema-form-array.cjs.map +1 -1
  15. package/dist/components/json-schema-form-array.d.ts.map +1 -1
  16. package/dist/components/json-schema-form-array.js +118 -38
  17. package/dist/components/json-schema-form-array.js.map +1 -1
  18. package/dist/components/json-schema-form-fields.cjs +121 -51
  19. package/dist/components/json-schema-form-fields.cjs.map +1 -1
  20. package/dist/components/json-schema-form-fields.d.ts +9 -6
  21. package/dist/components/json-schema-form-fields.d.ts.map +1 -1
  22. package/dist/components/json-schema-form-fields.js +121 -51
  23. package/dist/components/json-schema-form-fields.js.map +1 -1
  24. package/dist/components/json-schema-form-render.cjs +15 -8
  25. package/dist/components/json-schema-form-render.cjs.map +1 -1
  26. package/dist/components/json-schema-form-render.d.ts +5 -2
  27. package/dist/components/json-schema-form-render.d.ts.map +1 -1
  28. package/dist/components/json-schema-form-render.js +15 -8
  29. package/dist/components/json-schema-form-render.js.map +1 -1
  30. package/dist/components/json-schema-form-resolve.cjs +41 -6
  31. package/dist/components/json-schema-form-resolve.cjs.map +1 -1
  32. package/dist/components/json-schema-form-resolve.d.ts.map +1 -1
  33. package/dist/components/json-schema-form-resolve.js +41 -6
  34. package/dist/components/json-schema-form-resolve.js.map +1 -1
  35. package/dist/components/json-schema-form-size.cjs +61 -0
  36. package/dist/components/json-schema-form-size.cjs.map +1 -0
  37. package/dist/components/json-schema-form-size.d.ts +11 -0
  38. package/dist/components/json-schema-form-size.d.ts.map +1 -0
  39. package/dist/components/json-schema-form-size.js +61 -0
  40. package/dist/components/json-schema-form-size.js.map +1 -0
  41. package/dist/components/json-schema-form-types.d.ts +36 -1
  42. package/dist/components/json-schema-form-types.d.ts.map +1 -1
  43. package/dist/components.cjs +2 -0
  44. package/dist/components.cjs.map +1 -1
  45. package/dist/components.d.ts +3 -1
  46. package/dist/components.d.ts.map +1 -1
  47. package/dist/components.js +2 -0
  48. package/dist/components.js.map +1 -1
  49. package/dist/data/Clicky.cjs +412 -90
  50. package/dist/data/Clicky.cjs.map +1 -1
  51. package/dist/data/Clicky.d.ts +4 -2
  52. package/dist/data/Clicky.d.ts.map +1 -1
  53. package/dist/data/Clicky.js +413 -91
  54. package/dist/data/Clicky.js.map +1 -1
  55. package/dist/data/DataTable.cjs +534 -293
  56. package/dist/data/DataTable.cjs.map +1 -1
  57. package/dist/data/DataTable.d.ts +12 -0
  58. package/dist/data/DataTable.d.ts.map +1 -1
  59. package/dist/data/DataTable.js +534 -293
  60. package/dist/data/DataTable.js.map +1 -1
  61. package/dist/data.d.ts +1 -1
  62. package/dist/data.d.ts.map +1 -1
  63. package/dist/index.cjs +2 -0
  64. package/dist/index.cjs.map +1 -1
  65. package/dist/index.js +2 -0
  66. package/dist/index.js.map +1 -1
  67. package/dist/rpc/CommandOutput.cjs +101 -20
  68. package/dist/rpc/CommandOutput.cjs.map +1 -1
  69. package/dist/rpc/CommandOutput.d.ts +12 -4
  70. package/dist/rpc/CommandOutput.d.ts.map +1 -1
  71. package/dist/rpc/CommandOutput.js +102 -21
  72. package/dist/rpc/CommandOutput.js.map +1 -1
  73. package/dist/rpc/ExecutionResult.cjs +4 -76
  74. package/dist/rpc/ExecutionResult.cjs.map +1 -1
  75. package/dist/rpc/ExecutionResult.d.ts +3 -22
  76. package/dist/rpc/ExecutionResult.d.ts.map +1 -1
  77. package/dist/rpc/ExecutionResult.js +4 -76
  78. package/dist/rpc/ExecutionResult.js.map +1 -1
  79. package/dist/rpc/OperationCatalog.cjs +22 -13
  80. package/dist/rpc/OperationCatalog.cjs.map +1 -1
  81. package/dist/rpc/OperationCatalog.d.ts.map +1 -1
  82. package/dist/rpc/OperationCatalog.js +24 -15
  83. package/dist/rpc/OperationCatalog.js.map +1 -1
  84. package/dist/rpc/OperationCommandPage.cjs +10 -20
  85. package/dist/rpc/OperationCommandPage.cjs.map +1 -1
  86. package/dist/rpc/OperationCommandPage.d.ts.map +1 -1
  87. package/dist/rpc/OperationCommandPage.js +11 -21
  88. package/dist/rpc/OperationCommandPage.js.map +1 -1
  89. package/dist/rpc/apiClient.cjs +18 -0
  90. package/dist/rpc/apiClient.cjs.map +1 -1
  91. package/dist/rpc/apiClient.d.ts.map +1 -1
  92. package/dist/rpc/apiClient.js +18 -0
  93. package/dist/rpc/apiClient.js.map +1 -1
  94. package/dist/rpc/formMetadata.cjs +31 -0
  95. package/dist/rpc/formMetadata.cjs.map +1 -1
  96. package/dist/rpc/formMetadata.d.ts +3 -1
  97. package/dist/rpc/formMetadata.d.ts.map +1 -1
  98. package/dist/rpc/formMetadata.js +31 -0
  99. package/dist/rpc/formMetadata.js.map +1 -1
  100. package/dist/rpc/types.cjs.map +1 -1
  101. package/dist/rpc/types.d.ts +7 -0
  102. package/dist/rpc/types.d.ts.map +1 -1
  103. package/dist/rpc/types.js.map +1 -1
  104. package/dist/styles.css +1 -1
  105. package/package.json +1 -1
@@ -27,6 +27,10 @@ const UiChevronDown = require("../icons/components/UiChevronDown.cjs");
27
27
  const UiComment = require("../icons/components/UiComment.cjs");
28
28
  const UiTable = require("../icons/components/UiTable.cjs");
29
29
  const UiFileCode = require("../icons/components/UiFileCode.cjs");
30
+ const UiFileSpreadsheet = require("../icons/components/UiFileSpreadsheet.cjs");
31
+ const UiMarkdown = require("../icons/components/UiMarkdown.cjs");
32
+ const UiFileText = require("../icons/components/UiFileText.cjs");
33
+ const UiJson = require("../icons/components/UiJson.cjs");
30
34
  const UiEye = require("../icons/components/UiEye.cjs");
31
35
  const CLICKY_PRIMARY_VIEW_FORMATS = ["clicky", "json"];
32
36
  const CLICKY_OVERFLOW_VIEW_FORMATS = [
@@ -39,12 +43,20 @@ const CLICKY_OVERFLOW_VIEW_FORMATS = [
39
43
  "excel",
40
44
  "slack"
41
45
  ];
42
- const CLICKY_DOWNLOAD_FORMATS = ["json", "clicky", ...CLICKY_OVERFLOW_VIEW_FORMATS];
46
+ const CLICKY_DOWNLOAD_FORMATS = [
47
+ "yaml",
48
+ "json",
49
+ "csv",
50
+ "pdf",
51
+ "markdown"
52
+ ];
43
53
  const clickyRuntimeContextDefault = {
44
54
  operations: [],
45
55
  operationsLoading: false
46
56
  };
47
- const ClickyRuntimeContext = react.createContext(clickyRuntimeContextDefault);
57
+ const ClickyRuntimeContext = react.createContext(
58
+ clickyRuntimeContextDefault
59
+ );
48
60
  function Clicky(props) {
49
61
  const [queryClient] = react.useState(
50
62
  () => new reactQuery.QueryClient({
@@ -56,6 +68,10 @@ function Clicky(props) {
56
68
  }
57
69
  })
58
70
  );
71
+ const tableMenuActions = react.useMemo(
72
+ () => getDownloadMenuActions({ url: props.url, download: props.download }),
73
+ [props.download, props.url]
74
+ );
59
75
  const content = /* @__PURE__ */ jsxRuntime.jsx(
60
76
  ClickyRuntimeProvider,
61
77
  {
@@ -67,6 +83,7 @@ function Clicky(props) {
67
83
  ...props.timeRange ? { tableTimeRange: props.timeRange } : {},
68
84
  ...props.externalFilters ? { tableExternalFilters: props.externalFilters } : {},
69
85
  ...props.pagination ? { tablePagination: props.pagination } : {},
86
+ ...tableMenuActions.length > 0 ? { tableMenuActions } : {},
70
87
  children: props.url ? /* @__PURE__ */ jsxRuntime.jsx(ClickyRemoteRenderer, { ...props, url: props.url }) : /* @__PURE__ */ jsxRuntime.jsx(
71
88
  ClickyContent,
72
89
  {
@@ -90,10 +107,11 @@ function ClickyRuntimeProvider({
90
107
  tableTimeRange,
91
108
  tableExternalFilters,
92
109
  tablePagination,
110
+ tableMenuActions,
93
111
  children
94
112
  }) {
95
113
  if (!commandRuntime) {
96
- const hasOverrides = onTableRowClick || getTableRowHref || isTableRowClickable || tableSearch || tableTimeRange || tableExternalFilters || tablePagination;
114
+ const hasOverrides = onTableRowClick || getTableRowHref || isTableRowClickable || tableSearch || tableTimeRange || tableExternalFilters || tablePagination || tableMenuActions;
97
115
  return /* @__PURE__ */ jsxRuntime.jsx(
98
116
  ClickyRuntimeContext.Provider,
99
117
  {
@@ -105,7 +123,8 @@ function ClickyRuntimeProvider({
105
123
  tableSearch,
106
124
  tableTimeRange,
107
125
  tableExternalFilters,
108
- tablePagination
126
+ tablePagination,
127
+ tableMenuActions
109
128
  } : clickyRuntimeContextDefault,
110
129
  children
111
130
  }
@@ -122,6 +141,7 @@ function ClickyRuntimeProvider({
122
141
  ...tableTimeRange ? { tableTimeRange } : {},
123
142
  ...tableExternalFilters ? { tableExternalFilters } : {},
124
143
  ...tablePagination ? { tablePagination } : {},
144
+ ...tableMenuActions ? { tableMenuActions } : {},
125
145
  children
126
146
  }
127
147
  );
@@ -135,6 +155,7 @@ function ClickyCommandRuntimeProvider({
135
155
  tableTimeRange,
136
156
  tableExternalFilters,
137
157
  tablePagination,
158
+ tableMenuActions,
138
159
  children
139
160
  }) {
140
161
  const { operations, isLoading } = useOperations.useOperations(commandRuntime.client);
@@ -148,6 +169,7 @@ function ClickyCommandRuntimeProvider({
148
169
  tableTimeRange,
149
170
  tableExternalFilters,
150
171
  tablePagination,
172
+ tableMenuActions,
151
173
  operations,
152
174
  operationsLoading: isLoading
153
175
  }),
@@ -161,7 +183,8 @@ function ClickyCommandRuntimeProvider({
161
183
  tableSearch,
162
184
  tableTimeRange,
163
185
  tableExternalFilters,
164
- tablePagination
186
+ tablePagination,
187
+ tableMenuActions
165
188
  ]
166
189
  );
167
190
  return /* @__PURE__ */ jsxRuntime.jsx(ClickyRuntimeContext.Provider, { value, children });
@@ -194,13 +217,22 @@ function ClickyRemoteRenderer({
194
217
  className
195
218
  }) {
196
219
  var _a, _b;
197
- const availableViews = react.useMemo(() => getAvailableViews({ data, url, view }), [data, url, view]);
198
- const primaryViews = react.useMemo(() => availableViews.filter(isPrimaryViewFormat), [availableViews]);
220
+ const availableViews = react.useMemo(
221
+ () => getAvailableViews({ data, url, view }),
222
+ [data, url, view]
223
+ );
224
+ const primaryViews = react.useMemo(
225
+ () => availableViews.filter(isPrimaryViewFormat),
226
+ [availableViews]
227
+ );
199
228
  const overflowViews = react.useMemo(
200
229
  () => availableViews.filter(isOverflowViewFormat),
201
230
  [availableViews]
202
231
  );
203
- const downloadFormats = react.useMemo(() => getDownloadFormats({ url, download }), [download, url]);
232
+ const downloadFormats = react.useMemo(
233
+ () => getDownloadFormats({ url, download }),
234
+ [download, url]
235
+ );
204
236
  const [activeView, setActiveView] = react.useState(
205
237
  () => availableViews[0] ?? "clicky"
206
238
  );
@@ -219,25 +251,34 @@ function ClickyRemoteRenderer({
219
251
  const fallbackJsonData = react.useMemo(() => parseJsonValue(data), [data]);
220
252
  const effectiveJsonData = activeView === "json" && ((_b = activeQuery.data) == null ? void 0 : _b.kind) === "text" ? parseJsonValue(activeQuery.data.text) : fallbackJsonData;
221
253
  const activeOverflowView = isOverflowViewFormat(activeView) ? activeView : null;
222
- const canDownload = downloadFormats.length > 0;
254
+ const downloadHandledByTable = clickyPayloadHasTable(effectiveClickyData);
255
+ const canDownload = downloadFormats.length > 0 && !downloadHandledByTable;
223
256
  const loadingMessage = `Fetching ${formattedUrl}`;
224
257
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("space-y-density-3", className), children: [
225
258
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2 rounded-md border border-border bg-muted/20 px-density-3 py-density-2", children: [
226
- primaryViews.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", "aria-label": "Clicky view mode", className: "flex flex-wrap gap-1", children: primaryViews.map((mode) => /* @__PURE__ */ jsxRuntime.jsx(
227
- "button",
259
+ primaryViews.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
260
+ "div",
228
261
  {
229
- type: "button",
230
- role: "radio",
231
- "aria-checked": activeView === mode,
232
- onClick: () => setActiveView(mode),
233
- className: utils.cn(
234
- "rounded-md border px-2.5 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
235
- activeView === mode ? "border-foreground/20 bg-accent text-foreground" : "border-transparent text-muted-foreground hover:border-foreground/20 hover:text-foreground"
236
- ),
237
- children: formatViewLabel(mode)
238
- },
239
- mode
240
- )) }),
262
+ role: "radiogroup",
263
+ "aria-label": "Clicky view mode",
264
+ className: "flex flex-wrap gap-1",
265
+ children: primaryViews.map((mode) => /* @__PURE__ */ jsxRuntime.jsx(
266
+ "button",
267
+ {
268
+ type: "button",
269
+ role: "radio",
270
+ "aria-checked": activeView === mode,
271
+ onClick: () => setActiveView(mode),
272
+ className: utils.cn(
273
+ "rounded-md border px-2.5 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
274
+ activeView === mode ? "border-foreground/20 bg-accent text-foreground" : "border-transparent text-muted-foreground hover:border-foreground/20 hover:text-foreground"
275
+ ),
276
+ children: formatViewLabel(mode)
277
+ },
278
+ mode
279
+ ))
280
+ }
281
+ ),
241
282
  overflowViews.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
242
283
  ClickyViewMenu,
243
284
  {
@@ -248,7 +289,14 @@ function ClickyRemoteRenderer({
248
289
  ),
249
290
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-auto flex items-center gap-2", children: [
250
291
  shouldFetchRemoteView(activeView) && activeQuery.isFetching && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Refreshing…" }),
251
- canDownload && /* @__PURE__ */ jsxRuntime.jsx(ClickyDownloadMenu, { url, formats: downloadFormats, label: download == null ? void 0 : download.label })
292
+ canDownload && /* @__PURE__ */ jsxRuntime.jsx(
293
+ ClickyDownloadMenu,
294
+ {
295
+ url,
296
+ formats: downloadFormats,
297
+ label: download == null ? void 0 : download.label
298
+ }
299
+ )
252
300
  ] })
253
301
  ] }),
254
302
  activeView === "pdf" ? /* @__PURE__ */ jsxRuntime.jsx(ClickyPdfPreview, { src: formattedUrl }) : activeView === "html" ? /* @__PURE__ */ jsxRuntime.jsx(ClickyHtmlPreview, { src: formattedUrl }) : activeView === "excel" ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -292,7 +340,13 @@ function ClickyRemoteRenderer({
292
340
  }
293
341
  ),
294
342
  /* @__PURE__ */ jsxRuntime.jsx(ClickyJsonTree, { value: effectiveJsonData })
295
- ] }) : activeQuery.isPending ? /* @__PURE__ */ jsxRuntime.jsx(ClickyNotice, { title: `Loading ${formatViewLabel(activeView)}`, message: loadingMessage }) : activeQuery.isError ? /* @__PURE__ */ jsxRuntime.jsx(
343
+ ] }) : activeQuery.isPending ? /* @__PURE__ */ jsxRuntime.jsx(
344
+ ClickyNotice,
345
+ {
346
+ title: `Loading ${formatViewLabel(activeView)}`,
347
+ message: loadingMessage
348
+ }
349
+ ) : activeQuery.isError ? /* @__PURE__ */ jsxRuntime.jsx(
296
350
  ClickyNotice,
297
351
  {
298
352
  title: `${formatViewLabel(activeView)} request failed`,
@@ -357,15 +411,22 @@ function ClickyViewMenu({
357
411
  {
358
412
  icon: meta.icon,
359
413
  className: utils.cn(
360
- "mt-0.5 shrink-0 text-base text-muted-foreground",
361
- active && "text-foreground"
414
+ "mt-0.5 shrink-0 text-base",
415
+ meta.iconClassName ?? "text-muted-foreground",
416
+ active && !meta.iconClassName && "text-foreground"
362
417
  )
363
418
  }
364
419
  ),
365
420
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
366
421
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center justify-between gap-3", children: [
367
422
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: meta.label }),
368
- active && /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: UiCheck.UiCheck, className: "text-xs text-muted-foreground" })
423
+ active && /* @__PURE__ */ jsxRuntime.jsx(
424
+ Icon.Icon,
425
+ {
426
+ icon: UiCheck.UiCheck,
427
+ className: "text-xs text-muted-foreground"
428
+ }
429
+ )
369
430
  ] }),
370
431
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-0.5 block text-xs text-muted-foreground", children: meta.description })
371
432
  ] })
@@ -397,7 +458,7 @@ function ClickyDownloadMenu({
397
458
  type: "button",
398
459
  "aria-label": label ? `Download ${primaryMeta.label} ${label}` : `Download ${primaryMeta.label}`,
399
460
  className: "inline-flex items-center gap-2 rounded-md border border-input bg-background px-3 py-1.5 text-xs font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
400
- onClick: () => submitDownloadRequest(buildFormatUrl(url, primaryFormat)),
461
+ onClick: () => triggerDownload(buildDownloadUrl(url, primaryFormat, label)),
401
462
  children: [
402
463
  /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: UiCloudDownload.UiCloudDownload, className: "text-sm" }),
403
464
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: `Download ${primaryMeta.label}` })
@@ -431,10 +492,10 @@ function ClickyDownloadMenu({
431
492
  type: "button",
432
493
  role: "menuitem",
433
494
  className: utils.cn(
434
- "flex w-full items-start gap-3 rounded-md px-3 py-2 text-left text-sm transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:outline-none"
495
+ "flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:outline-none"
435
496
  ),
436
497
  onClick: () => {
437
- submitDownloadRequest(buildFormatUrl(url, format));
498
+ triggerDownload(buildDownloadUrl(url, format, label));
438
499
  setOpen(false);
439
500
  },
440
501
  children: [
@@ -442,13 +503,13 @@ function ClickyDownloadMenu({
442
503
  Icon.Icon,
443
504
  {
444
505
  icon: meta.icon,
445
- className: "mt-0.5 shrink-0 text-base text-muted-foreground"
506
+ className: utils.cn(
507
+ "shrink-0 text-sm",
508
+ meta.iconClassName ?? "text-muted-foreground"
509
+ )
446
510
  }
447
511
  ),
448
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
449
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: meta.label }),
450
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-0.5 block text-xs text-muted-foreground", children: meta.description })
451
- ] })
512
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: meta.label }) })
452
513
  ]
453
514
  },
454
515
  format
@@ -503,7 +564,9 @@ function fetchRemoteFormat(url, format) {
503
564
  }
504
565
  }).then(async (response) => {
505
566
  if (!response.ok) {
506
- throw new Error(`Request failed with ${response.status} ${response.statusText}`.trim());
567
+ throw new Error(
568
+ `Request failed with ${response.status} ${response.statusText}`.trim()
569
+ );
507
570
  }
508
571
  const contentType = response.headers.get("Content-Type") ?? "";
509
572
  if (format === "excel") {
@@ -580,16 +643,41 @@ function ClickyPdfPreview({ src }) {
580
643
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-md border border-border bg-background", children: [
581
644
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 py-2 text-xs text-muted-foreground", children: [
582
645
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "PDF preview" }),
583
- /* @__PURE__ */ jsxRuntime.jsx("a", { href: src, target: "_blank", rel: "noreferrer", className: "text-primary hover:underline", children: "Open in new tab" })
646
+ /* @__PURE__ */ jsxRuntime.jsx(
647
+ "a",
648
+ {
649
+ href: src,
650
+ target: "_blank",
651
+ rel: "noreferrer",
652
+ className: "text-primary hover:underline",
653
+ children: "Open in new tab"
654
+ }
655
+ )
584
656
  ] }),
585
- /* @__PURE__ */ jsxRuntime.jsx("iframe", { title: "Clicky PDF preview", src, className: "h-[720px] w-full bg-white" })
657
+ /* @__PURE__ */ jsxRuntime.jsx(
658
+ "iframe",
659
+ {
660
+ title: "Clicky PDF preview",
661
+ src,
662
+ className: "h-[720px] w-full bg-white"
663
+ }
664
+ )
586
665
  ] });
587
666
  }
588
667
  function ClickyHtmlPreview({ src }) {
589
668
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-md border border-border bg-background", children: [
590
669
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 py-2 text-xs text-muted-foreground", children: [
591
670
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "HTML preview" }),
592
- /* @__PURE__ */ jsxRuntime.jsx("a", { href: src, target: "_blank", rel: "noreferrer", className: "text-primary hover:underline", children: "Open in new tab" })
671
+ /* @__PURE__ */ jsxRuntime.jsx(
672
+ "a",
673
+ {
674
+ href: src,
675
+ target: "_blank",
676
+ rel: "noreferrer",
677
+ className: "text-primary hover:underline",
678
+ children: "Open in new tab"
679
+ }
680
+ )
593
681
  ] }),
594
682
  /* @__PURE__ */ jsxRuntime.jsx(
595
683
  "iframe",
@@ -616,7 +704,16 @@ function ClickyUnsupportedPreview({
616
704
  message,
617
705
  " "
618
706
  ] }),
619
- /* @__PURE__ */ jsxRuntime.jsx("a", { href, target: "_blank", rel: "noreferrer", className: "text-primary hover:underline", children: "Open format" })
707
+ /* @__PURE__ */ jsxRuntime.jsx(
708
+ "a",
709
+ {
710
+ href,
711
+ target: "_blank",
712
+ rel: "noreferrer",
713
+ className: "text-primary hover:underline",
714
+ children: "Open format"
715
+ }
716
+ )
620
717
  ] })
621
718
  }
622
719
  );
@@ -638,7 +735,10 @@ function ClickyRemotePreview({
638
735
  }
639
736
  );
640
737
  }
641
- function ClickyTextPreview({ title, content }) {
738
+ function ClickyTextPreview({
739
+ title,
740
+ content
741
+ }) {
642
742
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-md border border-border bg-background", children: [
643
743
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-border px-3 py-2 text-xs text-muted-foreground", children: title }),
644
744
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -651,7 +751,10 @@ function ClickyTextPreview({ title, content }) {
651
751
  )
652
752
  ] });
653
753
  }
654
- function ClickyJsonTree({ value, emptyLabel = "JSON" }) {
754
+ function ClickyJsonTree({
755
+ value,
756
+ emptyLabel = "JSON"
757
+ }) {
655
758
  const roots = react.useMemo(() => buildJsonTree(value), [value]);
656
759
  if (value === void 0) {
657
760
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -729,6 +832,23 @@ function getDownloadFormats({
729
832
  }
730
833
  return [...CLICKY_DOWNLOAD_FORMATS];
731
834
  }
835
+ function getDownloadMenuActions({
836
+ url,
837
+ download
838
+ }) {
839
+ const formats = getDownloadFormats({ url, download });
840
+ if (!url || formats.length === 0) return [];
841
+ return formats.map((format) => {
842
+ const meta = getRemoteFormatMeta(format);
843
+ return {
844
+ id: `download-${format}`,
845
+ label: meta.label,
846
+ icon: meta.icon,
847
+ ...meta.iconClassName ? { iconClassName: meta.iconClassName } : {},
848
+ onSelect: () => triggerDownload(buildDownloadUrl(url, format, download == null ? void 0 : download.label))
849
+ };
850
+ });
851
+ }
732
852
  function getRemoteFormatMeta(format) {
733
853
  switch (format) {
734
854
  case "clicky":
@@ -742,14 +862,15 @@ function getRemoteFormatMeta(format) {
742
862
  return {
743
863
  label: "JSON",
744
864
  description: "Plain JSON for inspecting the raw response body",
745
- icon: UiFileCode.UiFileCode,
865
+ icon: UiJson.UiJson,
746
866
  accept: "application/json, text/plain;q=0.8,*/*;q=0.7"
747
867
  };
748
868
  case "pdf":
749
869
  return {
750
870
  label: "PDF",
751
871
  description: "Portable document for sharing and printing",
752
- icon: UiFileCode.UiFileCode,
872
+ icon: UiFileText.UiFileText,
873
+ iconClassName: "text-rose-600 dark:text-rose-400",
753
874
  accept: "application/pdf, */*;q=0.7"
754
875
  };
755
876
  case "html":
@@ -763,7 +884,7 @@ function getRemoteFormatMeta(format) {
763
884
  return {
764
885
  label: "Markdown",
765
886
  description: "Markdown formatted for docs, comments, and chat",
766
- icon: UiFileCode.UiFileCode,
887
+ icon: UiMarkdown.UiMarkdown,
767
888
  accept: "text/markdown, text/plain;q=0.8,*/*;q=0.7"
768
889
  };
769
890
  case "yaml":
@@ -771,13 +892,15 @@ function getRemoteFormatMeta(format) {
771
892
  label: "YAML",
772
893
  description: "YAML for config-friendly inspection and export",
773
894
  icon: UiFileCode.UiFileCode,
895
+ iconClassName: "text-violet-600 dark:text-violet-400",
774
896
  accept: "application/yaml, text/yaml;q=0.9, text/plain;q=0.8,*/*;q=0.7"
775
897
  };
776
898
  case "csv":
777
899
  return {
778
900
  label: "CSV",
779
901
  description: "Comma-separated values for spreadsheets and imports",
780
- icon: UiTable.UiTable,
902
+ icon: UiFileSpreadsheet.UiFileSpreadsheet,
903
+ iconClassName: "text-emerald-600 dark:text-emerald-400",
781
904
  accept: "text/csv, text/plain;q=0.8,*/*;q=0.7"
782
905
  };
783
906
  case "pretty":
@@ -809,12 +932,66 @@ function formatViewLabel(mode) {
809
932
  function buildFormatUrl(url, format) {
810
933
  const base = typeof window === "undefined" ? "http://localhost" : window.location.origin;
811
934
  const resolved = new URL(url, base);
812
- resolved.searchParams.set("format", format === "clicky" ? "clicky-json" : format);
935
+ resolved.searchParams.set(
936
+ "format",
937
+ format === "clicky" ? "clicky-json" : format
938
+ );
813
939
  if (isAbsoluteUrl(url)) {
814
940
  return resolved.toString();
815
941
  }
816
942
  return `${resolved.pathname}${resolved.search}${resolved.hash}`;
817
943
  }
944
+ function buildDownloadUrl(url, format, label) {
945
+ const formatted = buildFormatUrl(url, format);
946
+ const base = typeof window === "undefined" ? "http://localhost" : window.location.origin;
947
+ const resolved = new URL(formatted, base);
948
+ resolved.searchParams.set("filename", downloadFilename(url, format, label));
949
+ resolved.searchParams.set("_download", Date.now().toString());
950
+ if (isAbsoluteUrl(formatted)) {
951
+ return resolved.toString();
952
+ }
953
+ return `${resolved.pathname}${resolved.search}${resolved.hash}`;
954
+ }
955
+ function downloadFilename(url, format, label) {
956
+ const stem = sanitizeFilenameStem(
957
+ label || filenameStemFromUrl(url) || "clicky-output"
958
+ );
959
+ return `${stem}${downloadExtension(format)}`;
960
+ }
961
+ function filenameStemFromUrl(url) {
962
+ const base = typeof window === "undefined" ? "http://localhost" : window.location.origin;
963
+ const resolved = new URL(url, base);
964
+ const segment = resolved.pathname.split("/").filter(Boolean).at(-1);
965
+ return segment ?? "";
966
+ }
967
+ function sanitizeFilenameStem(value) {
968
+ const cleaned = value.trim().replace(/\.[a-z0-9]+$/i, "").replace(/[^a-z0-9._-]+/gi, "-").replace(/-+/g, "-").replace(/^[._-]+|[._-]+$/g, "");
969
+ return cleaned || "clicky-output";
970
+ }
971
+ function downloadExtension(format) {
972
+ switch (format) {
973
+ case "clicky":
974
+ return ".clicky.json";
975
+ case "json":
976
+ return ".json";
977
+ case "pdf":
978
+ return ".pdf";
979
+ case "html":
980
+ return ".html";
981
+ case "markdown":
982
+ return ".md";
983
+ case "yaml":
984
+ return ".yaml";
985
+ case "csv":
986
+ return ".csv";
987
+ case "pretty":
988
+ return ".txt";
989
+ case "excel":
990
+ return ".xlsx";
991
+ case "slack":
992
+ return ".slack.json";
993
+ }
994
+ }
818
995
  function shouldFetchRemoteView(format) {
819
996
  return format !== "pdf" && format !== "html" && format !== "excel";
820
997
  }
@@ -863,12 +1040,36 @@ function parseJsonValue(data) {
863
1040
  return data;
864
1041
  }
865
1042
  }
1043
+ function clickyPayloadHasTable(data) {
1044
+ if (data === void 0) return false;
1045
+ const parsed = parseClickyData(data);
1046
+ return parsed.ok ? clickyNodeHasTable(parsed.document.node) : false;
1047
+ }
1048
+ function clickyNodeHasTable(node) {
1049
+ var _a, _b, _c, _d;
1050
+ if (!node) return false;
1051
+ if (node.kind === "table") return true;
1052
+ if ((_a = node.children) == null ? void 0 : _a.some(clickyNodeHasTable)) return true;
1053
+ if ((_b = node.items) == null ? void 0 : _b.some(clickyNodeHasTable)) return true;
1054
+ if ((_c = node.fields) == null ? void 0 : _c.some((field) => clickyNodeHasTable(field.value)))
1055
+ return true;
1056
+ if (node.label && clickyNodeHasTable(node.label)) return true;
1057
+ if (node.content && clickyNodeHasTable(node.content)) return true;
1058
+ if (node.tooltip && clickyNodeHasTable(node.tooltip)) return true;
1059
+ if ((_d = node.rows) == null ? void 0 : _d.some((row) => row.detail && clickyNodeHasTable(row.detail)))
1060
+ return true;
1061
+ return false;
1062
+ }
866
1063
  function buildJsonTree(value) {
867
1064
  if (Array.isArray(value)) {
868
- return value.map((entry, index) => buildJsonTreeNode(String(index), entry, `$[${index}]`));
1065
+ return value.map(
1066
+ (entry, index) => buildJsonTreeNode(String(index), entry, `$[${index}]`)
1067
+ );
869
1068
  }
870
1069
  if (isPlainObject(value)) {
871
- return Object.entries(value).map(([key, entry]) => buildJsonTreeNode(key, entry, `$.${key}`));
1070
+ return Object.entries(value).map(
1071
+ ([key, entry]) => buildJsonTreeNode(key, entry, `$.${key}`)
1072
+ );
872
1073
  }
873
1074
  if (value === void 0) {
874
1075
  return [];
@@ -917,15 +1118,23 @@ function summarizeJsonValue(value) {
917
1118
  function isPlainObject(value) {
918
1119
  return value != null && typeof value === "object" && !Array.isArray(value);
919
1120
  }
920
- function submitDownloadRequest(url) {
1121
+ const CLICKY_DOWNLOAD_FRAME_ID = "clicky-download-frame";
1122
+ function triggerDownload(url) {
921
1123
  if (typeof document === "undefined") return;
922
- const form = document.createElement("form");
923
- form.method = "GET";
924
- form.action = url;
925
- form.style.display = "none";
926
- document.body.appendChild(form);
927
- form.submit();
928
- document.body.removeChild(form);
1124
+ let frame = document.getElementById(
1125
+ CLICKY_DOWNLOAD_FRAME_ID
1126
+ );
1127
+ if (!frame) {
1128
+ frame = document.createElement("iframe");
1129
+ frame.id = CLICKY_DOWNLOAD_FRAME_ID;
1130
+ frame.name = CLICKY_DOWNLOAD_FRAME_ID;
1131
+ frame.title = "Clicky download target";
1132
+ frame.setAttribute("aria-hidden", "true");
1133
+ frame.tabIndex = -1;
1134
+ frame.style.display = "none";
1135
+ document.body.appendChild(frame);
1136
+ }
1137
+ frame.src = url;
929
1138
  }
930
1139
  function isAbsoluteUrl(url) {
931
1140
  return /^[a-z][a-z\d+\-.]*:/i.test(url) || url.startsWith("//");
@@ -1018,7 +1227,10 @@ function ClickyComment({ node }) {
1018
1227
  return /* @__PURE__ */ jsxRuntime.jsx(
1019
1228
  "div",
1020
1229
  {
1021
- className: utils.cn("mt-1 text-xs leading-snug text-muted-foreground", (_d = node.style) == null ? void 0 : _d.className),
1230
+ className: utils.cn(
1231
+ "mt-1 text-xs leading-snug text-muted-foreground",
1232
+ (_d = node.style) == null ? void 0 : _d.className
1233
+ ),
1022
1234
  style: inlineStyle,
1023
1235
  title: ((_e = node.tooltip) == null ? void 0 : _e.plain) ?? text,
1024
1236
  children: content
@@ -1220,11 +1432,17 @@ function ClickyCommandDialog({
1220
1432
  setIsExecuting(true);
1221
1433
  setError("");
1222
1434
  try {
1223
- const response = await executeClickyCommand(runtime.commandRuntime.client, operation, values);
1435
+ const response = await executeClickyCommand(
1436
+ runtime.commandRuntime.client,
1437
+ operation,
1438
+ values
1439
+ );
1224
1440
  setResult(response);
1225
1441
  } catch (err) {
1226
1442
  setResult(null);
1227
- setError(err instanceof Error ? err.message : String(err ?? "Unknown error"));
1443
+ setError(
1444
+ err instanceof Error ? err.message : String(err ?? "Unknown error")
1445
+ );
1228
1446
  } finally {
1229
1447
  setIsExecuting(false);
1230
1448
  }
@@ -1247,7 +1465,13 @@ function ClickyCommandDialog({
1247
1465
  operation ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3 text-xs text-muted-foreground", children: [
1248
1466
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-md border border-border bg-muted px-2 py-1 font-medium uppercase", children: operation.method }),
1249
1467
  /* @__PURE__ */ jsxRuntime.jsx("code", { children: operation.path })
1250
- ] }) : runtime.operationsLoading ? /* @__PURE__ */ jsxRuntime.jsx(ClickyNotice, { title: "Loading commands", message: "Resolving the command definition." }) : /* @__PURE__ */ jsxRuntime.jsx(
1468
+ ] }) : runtime.operationsLoading ? /* @__PURE__ */ jsxRuntime.jsx(
1469
+ ClickyNotice,
1470
+ {
1471
+ title: "Loading commands",
1472
+ message: "Resolving the command definition."
1473
+ }
1474
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1251
1475
  ClickyNotice,
1252
1476
  {
1253
1477
  title: "Unknown command",
@@ -1269,7 +1493,14 @@ function ClickyCommandDialog({
1269
1493
  onSubmit: runCommand
1270
1494
  }
1271
1495
  ) }),
1272
- error ? /* @__PURE__ */ jsxRuntime.jsx(ClickyNotice, { title: "Command failed", message: error, tone: "destructive" }) : /* @__PURE__ */ jsxRuntime.jsx(
1496
+ error ? /* @__PURE__ */ jsxRuntime.jsx(
1497
+ ClickyNotice,
1498
+ {
1499
+ title: "Command failed",
1500
+ message: error,
1501
+ tone: "destructive"
1502
+ }
1503
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1273
1504
  ClickyCommandResponse,
1274
1505
  {
1275
1506
  response: result,
@@ -1281,7 +1512,9 @@ function ClickyCommandDialog({
1281
1512
  }
1282
1513
  );
1283
1514
  }
1284
- function ClickyAsyncCommandResult({ resolved }) {
1515
+ function ClickyAsyncCommandResult({
1516
+ resolved
1517
+ }) {
1285
1518
  const runtime = react.useContext(ClickyRuntimeContext);
1286
1519
  const operation = resolved.operation;
1287
1520
  const parameters = (operation == null ? void 0 : operation.operation.parameters) ?? [];
@@ -1303,7 +1536,11 @@ function ClickyAsyncCommandResult({ resolved }) {
1303
1536
  ],
1304
1537
  enabled: runtime.commandRuntime != null && operation != null && missing.length === 0,
1305
1538
  retry: 0,
1306
- queryFn: async () => executeClickyCommand(runtime.commandRuntime.client, operation, initialValues)
1539
+ queryFn: async () => executeClickyCommand(
1540
+ runtime.commandRuntime.client,
1541
+ operation,
1542
+ initialValues
1543
+ )
1307
1544
  });
1308
1545
  if (!runtime.commandRuntime) {
1309
1546
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -1317,7 +1554,13 @@ function ClickyAsyncCommandResult({ resolved }) {
1317
1554
  }
1318
1555
  if (!operation) {
1319
1556
  if (runtime.operationsLoading) {
1320
- return /* @__PURE__ */ jsxRuntime.jsx(ClickyNotice, { title: "Loading commands", message: "Resolving the command definition." });
1557
+ return /* @__PURE__ */ jsxRuntime.jsx(
1558
+ ClickyNotice,
1559
+ {
1560
+ title: "Loading commands",
1561
+ message: "Resolving the command definition."
1562
+ }
1563
+ );
1321
1564
  }
1322
1565
  return /* @__PURE__ */ jsxRuntime.jsx(
1323
1566
  ClickyNotice,
@@ -1339,7 +1582,13 @@ function ClickyAsyncCommandResult({ resolved }) {
1339
1582
  );
1340
1583
  }
1341
1584
  if (query.isPending) {
1342
- return /* @__PURE__ */ jsxRuntime.jsx(ClickyNotice, { title: "Running command", message: "Loading Clicky response…" });
1585
+ return /* @__PURE__ */ jsxRuntime.jsx(
1586
+ ClickyNotice,
1587
+ {
1588
+ title: "Running command",
1589
+ message: "Loading Clicky response…"
1590
+ }
1591
+ );
1343
1592
  }
1344
1593
  if (query.isError) {
1345
1594
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -1351,7 +1600,13 @@ function ClickyAsyncCommandResult({ resolved }) {
1351
1600
  }
1352
1601
  );
1353
1602
  }
1354
- return /* @__PURE__ */ jsxRuntime.jsx(ClickyCommandResponse, { response: query.data, emptyMessage: "No response body returned." });
1603
+ return /* @__PURE__ */ jsxRuntime.jsx(
1604
+ ClickyCommandResponse,
1605
+ {
1606
+ response: query.data,
1607
+ emptyMessage: "No response body returned."
1608
+ }
1609
+ );
1355
1610
  }
1356
1611
  function ClickyCommandResponse({
1357
1612
  response,
@@ -1359,7 +1614,13 @@ function ClickyCommandResponse({
1359
1614
  emptyMessage
1360
1615
  }) {
1361
1616
  if (pending) {
1362
- return /* @__PURE__ */ jsxRuntime.jsx(ClickyNotice, { title: "Running command", message: "Loading Clicky response…" });
1617
+ return /* @__PURE__ */ jsxRuntime.jsx(
1618
+ ClickyNotice,
1619
+ {
1620
+ title: "Running command",
1621
+ message: "Loading Clicky response…"
1622
+ }
1623
+ );
1363
1624
  }
1364
1625
  if (!response) {
1365
1626
  return /* @__PURE__ */ jsxRuntime.jsx(ClickyNotice, { title: "No response", message: emptyMessage });
@@ -1379,7 +1640,15 @@ function ClickyCommandResponse({
1379
1640
  function ClickyIconNode({ node }) {
1380
1641
  var _a;
1381
1642
  const inlineStyle = toInlineStyle(node.style, node.plain ?? node.unicode);
1382
- return /* @__PURE__ */ jsxRuntime.jsx("span", { style: inlineStyle, title: (_a = node.tooltip) == null ? void 0 : _a.plain, className: "inline-flex items-center", children: node.iconify ? /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { name: node.iconify }) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: node.unicode ?? node.plain }) });
1643
+ return /* @__PURE__ */ jsxRuntime.jsx(
1644
+ "span",
1645
+ {
1646
+ style: inlineStyle,
1647
+ title: (_a = node.tooltip) == null ? void 0 : _a.plain,
1648
+ className: "inline-flex items-center",
1649
+ children: node.iconify ? /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { name: node.iconify }) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: node.unicode ?? node.plain })
1650
+ }
1651
+ );
1383
1652
  }
1384
1653
  function ClickyList({ node }) {
1385
1654
  const items = node.items ?? [];
@@ -1412,7 +1681,10 @@ function ClickyList({ node }) {
1412
1681
  return /* @__PURE__ */ jsxRuntime.jsx(Tag, { className: utils.cn("ml-5 space-y-1 text-sm", listClass), children: items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(ClickyNodeRenderer, { node: item }) }, index)) });
1413
1682
  }
1414
1683
  function ClickyMap({ node }) {
1415
- const fields = node.fields ?? [];
1684
+ const runtime = react.useContext(ClickyRuntimeContext);
1685
+ const fields = (node.fields ?? []).filter(
1686
+ (field) => !(runtime.tablePagination && isPaginationMetadataField(field))
1687
+ );
1416
1688
  if (fields.length === 0) return null;
1417
1689
  const inlineFields = fields.filter((field) => isInlineNode(field.value));
1418
1690
  const blockFields = fields.filter((field) => !isInlineNode(field.value));
@@ -1427,6 +1699,14 @@ function ClickyMap({ node }) {
1427
1699
  ] }, field.name))
1428
1700
  ] });
1429
1701
  }
1702
+ function isPaginationMetadataField(field) {
1703
+ const name = (field.label || field.name || "").toLowerCase();
1704
+ if (name !== "page" || field.value.kind !== "map") return false;
1705
+ const keys = new Set(
1706
+ (field.value.fields ?? []).map((item) => item.name.toLowerCase())
1707
+ );
1708
+ return keys.has("limit") && keys.has("offset") && keys.has("total");
1709
+ }
1430
1710
  function ClickyTableNode({ node }) {
1431
1711
  return /* @__PURE__ */ jsxRuntime.jsx(
1432
1712
  ClickyTable,
@@ -1447,7 +1727,8 @@ function ClickyTable({
1447
1727
  search,
1448
1728
  timeRange,
1449
1729
  externalFilters,
1450
- pagination
1730
+ pagination,
1731
+ menuActions
1451
1732
  }) {
1452
1733
  const runtime = react.useContext(ClickyRuntimeContext);
1453
1734
  const rowClick = onTableRowClick ?? runtime.onTableRowClick;
@@ -1457,6 +1738,7 @@ function ClickyTable({
1457
1738
  const effectiveTimeRange = timeRange ?? runtime.tableTimeRange;
1458
1739
  const effectiveExternalFilters = externalFilters ?? runtime.tableExternalFilters;
1459
1740
  const effectivePagination = pagination ?? runtime.tablePagination;
1741
+ const effectiveMenuActions = menuActions ?? runtime.tableMenuActions;
1460
1742
  if (columns.length === 0 || rows.length === 0) {
1461
1743
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-muted-foreground", children: "No data" });
1462
1744
  }
@@ -1517,7 +1799,8 @@ function ClickyTable({
1517
1799
  ...effectiveSearch ? { externalSearch: effectiveSearch } : {},
1518
1800
  ...effectiveTimeRange ? { externalTimeRange: effectiveTimeRange } : {},
1519
1801
  ...effectiveExternalFilters ? { externalFilters: effectiveExternalFilters } : {},
1520
- ...effectivePagination ? { pagination: effectivePagination } : {}
1802
+ ...effectivePagination ? { pagination: effectivePagination } : {},
1803
+ ...effectiveMenuActions ? { menuActions: effectiveMenuActions } : {}
1521
1804
  }
1522
1805
  );
1523
1806
  }
@@ -1536,7 +1819,14 @@ function ClickyTableRowDetail({
1536
1819
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Tags" }),
1537
1820
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-2", children: tagFields.map(({ column, tags, tableKey }) => {
1538
1821
  const tagActions = context.filterActionsByColumn[tableKey];
1539
- const content = /* @__PURE__ */ jsxRuntime.jsx(TagList.TagList, { tags, maxVisible: tags.length, actions: "inline" });
1822
+ const content = /* @__PURE__ */ jsxRuntime.jsx(
1823
+ TagList.TagList,
1824
+ {
1825
+ tags,
1826
+ maxVisible: tags.length,
1827
+ actions: "inline"
1828
+ }
1829
+ );
1540
1830
  return /* @__PURE__ */ jsxRuntime.jsxs(
1541
1831
  "div",
1542
1832
  {
@@ -1552,10 +1842,17 @@ function ClickyTableRowDetail({
1552
1842
  ] }),
1553
1843
  /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-2", children: [
1554
1844
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Fields" }),
1555
- /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "grid gap-2 md:grid-cols-2", children: columns.map((column) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md border border-border bg-background p-2", children: [
1556
- /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: column.label || prettifyName(column.name) }),
1557
- /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "mt-1 min-w-0 text-sm text-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(ClickyNodeRenderer, { node: row.cells[column.name] }) })
1558
- ] }, column.name)) })
1845
+ /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "grid gap-2 md:grid-cols-2", children: columns.map((column) => /* @__PURE__ */ jsxRuntime.jsxs(
1846
+ "div",
1847
+ {
1848
+ className: "rounded-md border border-border bg-background p-2",
1849
+ children: [
1850
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: column.label || prettifyName(column.name) }),
1851
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "mt-1 min-w-0 text-sm text-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(ClickyNodeRenderer, { node: row.cells[column.name] }) })
1852
+ ]
1853
+ },
1854
+ column.name
1855
+ )) })
1559
1856
  ] }),
1560
1857
  row.detail && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-2", children: [
1561
1858
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Detail" }),
@@ -1696,7 +1993,9 @@ function findFieldText(node, preferredName) {
1696
1993
  return "";
1697
1994
  }
1698
1995
  function hasMeaningfulText(node) {
1699
- return Boolean(clickyNodeText(node).trim() || ((node == null ? void 0 : node.fields) ?? []).length > 0);
1996
+ return Boolean(
1997
+ clickyNodeText(node).trim() || ((node == null ? void 0 : node.fields) ?? []).length > 0
1998
+ );
1700
1999
  }
1701
2000
  function normalizeFieldName(name) {
1702
2001
  return name.toLowerCase().replace(/[^a-z0-9]/g, "");
@@ -1786,17 +2085,20 @@ function ClickyHtmlNode({ node }) {
1786
2085
  return /* @__PURE__ */ jsxRuntime.jsx(Tag, { dangerouslySetInnerHTML: { __html: sanitized } });
1787
2086
  }
1788
2087
  function toInlineStyle(style, text) {
1789
- if (!style) return (text == null ? void 0 : text.includes("\n")) ? { whiteSpace: "pre-wrap" } : void 0;
2088
+ if (!style)
2089
+ return (text == null ? void 0 : text.includes("\n")) ? { whiteSpace: "pre-wrap" } : void 0;
1790
2090
  const inlineStyle = {};
1791
2091
  if (style.color) inlineStyle.color = style.color;
1792
- if (style.backgroundColor) inlineStyle.backgroundColor = style.backgroundColor;
2092
+ if (style.backgroundColor)
2093
+ inlineStyle.backgroundColor = style.backgroundColor;
1793
2094
  if (style.bold) inlineStyle.fontWeight = 700;
1794
2095
  if (style.faint) inlineStyle.opacity = 0.7;
1795
2096
  if (style.italic) inlineStyle.fontStyle = "italic";
1796
2097
  const decorations = [];
1797
2098
  if (style.underline) decorations.push("underline");
1798
2099
  if (style.strikethrough) decorations.push("line-through");
1799
- if (decorations.length > 0) inlineStyle.textDecoration = decorations.join(" ");
2100
+ if (decorations.length > 0)
2101
+ inlineStyle.textDecoration = decorations.join(" ");
1800
2102
  if (style.textTransform === "uppercase" || style.textTransform === "lowercase" || style.textTransform === "capitalize") {
1801
2103
  inlineStyle.textTransform = style.textTransform;
1802
2104
  }
@@ -1847,11 +2149,15 @@ function defaultResolveClickyCommand(request, operations) {
1847
2149
  if (!wanted) return void 0;
1848
2150
  return operations.find((operation) => {
1849
2151
  var _a, _b;
1850
- const metaCommand = normalizeCommandPath((_a = operation.operation["x-clicky"]) == null ? void 0 : _a.command);
2152
+ const metaCommand = normalizeCommandPath(
2153
+ (_a = operation.operation["x-clicky"]) == null ? void 0 : _a.command
2154
+ );
1851
2155
  if (metaCommand && metaCommand === wanted) {
1852
2156
  return true;
1853
2157
  }
1854
- const operationId = normalizeCommandPath((_b = operation.operation.operationId) == null ? void 0 : _b.replaceAll("_", "/"));
2158
+ const operationId = normalizeCommandPath(
2159
+ (_b = operation.operation.operationId) == null ? void 0 : _b.replaceAll("_", "/")
2160
+ );
1855
2161
  return operationId === wanted;
1856
2162
  });
1857
2163
  }
@@ -1861,7 +2167,9 @@ function normalizeCommandPath(value) {
1861
2167
  function buildCommandParameterValues(parameters, request) {
1862
2168
  const values = { ...request.flags };
1863
2169
  const args = [...request.args ?? []];
1864
- const positionalParams = parameters.filter((param) => types.isPositionalParam(param));
2170
+ const positionalParams = parameters.filter(
2171
+ (param) => types.isPositionalParam(param)
2172
+ );
1865
2173
  let argIndex = 0;
1866
2174
  for (const param of positionalParams) {
1867
2175
  if (param.name === "args") {
@@ -1880,13 +2188,18 @@ function buildCommandParameterValues(parameters, request) {
1880
2188
  return values;
1881
2189
  }
1882
2190
  function missingRequiredParameters(parameters, values) {
1883
- return parameters.filter((param) => param.required && (values[param.name] ?? "").trim() === "");
2191
+ return parameters.filter(
2192
+ (param) => param.required && (values[param.name] ?? "").trim() === ""
2193
+ );
1884
2194
  }
1885
2195
  async function executeClickyCommand(client, operation, values) {
1886
2196
  return client.executeCommand(
1887
2197
  operation.path,
1888
2198
  operation.method,
1889
- formMetadata.packParameterValues(formMetadata.pruneParameterValues(values), operation.operation.parameters ?? []),
2199
+ formMetadata.packParameterValues(
2200
+ formMetadata.pruneParameterValues(values),
2201
+ operation.operation.parameters ?? []
2202
+ ),
1890
2203
  { Accept: "application/json+clicky" }
1891
2204
  );
1892
2205
  }
@@ -1914,7 +2227,10 @@ function substituteOperationPath(path, params) {
1914
2227
  const remaining = { ...params };
1915
2228
  for (const [key, value] of Object.entries(params)) {
1916
2229
  if (url.pathname.includes(`{${key}}`)) {
1917
- url.pathname = url.pathname.replace(`{${key}}`, encodeURIComponent(value));
2230
+ url.pathname = url.pathname.replace(
2231
+ `{${key}}`,
2232
+ encodeURIComponent(value)
2233
+ );
1918
2234
  delete remaining[key];
1919
2235
  }
1920
2236
  }
@@ -1944,14 +2260,20 @@ function clickyNodeText(node) {
1944
2260
  return htmlUtils.sanitizeHtml(node.html ?? "").replace(/<[^>]+>/g, " ").trim();
1945
2261
  if (node.kind === "code") return node.source ?? "";
1946
2262
  if ((node.kind === "link" || node.kind === "link-command") && ((_a = node.children) == null ? void 0 : _a.length)) {
1947
- return [node.text, ...node.children.map((child) => clickyNodeText(child))].join("");
2263
+ return [
2264
+ node.text,
2265
+ ...node.children.map((child) => clickyNodeText(child))
2266
+ ].join("");
1948
2267
  }
1949
2268
  if (node.kind === "button" && node.label) return clickyNodeText(node.label);
1950
2269
  if (node.kind === "button-group") {
1951
2270
  return (node.items ?? []).map((item) => clickyNodeText(item)).join(" ");
1952
2271
  }
1953
2272
  if (node.kind === "text" && ((_b = node.children) == null ? void 0 : _b.length)) {
1954
- return [node.text, ...node.children.map((child) => clickyNodeText(child))].join("");
2273
+ return [
2274
+ node.text,
2275
+ ...node.children.map((child) => clickyNodeText(child))
2276
+ ].join("");
1955
2277
  }
1956
2278
  return "";
1957
2279
  }