dishui 0.0.91 → 0.0.101

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 (156) hide show
  1. package/dist/.release-verified.json +6 -0
  2. package/dist/ai.js +24 -0
  3. package/dist/components/Card/Metric2.js +11 -11
  4. package/dist/components/Card/Metric2.js.map +1 -1
  5. package/dist/components/Card/Ticket.d.ts +52 -0
  6. package/dist/components/Card/Ticket2.js +218 -0
  7. package/dist/components/Card/Ticket2.js.map +1 -0
  8. package/dist/components/Card/index.d.ts +32 -0
  9. package/dist/components/Card/index.js +211 -203
  10. package/dist/components/Card/index.js.map +1 -1
  11. package/dist/components/GroupButton/index.js +4 -4
  12. package/dist/components/GroupButton/index.js.map +1 -1
  13. package/dist/components/GroupedTable/index.js +10 -10
  14. package/dist/components/GroupedTable/index.js.map +1 -1
  15. package/dist/components/NavigationList/index.js +9 -9
  16. package/dist/components/NavigationList/index.js.map +1 -1
  17. package/dist/components/Section/index.js +11 -11
  18. package/dist/components/Section/index.js.map +1 -1
  19. package/dist/components/Skeleton/index.js +1 -1
  20. package/dist/components/Skeleton/index.js.map +1 -1
  21. package/dist/components/Table/index.js +6 -6
  22. package/dist/components/Table/index.js.map +1 -1
  23. package/dist/components/ai/AgentChat/index.d.ts +54 -0
  24. package/dist/components/ai/AgentChat/index.js +176 -0
  25. package/dist/components/ai/AgentChat/index.js.map +1 -0
  26. package/dist/components/ai/AgentRunCard/index.d.ts +38 -0
  27. package/dist/components/ai/AgentRunCard/index.js +100 -0
  28. package/dist/components/ai/AgentRunCard/index.js.map +1 -0
  29. package/dist/components/ai/AgentScreen/index.d.ts +50 -0
  30. package/dist/components/ai/AgentScreen/index.js +233 -0
  31. package/dist/components/ai/AgentScreen/index.js.map +1 -0
  32. package/dist/components/ai/ApprovalCard/index.d.ts +26 -0
  33. package/dist/components/ai/ApprovalCard/index.js +89 -0
  34. package/dist/components/ai/ApprovalCard/index.js.map +1 -0
  35. package/dist/components/ai/CodeView/index.d.ts +30 -0
  36. package/dist/components/ai/CodeView/index.js +149 -0
  37. package/dist/components/ai/CodeView/index.js.map +1 -0
  38. package/dist/components/ai/CommandSearch/index.d.ts +39 -0
  39. package/dist/components/ai/CommandSearch/index.js +217 -0
  40. package/dist/components/ai/CommandSearch/index.js.map +1 -0
  41. package/dist/components/ai/ContextCards/index.d.ts +42 -0
  42. package/dist/components/ai/ContextCards/index.js +106 -0
  43. package/dist/components/ai/ContextCards/index.js.map +1 -0
  44. package/dist/components/ai/DiffTable/index.d.ts +70 -0
  45. package/dist/components/ai/DiffTable/index.js +235 -0
  46. package/dist/components/ai/DiffTable/index.js.map +1 -0
  47. package/dist/components/ai/FilterTable/index.d.ts +35 -0
  48. package/dist/components/ai/FilterTable/index.js +86 -0
  49. package/dist/components/ai/FilterTable/index.js.map +1 -0
  50. package/dist/components/ai/FineTuneCard/index.d.ts +24 -0
  51. package/dist/components/ai/FineTuneCard/index.js +75 -0
  52. package/dist/components/ai/FineTuneCard/index.js.map +1 -0
  53. package/dist/components/ai/InsightCards/index.d.ts +23 -0
  54. package/dist/components/ai/InsightCards/index.js +64 -0
  55. package/dist/components/ai/InsightCards/index.js.map +1 -0
  56. package/dist/components/ai/IssueCard/index.d.ts +39 -0
  57. package/dist/components/ai/IssueCard/index.js +78 -0
  58. package/dist/components/ai/IssueCard/index.js.map +1 -0
  59. package/dist/components/ai/LoadingState/index.d.ts +22 -0
  60. package/dist/components/ai/LoadingState/index.js +80 -0
  61. package/dist/components/ai/LoadingState/index.js.map +1 -0
  62. package/dist/components/ai/PromptBar/index.d.ts +26 -0
  63. package/dist/components/ai/PromptBar/index.js +117 -0
  64. package/dist/components/ai/PromptBar/index.js.map +1 -0
  65. package/dist/components/ai/RecommendationCard/index.d.ts +44 -0
  66. package/dist/components/ai/RecommendationCard/index.js +142 -0
  67. package/dist/components/ai/RecommendationCard/index.js.map +1 -0
  68. package/dist/components/ai/RecordsTable/index.d.ts +65 -0
  69. package/dist/components/ai/RecordsTable/index.js +334 -0
  70. package/dist/components/ai/RecordsTable/index.js.map +1 -0
  71. package/dist/components/ai/SelectionActions/index.d.ts +19 -0
  72. package/dist/components/ai/SelectionActions/index.js +40 -0
  73. package/dist/components/ai/SelectionActions/index.js.map +1 -0
  74. package/dist/components/ai/StateFlow/index.d.ts +24 -0
  75. package/dist/components/ai/StateFlow/index.js +50 -0
  76. package/dist/components/ai/StateFlow/index.js.map +1 -0
  77. package/dist/components/ai/StreamingText/index.d.ts +44 -0
  78. package/dist/components/ai/StreamingText/index.js +211 -0
  79. package/dist/components/ai/StreamingText/index.js.map +1 -0
  80. package/dist/components/ai/TaskRows/index.d.ts +53 -0
  81. package/dist/components/ai/TaskRows/index.js +186 -0
  82. package/dist/components/ai/TaskRows/index.js.map +1 -0
  83. package/dist/components/ai/Thinking/index.d.ts +47 -0
  84. package/dist/components/ai/Thinking/index.js +197 -0
  85. package/dist/components/ai/Thinking/index.js.map +1 -0
  86. package/dist/components/ai/ToolChips/index.d.ts +21 -0
  87. package/dist/components/ai/ToolChips/index.js +63 -0
  88. package/dist/components/ai/ToolChips/index.js.map +1 -0
  89. package/dist/components/ai/index.d.ts +54 -0
  90. package/dist/components/ai/shared.d.ts +13 -0
  91. package/dist/components/ai/shared.js +25 -0
  92. package/dist/components/ai/shared.js.map +1 -0
  93. package/dist/components/pro/DataTable/rowDetailExtension.js +1 -1
  94. package/dist/components/pro/DataTable/rowDetailExtension.js.map +1 -1
  95. package/dist/components/pro/Flow/constants.js +3 -3
  96. package/dist/components/pro/Flow/constants.js.map +1 -1
  97. package/dist/components/pro/Flow/nodes/shapes.js +3 -3
  98. package/dist/components/pro/Flow/nodes/shapes.js.map +1 -1
  99. package/dist/components/pro/Flow/utils/themeColor.d.ts +2 -2
  100. package/dist/components/pro/Flow/utils/themeColor.js +2 -2
  101. package/dist/components/pro/Flow/utils/themeColor.js.map +1 -1
  102. package/dist/components/pro/Kanban/Kanban.d.ts +3 -0
  103. package/dist/components/pro/Kanban/Kanban.js +339 -0
  104. package/dist/components/pro/Kanban/Kanban.js.map +1 -0
  105. package/dist/components/pro/Kanban/Swimlanes.d.ts +3 -0
  106. package/dist/components/pro/Kanban/Swimlanes.js +60 -0
  107. package/dist/components/pro/Kanban/Swimlanes.js.map +1 -0
  108. package/dist/components/pro/Kanban/index.d.ts +5 -0
  109. package/dist/components/pro/Kanban/types.d.ts +103 -0
  110. package/dist/components/pro/Kanban/useKanbanDrag.d.ts +17 -0
  111. package/dist/components/pro/Kanban/useKanbanDrag.js +69 -0
  112. package/dist/components/pro/Kanban/useKanbanDrag.js.map +1 -0
  113. package/dist/components/pro/Kanban/utils.d.ts +13 -0
  114. package/dist/components/pro/Kanban/utils.js +48 -0
  115. package/dist/components/pro/Kanban/utils.js.map +1 -0
  116. package/dist/components/pro/RichTextEditor/AIRewrite.js +158 -127
  117. package/dist/components/pro/RichTextEditor/AIRewrite.js.map +1 -1
  118. package/dist/components/pro/RichTextEditor/BlockHandle.d.ts +2 -0
  119. package/dist/components/pro/RichTextEditor/BlockHandle.js +156 -115
  120. package/dist/components/pro/RichTextEditor/BlockHandle.js.map +1 -1
  121. package/dist/components/pro/RichTextEditor/RichTextEditor.js +136 -159
  122. package/dist/components/pro/RichTextEditor/RichTextEditor.js.map +1 -1
  123. package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js +44 -41
  124. package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js.map +1 -1
  125. package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js +59 -53
  126. package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js.map +1 -1
  127. package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js +48 -44
  128. package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js.map +1 -1
  129. package/dist/components/pro/RichTextEditor/Toolbar/TableOpsMenu.js +67 -63
  130. package/dist/components/pro/RichTextEditor/Toolbar/TableOpsMenu.js.map +1 -1
  131. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.d.ts +1 -0
  132. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js +182 -129
  133. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js.map +1 -1
  134. package/dist/components/pro/RichTextEditor/Toolbar/ToolbarButton.d.ts +1 -0
  135. package/dist/components/pro/RichTextEditor/Toolbar/ToolbarButton.js +3 -3
  136. package/dist/components/pro/RichTextEditor/Toolbar/ToolbarButton.js.map +1 -1
  137. package/dist/components/pro/RichTextEditor/Toolbar/useAnchoredDropdown.d.ts +3 -0
  138. package/dist/components/pro/RichTextEditor/Toolbar/useAnchoredDropdown.js +31 -0
  139. package/dist/components/pro/RichTextEditor/Toolbar/useAnchoredDropdown.js.map +1 -0
  140. package/dist/components/pro/RichTextEditor/index.d.ts +1 -1
  141. package/dist/components/pro/RichTextEditor/types.d.ts +78 -11
  142. package/dist/components/pro/RichTextEditor/types.js +11 -0
  143. package/dist/components/pro/RichTextEditor/types.js.map +1 -1
  144. package/dist/dishui.css +1 -1
  145. package/dist/index-nostyled.d.ts +1 -1
  146. package/dist/index.d.ts +6 -3
  147. package/dist/index.js +134 -107
  148. package/dist/kanban.js +5 -0
  149. package/dist/layouts/Sidebar.d.ts +16 -0
  150. package/dist/layouts/Sidebar.js +85 -52
  151. package/dist/layouts/Sidebar.js.map +1 -1
  152. package/dist/utils/i18n.js +20 -0
  153. package/dist/utils/i18n.js.map +1 -1
  154. package/dist/utils/menu.js +1 -1
  155. package/dist/utils/menu.js.map +1 -1
  156. package/package.json +14 -3
@@ -0,0 +1,235 @@
1
+ import { cn as e } from "../../../utils/cn.js";
2
+ import t from "../../Button/index.js";
3
+ /* empty css */
4
+ import { useEffect as n, useMemo as r, useState as i, useSyncExternalStore as a } from "react";
5
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
6
+ //#region src/components/ai/DiffTable/index.tsx
7
+ var c = {
8
+ added: "Added",
9
+ removed: "Removed",
10
+ modified: "Changed",
11
+ unchanged: "—",
12
+ acceptAll: "Accept all",
13
+ rejectAll: "Reject all",
14
+ accept: "Accept",
15
+ reject: "Reject",
16
+ accepted: "Accepted",
17
+ rejected: "Rejected",
18
+ status: "Status",
19
+ actions: "Actions",
20
+ empty: "∅"
21
+ };
22
+ function l(e) {
23
+ return typeof e == "object" && !!e;
24
+ }
25
+ function u(e) {
26
+ return e.change ? e.change : Object.values(e.cells).some(l) ? "modified" : void 0;
27
+ }
28
+ function d(e) {
29
+ let t = e.change;
30
+ return t === "added" || t === "removed" ? 1 : Object.values(e.cells).filter(l).length;
31
+ }
32
+ var f = (e, t) => `${e} ${t}${e === 1 ? "" : "s"}`, p = "(prefers-reduced-motion: reduce)", m = (e) => {
33
+ if (typeof window > "u" || !window.matchMedia) return () => {};
34
+ let t = window.matchMedia(p);
35
+ return t.addEventListener("change", e), () => t.removeEventListener("change", e);
36
+ }, h = () => typeof window < "u" && !!window.matchMedia && window.matchMedia(p).matches, g = () => a(m, h, () => !1), _ = () => /* @__PURE__ */ o("svg", {
37
+ width: "14",
38
+ height: "14",
39
+ viewBox: "0 0 24 24",
40
+ fill: "none",
41
+ stroke: "currentColor",
42
+ strokeWidth: "2",
43
+ strokeLinecap: "round",
44
+ strokeLinejoin: "round",
45
+ "aria-hidden": "true",
46
+ children: /* @__PURE__ */ o("path", { d: "M20 6 9 17l-5-5" })
47
+ }), v = () => /* @__PURE__ */ o("svg", {
48
+ width: "14",
49
+ height: "14",
50
+ viewBox: "0 0 24 24",
51
+ fill: "none",
52
+ stroke: "currentColor",
53
+ strokeWidth: "2",
54
+ strokeLinecap: "round",
55
+ strokeLinejoin: "round",
56
+ "aria-hidden": "true",
57
+ children: /* @__PURE__ */ o("path", { d: "M18 6 6 18M6 6l12 12" })
58
+ }), y = (e, t) => e == null || e === "" ? /* @__PURE__ */ o("span", {
59
+ className: "dishui-ai-diff-table__empty",
60
+ children: t
61
+ }) : String(e);
62
+ function b({ columns: a, rows: p, title: m, summary: h, sweeping: b = !1, sweepIntervalMs: x = 220, onAcceptAll: S, onRejectAll: C, onAcceptRow: w, onRejectRow: T, decisions: E, dense: D = !1, labels: O, className: k, ...A }) {
63
+ let j = {
64
+ ...c,
65
+ ...O
66
+ }, M = r(() => p.filter((e) => u(e)).map((e) => e.id), [p]), N = r(() => p.reduce((e, t) => e + d(t), 0), [p]), P = g(), F = b && !P, [I, L] = i(0);
67
+ n(() => {
68
+ if (!F) return;
69
+ let e = M.length, t = window.setInterval(() => {
70
+ L((n) => (n + 1 >= e && window.clearInterval(t), Math.min(n + 1, e)));
71
+ }, Math.max(16, x));
72
+ return () => {
73
+ window.clearInterval(t), L(0);
74
+ };
75
+ }, [
76
+ F,
77
+ x,
78
+ M.length
79
+ ]);
80
+ let R = r(() => F ? new Set(M.slice(0, I)) : null, [
81
+ F,
82
+ M,
83
+ I
84
+ ]), z = !F || I >= M.length, B = !!(w || T), V = !!(S || C), H = `${f(N, "change")} across ${f(M.length, "row")}`;
85
+ return /* @__PURE__ */ s("div", {
86
+ ...A,
87
+ className: e("dishui-ai-diff-table", D && "dishui-ai-diff-table--dense", F && !z && "dishui-ai-diff-table--sweeping", k),
88
+ children: [
89
+ (m || h !== null) && /* @__PURE__ */ s("div", {
90
+ className: "dishui-ai-diff-table__header",
91
+ children: [m && /* @__PURE__ */ o("div", {
92
+ className: "dishui-ai-diff-table__title",
93
+ children: m
94
+ }), /* @__PURE__ */ o("div", {
95
+ className: "dishui-ai-diff-table__summary",
96
+ "aria-live": "polite",
97
+ children: h ?? H
98
+ })]
99
+ }),
100
+ /* @__PURE__ */ o("div", {
101
+ className: "dishui-ai-diff-table__scroll",
102
+ children: /* @__PURE__ */ s("table", {
103
+ className: "dishui-ai-diff-table__table",
104
+ children: [/* @__PURE__ */ o("thead", { children: /* @__PURE__ */ s("tr", { children: [
105
+ /* @__PURE__ */ o("th", {
106
+ scope: "col",
107
+ className: "dishui-ai-diff-table__th dishui-ai-diff-table__th--status",
108
+ children: j.status
109
+ }),
110
+ a.map((t) => /* @__PURE__ */ o("th", {
111
+ scope: "col",
112
+ className: e("dishui-ai-diff-table__th", t.align === "right" && "dishui-ai-diff-table__th--right"),
113
+ children: t.label
114
+ }, t.key)),
115
+ B && /* @__PURE__ */ o("th", {
116
+ scope: "col",
117
+ className: "dishui-ai-diff-table__th dishui-ai-diff-table__th--actions",
118
+ children: /* @__PURE__ */ o("span", {
119
+ className: "dishui-ai-diff-table__sr",
120
+ children: j.actions
121
+ })
122
+ })
123
+ ] }) }), /* @__PURE__ */ o("tbody", { children: p.map((t) => {
124
+ let n = u(t), r = !n || !R || R.has(t.id), i = E?.[t.id];
125
+ return /* @__PURE__ */ s("tr", {
126
+ className: e("dishui-ai-diff-table__row", n && `dishui-ai-diff-table__row--${n}`, n && r && "dishui-ai-diff-table__row--revealed", i && `dishui-ai-diff-table__row--${i}`),
127
+ "data-change": n,
128
+ children: [
129
+ /* @__PURE__ */ o("td", {
130
+ className: "dishui-ai-diff-table__td dishui-ai-diff-table__td--status",
131
+ children: n && r ? /* @__PURE__ */ o("span", {
132
+ className: e("dishui-ai-diff-table__badge", `dishui-ai-diff-table__badge--${n}`),
133
+ children: j[n]
134
+ }) : /* @__PURE__ */ o("span", {
135
+ className: "dishui-ai-diff-table__badge dishui-ai-diff-table__badge--none",
136
+ "aria-hidden": "true",
137
+ children: j.unchanged
138
+ })
139
+ }),
140
+ a.map((i) => {
141
+ let a = t.cells[i.key], c = r && l(a), u = e("dishui-ai-diff-table__td", i.align === "right" && "dishui-ai-diff-table__td--right", i.mono && "dishui-ai-diff-table__td--mono", c && "dishui-ai-diff-table__td--changed");
142
+ return l(a) ? r ? /* @__PURE__ */ o("td", {
143
+ className: u,
144
+ children: /* @__PURE__ */ s("span", {
145
+ className: "dishui-ai-diff-table__change",
146
+ children: [
147
+ /* @__PURE__ */ o("del", {
148
+ className: "dishui-ai-diff-table__before",
149
+ children: y(a.before, j.empty)
150
+ }),
151
+ /* @__PURE__ */ o("span", {
152
+ className: "dishui-ai-diff-table__arrow",
153
+ "aria-hidden": "true",
154
+ children: "→"
155
+ }),
156
+ /* @__PURE__ */ o("ins", {
157
+ className: "dishui-ai-diff-table__after",
158
+ children: y(a.after, j.empty)
159
+ })
160
+ ]
161
+ })
162
+ }, i.key) : /* @__PURE__ */ o("td", {
163
+ className: u,
164
+ children: y(a.before, j.empty)
165
+ }, i.key) : /* @__PURE__ */ o("td", {
166
+ className: u,
167
+ children: n === "removed" && r ? /* @__PURE__ */ o("del", {
168
+ className: "dishui-ai-diff-table__before",
169
+ children: y(a, j.empty)
170
+ }) : n === "added" && r ? /* @__PURE__ */ o("ins", {
171
+ className: "dishui-ai-diff-table__after",
172
+ children: y(a, j.empty)
173
+ }) : y(a, j.empty)
174
+ }, i.key);
175
+ }),
176
+ B && /* @__PURE__ */ o("td", {
177
+ className: "dishui-ai-diff-table__td dishui-ai-diff-table__td--actions",
178
+ children: n && r && (i ? /* @__PURE__ */ s("span", {
179
+ className: e("dishui-ai-diff-table__decision", `dishui-ai-diff-table__decision--${i}`),
180
+ children: [o(i === "accepted" ? _ : v, {}), j[i]]
181
+ }) : /* @__PURE__ */ s("span", {
182
+ className: "dishui-ai-diff-table__row-actions",
183
+ children: [w && /* @__PURE__ */ o("button", {
184
+ type: "button",
185
+ className: "dishui-ai-diff-table__icon-btn",
186
+ "aria-label": j.accept,
187
+ title: j.accept,
188
+ onClick: () => w(t),
189
+ children: /* @__PURE__ */ o(_, {})
190
+ }), T && /* @__PURE__ */ o("button", {
191
+ type: "button",
192
+ className: "dishui-ai-diff-table__icon-btn",
193
+ "aria-label": j.reject,
194
+ title: j.reject,
195
+ onClick: () => T(t),
196
+ children: /* @__PURE__ */ o(v, {})
197
+ })]
198
+ }))
199
+ })
200
+ ]
201
+ }, t.id);
202
+ }) })]
203
+ })
204
+ }),
205
+ V && /* @__PURE__ */ s("div", {
206
+ className: "dishui-ai-diff-table__footer",
207
+ children: [/* @__PURE__ */ o("span", {
208
+ className: "dishui-ai-diff-table__footer-meta",
209
+ children: z ? H : "Reviewing…"
210
+ }), /* @__PURE__ */ s("span", {
211
+ className: "dishui-ai-diff-table__footer-actions",
212
+ children: [C && /* @__PURE__ */ o(t, {
213
+ type: "button",
214
+ variant: "secondary",
215
+ size: "sm",
216
+ onClick: C,
217
+ disabled: !z,
218
+ children: j.rejectAll
219
+ }), S && /* @__PURE__ */ o(t, {
220
+ type: "button",
221
+ variant: "primary",
222
+ size: "sm",
223
+ onClick: S,
224
+ disabled: !z,
225
+ children: j.acceptAll
226
+ })]
227
+ })]
228
+ })
229
+ ]
230
+ });
231
+ }
232
+ //#endregion
233
+ export { b as default, u as diffRowChange, l as isDiffCellChange };
234
+
235
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/DiffTable/index.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useState, useSyncExternalStore } from 'react';\nimport { cn } from '../../../utils/cn';\nimport Button from '../../Button';\nimport './DiffTable.css';\n\nexport type DiffTableColumn = {\n key: string;\n label: React.ReactNode;\n align?: 'left' | 'right';\n /** Render the cell in the mono font (IDs, SKUs). */\n mono?: boolean;\n};\n\nexport type DiffCellValue = string | number | null;\n\n/** A plain value is unchanged; an object describes a `before → after` edit. */\nexport type DiffCell = DiffCellValue | { before?: DiffCellValue; after?: DiffCellValue };\n\nexport type DiffRowChange = 'added' | 'removed' | 'modified';\n\nexport type DiffRow = {\n id: string;\n cells: Record<string, DiffCell>;\n /** Row-level change. Omitted rows are inferred as `modified` when any cell is an edit. */\n change?: DiffRowChange;\n};\n\nexport type DiffDecision = 'accepted' | 'rejected';\n\nexport type DiffTableProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title' | 'summary'> & {\n columns: DiffTableColumn[];\n rows: DiffRow[];\n title?: React.ReactNode;\n /** Summary line under the title. Auto-computed (`3 changes across 2 rows`) when omitted. */\n summary?: React.ReactNode;\n /** Reveal changed rows one by one, top to bottom. */\n sweeping?: boolean;\n /** Milliseconds between each revealed row while sweeping. */\n sweepIntervalMs?: number;\n onAcceptAll?: () => void;\n onRejectAll?: () => void;\n onAcceptRow?: (row: DiffRow) => void;\n onRejectRow?: (row: DiffRow) => void;\n /** Controlled per-row decisions, keyed by row id. */\n decisions?: Record<string, DiffDecision>;\n dense?: boolean;\n /** Text overrides. */\n labels?: Partial<typeof DEFAULT_LABELS>;\n};\n\nconst DEFAULT_LABELS = {\n added: 'Added',\n removed: 'Removed',\n modified: 'Changed',\n unchanged: '—',\n acceptAll: 'Accept all',\n rejectAll: 'Reject all',\n accept: 'Accept',\n reject: 'Reject',\n accepted: 'Accepted',\n rejected: 'Rejected',\n status: 'Status',\n actions: 'Actions',\n empty: '∅',\n};\n\nexport function isDiffCellChange(cell: DiffCell): cell is { before?: DiffCellValue; after?: DiffCellValue } {\n return typeof cell === 'object' && cell !== null;\n}\n\n/** Infer the row's change kind from its explicit flag or its cells. */\nexport function diffRowChange(row: DiffRow): DiffRowChange | undefined {\n if (row.change) return row.change;\n return Object.values(row.cells).some(isDiffCellChange) ? 'modified' : undefined;\n}\n\n/** Number of changed cells in a row (whole row counts as one for added/removed). */\nfunction countRowChanges(row: DiffRow): number {\n const change = row.change;\n if (change === 'added' || change === 'removed') return 1;\n return Object.values(row.cells).filter(isDiffCellChange).length;\n}\n\nconst plural = (n: number, word: string) => `${n} ${word}${n === 1 ? '' : 's'}`;\n\nconst REDUCED_MOTION = '(prefers-reduced-motion: reduce)';\nconst subscribeReducedMotion = (onChange: () => void) => {\n if (typeof window === 'undefined' || !window.matchMedia) return () => {};\n const mq = window.matchMedia(REDUCED_MOTION);\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n};\nconst getReducedMotion = () => typeof window !== 'undefined' && !!window.matchMedia && window.matchMedia(REDUCED_MOTION).matches;\nconst usePrefersReducedMotion = () => useSyncExternalStore(subscribeReducedMotion, getReducedMotion, () => false);\n\nconst CheckIcon = () => (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n);\nconst XIcon = () => (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n);\n\nconst renderValue = (value: DiffCellValue | undefined, empty: string) =>\n value === null || value === undefined || value === '' ? <span className=\"dishui-ai-diff-table__empty\">{empty}</span> : String(value);\n\n/**\n * AI-proposed edits sweeping through tabular data. Changed cells show the\n * old value struck through next to the new one; added/removed rows are\n * tinted and always labelled in the leading status column.\n */\nexport default function DiffTable({\n columns,\n rows,\n title,\n summary,\n sweeping: sweepingProp = false,\n sweepIntervalMs = 220,\n onAcceptAll,\n onRejectAll,\n onAcceptRow,\n onRejectRow,\n decisions,\n dense = false,\n labels: labelOverrides,\n className,\n ...rest\n}: DiffTableProps) {\n const labels = { ...DEFAULT_LABELS, ...labelOverrides };\n\n const changedIds = useMemo(() => rows.filter(r => diffRowChange(r)).map(r => r.id), [rows]);\n const changeCount = useMemo(() => rows.reduce((n, r) => n + countRowChanges(r), 0), [rows]);\n\n // Reduced motion: skip the sweep and show every change at once.\n const reducedMotion = usePrefersReducedMotion();\n const sweeping = sweepingProp && !reducedMotion;\n\n // Sweep: reveal one changed row per interval. `revealed` counts changed rows (top to bottom).\n const [revealed, setRevealed] = useState(0);\n useEffect(() => {\n if (!sweeping) return;\n const total = changedIds.length;\n const id = window.setInterval(() => {\n setRevealed(n => {\n if (n + 1 >= total) window.clearInterval(id);\n return Math.min(n + 1, total);\n });\n }, Math.max(16, sweepIntervalMs));\n return () => {\n window.clearInterval(id);\n // Restart from the top the next time a sweep begins.\n setRevealed(0);\n };\n }, [sweeping, sweepIntervalMs, changedIds.length]);\n\n const revealedIds = useMemo(() => {\n if (!sweeping) return null;\n return new Set(changedIds.slice(0, revealed));\n }, [sweeping, changedIds, revealed]);\n\n const done = !sweeping || revealed >= changedIds.length;\n const hasRowActions = Boolean(onAcceptRow || onRejectRow);\n const hasFooter = Boolean(onAcceptAll || onRejectAll);\n\n const autoSummary = `${plural(changeCount, 'change')} across ${plural(changedIds.length, 'row')}`;\n\n return (\n <div\n {...rest}\n className={cn('dishui-ai-diff-table', dense && 'dishui-ai-diff-table--dense', sweeping && !done && 'dishui-ai-diff-table--sweeping', className)}\n >\n {(title || summary !== null) && (\n <div className=\"dishui-ai-diff-table__header\">\n {title && <div className=\"dishui-ai-diff-table__title\">{title}</div>}\n <div className=\"dishui-ai-diff-table__summary\" aria-live=\"polite\">\n {summary ?? autoSummary}\n </div>\n </div>\n )}\n\n <div className=\"dishui-ai-diff-table__scroll\">\n <table className=\"dishui-ai-diff-table__table\">\n <thead>\n <tr>\n <th scope=\"col\" className=\"dishui-ai-diff-table__th dishui-ai-diff-table__th--status\">{labels.status}</th>\n {columns.map(col => (\n <th\n key={col.key}\n scope=\"col\"\n className={cn('dishui-ai-diff-table__th', col.align === 'right' && 'dishui-ai-diff-table__th--right')}\n >\n {col.label}\n </th>\n ))}\n {hasRowActions && (\n <th scope=\"col\" className=\"dishui-ai-diff-table__th dishui-ai-diff-table__th--actions\">\n <span className=\"dishui-ai-diff-table__sr\">{labels.actions}</span>\n </th>\n )}\n </tr>\n </thead>\n <tbody>\n {rows.map(row => {\n const change = diffRowChange(row);\n const visible = !change || !revealedIds || revealedIds.has(row.id);\n const decision = decisions?.[row.id];\n return (\n <tr\n key={row.id}\n className={cn(\n 'dishui-ai-diff-table__row',\n change && `dishui-ai-diff-table__row--${change}`,\n change && visible && 'dishui-ai-diff-table__row--revealed',\n decision && `dishui-ai-diff-table__row--${decision}`,\n )}\n data-change={change}\n >\n <td className=\"dishui-ai-diff-table__td dishui-ai-diff-table__td--status\">\n {change && visible ? (\n <span className={cn('dishui-ai-diff-table__badge', `dishui-ai-diff-table__badge--${change}`)}>\n {labels[change]}\n </span>\n ) : (\n <span className=\"dishui-ai-diff-table__badge dishui-ai-diff-table__badge--none\" aria-hidden=\"true\">\n {labels.unchanged}\n </span>\n )}\n </td>\n {columns.map(col => {\n const cell = row.cells[col.key];\n const changed = visible && isDiffCellChange(cell);\n const tdClass = cn(\n 'dishui-ai-diff-table__td',\n col.align === 'right' && 'dishui-ai-diff-table__td--right',\n col.mono && 'dishui-ai-diff-table__td--mono',\n changed && 'dishui-ai-diff-table__td--changed',\n );\n if (isDiffCellChange(cell)) {\n if (!visible) {\n return <td key={col.key} className={tdClass}>{renderValue(cell.before, labels.empty)}</td>;\n }\n return (\n <td key={col.key} className={tdClass}>\n <span className=\"dishui-ai-diff-table__change\">\n <del className=\"dishui-ai-diff-table__before\">{renderValue(cell.before, labels.empty)}</del>\n <span className=\"dishui-ai-diff-table__arrow\" aria-hidden=\"true\">→</span>\n <ins className=\"dishui-ai-diff-table__after\">{renderValue(cell.after, labels.empty)}</ins>\n </span>\n </td>\n );\n }\n return (\n <td key={col.key} className={tdClass}>\n {change === 'removed' && visible ? (\n <del className=\"dishui-ai-diff-table__before\">{renderValue(cell, labels.empty)}</del>\n ) : change === 'added' && visible ? (\n <ins className=\"dishui-ai-diff-table__after\">{renderValue(cell, labels.empty)}</ins>\n ) : (\n renderValue(cell, labels.empty)\n )}\n </td>\n );\n })}\n {hasRowActions && (\n <td className=\"dishui-ai-diff-table__td dishui-ai-diff-table__td--actions\">\n {change && visible && (\n decision ? (\n <span className={cn('dishui-ai-diff-table__decision', `dishui-ai-diff-table__decision--${decision}`)}>\n {decision === 'accepted' ? <CheckIcon /> : <XIcon />}\n {labels[decision]}\n </span>\n ) : (\n <span className=\"dishui-ai-diff-table__row-actions\">\n {onAcceptRow && (\n <button type=\"button\" className=\"dishui-ai-diff-table__icon-btn\" aria-label={labels.accept} title={labels.accept} onClick={() => onAcceptRow(row)}>\n <CheckIcon />\n </button>\n )}\n {onRejectRow && (\n <button type=\"button\" className=\"dishui-ai-diff-table__icon-btn\" aria-label={labels.reject} title={labels.reject} onClick={() => onRejectRow(row)}>\n <XIcon />\n </button>\n )}\n </span>\n )\n )}\n </td>\n )}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n\n {hasFooter && (\n <div className=\"dishui-ai-diff-table__footer\">\n <span className=\"dishui-ai-diff-table__footer-meta\">{done ? autoSummary : 'Reviewing…'}</span>\n <span className=\"dishui-ai-diff-table__footer-actions\">\n {onRejectAll && (\n <Button type=\"button\" variant=\"secondary\" size=\"sm\" onClick={onRejectAll} disabled={!done}>\n {labels.rejectAll}\n </Button>\n )}\n {onAcceptAll && (\n <Button type=\"button\" variant=\"primary\" size=\"sm\" onClick={onAcceptAll} disabled={!done}>\n {labels.acceptAll}\n </Button>\n )}\n </span>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ export type FilterTableColumn<Row> = {
3
+ key: string;
4
+ label: React.ReactNode;
5
+ render?: (row: Row) => React.ReactNode;
6
+ value?: (row: Row) => string | number;
7
+ align?: 'left' | 'right';
8
+ mono?: boolean;
9
+ };
10
+ export type FilterTableFilter<Row> = {
11
+ id: string;
12
+ label: string;
13
+ predicate: (row: Row) => boolean;
14
+ };
15
+ export type FilterTableProps<Row extends {
16
+ id: string;
17
+ }> = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {
18
+ rows: Row[];
19
+ columns: FilterTableColumn<Row>[];
20
+ filters?: FilterTableFilter<Row>[];
21
+ value?: string;
22
+ defaultValue?: string;
23
+ onChange?: (id: string) => void;
24
+ search?: string;
25
+ defaultSearch?: string;
26
+ onSearchChange?: (query: string) => void;
27
+ searchPlaceholder?: string;
28
+ emptyText?: React.ReactNode;
29
+ noResultsText?: React.ReactNode;
30
+ caption?: React.ReactNode;
31
+ loading?: boolean;
32
+ };
33
+ export default function FilterTable<Row extends {
34
+ id: string;
35
+ }>({ rows, columns, filters, value, defaultValue, onChange, search, defaultSearch, onSearchChange, searchPlaceholder, emptyText, noResultsText, caption, loading, className, ...rest }: FilterTableProps<Row>): React.JSX.Element;
@@ -0,0 +1,86 @@
1
+ import { cn as e } from "../../../utils/cn.js";
2
+ import t from "../../Table/index.js";
3
+ import n from "../../Skeleton/index.js";
4
+ /* empty css */
5
+ import { useMemo as r, useState as i } from "react";
6
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
7
+ //#region src/components/ai/FilterTable/index.tsx
8
+ var s = [];
9
+ function c({ rows: c, columns: l, filters: u = s, value: d, defaultValue: f = "all", onChange: p, search: m, defaultSearch: h = "", onSearchChange: g, searchPlaceholder: _ = "Filter records…", emptyText: v = "No records yet", noResultsText: y = "No matching records", caption: b, loading: x = !1, className: S, ...C }) {
10
+ let [w, T] = i(f), [E, D] = i(h), O = d ?? w, k = m ?? E, A = r(() => c.filter((e) => {
11
+ let t = u.find((e) => e.id === O);
12
+ return t && !t.predicate(e) ? !1 : !k.trim() || l.some((t) => String(t.value?.(e) ?? e[t.key] ?? "").toLowerCase().includes(k.trim().toLowerCase()));
13
+ }), [
14
+ c,
15
+ l,
16
+ u,
17
+ O,
18
+ k
19
+ ]), j = (e) => {
20
+ d === void 0 && T(e), p?.(e);
21
+ }, M = (e) => {
22
+ m === void 0 && D(e), g?.(e);
23
+ };
24
+ return /* @__PURE__ */ o("div", {
25
+ ...C,
26
+ className: e("dishui-ai-filter-table", S),
27
+ "aria-busy": x || void 0,
28
+ children: [/* @__PURE__ */ o("div", {
29
+ className: "dishui-ai-filter-table__toolbar",
30
+ children: [/* @__PURE__ */ o("div", {
31
+ className: "dishui-ai-filter-table__filters",
32
+ role: "group",
33
+ "aria-label": "Table filters",
34
+ children: [/* @__PURE__ */ o("button", {
35
+ type: "button",
36
+ "aria-pressed": O === "all",
37
+ onClick: () => j("all"),
38
+ children: ["All ", /* @__PURE__ */ a("span", { children: c.length })]
39
+ }), u.map((e) => /* @__PURE__ */ o("button", {
40
+ type: "button",
41
+ "aria-pressed": O === e.id,
42
+ onClick: () => j(e.id),
43
+ children: [
44
+ e.label,
45
+ " ",
46
+ /* @__PURE__ */ a("span", { children: c.filter(e.predicate).length })
47
+ ]
48
+ }, e.id))]
49
+ }), /* @__PURE__ */ a("input", {
50
+ type: "search",
51
+ "aria-label": _,
52
+ placeholder: _,
53
+ value: k,
54
+ onChange: (e) => M(e.target.value)
55
+ })]
56
+ }), /* @__PURE__ */ a("div", {
57
+ className: "dishui-ai-filter-table__scroll",
58
+ children: /* @__PURE__ */ o(t, { children: [
59
+ b && /* @__PURE__ */ a("caption", { children: b }),
60
+ /* @__PURE__ */ a(t.Head, { children: /* @__PURE__ */ a(t.Row, { children: l.map((e) => /* @__PURE__ */ a(t.HeaderCell, {
61
+ className: e.align === "right" ? "dishui-ai-filter-table__right" : void 0,
62
+ children: e.label
63
+ }, e.key)) }) }),
64
+ /* @__PURE__ */ o(t.Body, { children: [x ? [
65
+ "one",
66
+ "two",
67
+ "three"
68
+ ].map((e) => /* @__PURE__ */ a(t.Row, {
69
+ "aria-hidden": "true",
70
+ children: l.map((e) => /* @__PURE__ */ a(t.Cell, { children: /* @__PURE__ */ a(n, { className: "dishui-ai-filter-table__skeleton" }) }, e.key))
71
+ }, e)) : A.map((n) => /* @__PURE__ */ a(t.Row, { children: l.map((r) => /* @__PURE__ */ a(t.Cell, {
72
+ className: e(r.align === "right" && "dishui-ai-filter-table__right", r.mono && "dishui-ai-filter-table__mono"),
73
+ children: r.render ? r.render(n) : String(r.value?.(n) ?? n[r.key] ?? "—")
74
+ }, r.key)) }, n.id)), !x && A.length === 0 && /* @__PURE__ */ a(t.Row, { children: /* @__PURE__ */ a(t.Cell, {
75
+ className: "dishui-ai-filter-table__empty",
76
+ colSpan: l.length,
77
+ children: c.length ? y : v
78
+ }) })] })
79
+ ] })
80
+ })]
81
+ });
82
+ }
83
+ //#endregion
84
+ export { c as default };
85
+
86
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/FilterTable/index.tsx"],"sourcesContent":["import React, { useMemo, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport Table from '../../Table';\nimport Skeleton from '../../Skeleton';\nimport './FilterTable.css';\n\nconst EMPTY_FILTERS: FilterTableFilter<never>[] = [];\n\nexport type FilterTableColumn<Row> = { key: string; label: React.ReactNode; render?: (row: Row) => React.ReactNode; value?: (row: Row) => string | number; align?: 'left' | 'right'; mono?: boolean };\nexport type FilterTableFilter<Row> = { id: string; label: string; predicate: (row: Row) => boolean };\nexport type FilterTableProps<Row extends { id: string }> = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & { rows: Row[]; columns: FilterTableColumn<Row>[]; filters?: FilterTableFilter<Row>[]; value?: string; defaultValue?: string; onChange?: (id: string) => void; search?: string; defaultSearch?: string; onSearchChange?: (query: string) => void; searchPlaceholder?: string; emptyText?: React.ReactNode; noResultsText?: React.ReactNode; caption?: React.ReactNode; loading?: boolean };\n\nexport default function FilterTable<Row extends { id: string }>({ rows, columns, filters = EMPTY_FILTERS as FilterTableFilter<Row>[], value, defaultValue = 'all', onChange, search, defaultSearch = '', onSearchChange, searchPlaceholder = 'Filter records…', emptyText = 'No records yet', noResultsText = 'No matching records', caption, loading = false, className, ...rest }: FilterTableProps<Row>) {\n const [internalFilter, setInternalFilter] = useState(defaultValue); const [internalSearch, setInternalSearch] = useState(defaultSearch); const active = value ?? internalFilter; const query = search ?? internalSearch;\n const shown = useMemo(() => rows.filter(row => { const filter = filters.find(x => x.id === active); if (filter && !filter.predicate(row)) return false; if (!query.trim()) return true; return columns.some(col => String(col.value?.(row) ?? (row as Record<string, unknown>)[col.key] ?? '').toLowerCase().includes(query.trim().toLowerCase())); }), [rows, columns, filters, active, query]);\n const setFilter = (id: string) => { if (value === undefined) setInternalFilter(id); onChange?.(id); };\n const setSearch = (next: string) => { if (search === undefined) setInternalSearch(next); onSearchChange?.(next); };\n return <div {...rest} className={cn('dishui-ai-filter-table', className)} aria-busy={loading || undefined}><div className=\"dishui-ai-filter-table__toolbar\"><div className=\"dishui-ai-filter-table__filters\" role=\"group\" aria-label=\"Table filters\"><button type=\"button\" aria-pressed={active === 'all'} onClick={() => setFilter('all')}>All <span>{rows.length}</span></button>{filters.map(filter => <button key={filter.id} type=\"button\" aria-pressed={active === filter.id} onClick={() => setFilter(filter.id)}>{filter.label} <span>{rows.filter(filter.predicate).length}</span></button>)}</div><input type=\"search\" aria-label={searchPlaceholder} placeholder={searchPlaceholder} value={query} onChange={e => setSearch(e.target.value)}/></div><div className=\"dishui-ai-filter-table__scroll\"><Table>{caption && <caption>{caption}</caption>}<Table.Head><Table.Row>{columns.map(col => <Table.HeaderCell key={col.key} className={col.align === 'right' ? 'dishui-ai-filter-table__right' : undefined}>{col.label}</Table.HeaderCell>)}</Table.Row></Table.Head><Table.Body>{loading ? ['one', 'two', 'three'].map(rowKey => <Table.Row key={rowKey} aria-hidden=\"true\">{columns.map(col => <Table.Cell key={col.key}><Skeleton className=\"dishui-ai-filter-table__skeleton\" /></Table.Cell>)}</Table.Row>) : shown.map(row => <Table.Row key={row.id}>{columns.map(col => <Table.Cell key={col.key} className={cn(col.align === 'right' && 'dishui-ai-filter-table__right', col.mono && 'dishui-ai-filter-table__mono')}>{col.render ? col.render(row) : String(col.value?.(row) ?? (row as Record<string, unknown>)[col.key] ?? '—')}</Table.Cell>)}</Table.Row>)}{!loading && shown.length === 0 && <Table.Row><Table.Cell className=\"dishui-ai-filter-table__empty\" colSpan={columns.length}>{rows.length ? noResultsText : emptyText}</Table.Cell></Table.Row>}</Table.Body></Table></div></div>;\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ export type FineTuneMetric = {
3
+ label: React.ReactNode;
4
+ value: React.ReactNode;
5
+ };
6
+ export type FineTuneCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> & {
7
+ title: React.ReactNode;
8
+ model?: string;
9
+ description?: React.ReactNode;
10
+ status?: 'draft' | 'queued' | 'training' | 'ready' | 'failed';
11
+ progress?: number;
12
+ metrics?: FineTuneMetric[];
13
+ error?: React.ReactNode;
14
+ onStart?: () => void;
15
+ onCancel?: () => void;
16
+ onRetry?: () => void;
17
+ disabled?: boolean;
18
+ labels?: {
19
+ start?: string;
20
+ cancel?: string;
21
+ retry?: string;
22
+ };
23
+ };
24
+ export default function FineTuneCard({ title, model, description, status, progress, metrics, error, onStart, onCancel, onRetry, disabled, labels, className, ...rest }: FineTuneCardProps): React.JSX.Element;
@@ -0,0 +1,75 @@
1
+ import { cn as e } from "../../../utils/cn.js";
2
+ import t from "../../Button/index.js";
3
+ import { clamp as n } from "../shared.js";
4
+ /* empty css */
5
+ import "react";
6
+ import { jsx as r, jsxs as i } from "react/jsx-runtime";
7
+ //#region src/components/ai/FineTuneCard/index.tsx
8
+ var a = {
9
+ draft: "Draft",
10
+ queued: "Queued",
11
+ training: "Training",
12
+ ready: "Ready",
13
+ failed: "Failed"
14
+ }, o = [];
15
+ function s({ title: s, model: c, description: l, status: u = "draft", progress: d = 0, metrics: f = o, error: p, onStart: m, onCancel: h, onRetry: g, disabled: _ = !1, labels: v, className: y, ...b }) {
16
+ let x = Math.round(n(d, 0, 1) * 100), S = u === "queued" || u === "training";
17
+ return /* @__PURE__ */ i("article", {
18
+ ...b,
19
+ className: e("dishui-ai-fine-tune-card", `dishui-ai-fine-tune-card--${u}`, y),
20
+ children: [
21
+ /* @__PURE__ */ i("header", { children: [/* @__PURE__ */ i("div", { children: [/* @__PURE__ */ r("h3", { children: s }), c && /* @__PURE__ */ r("code", { children: c })] }), /* @__PURE__ */ r("span", {
22
+ className: "dishui-ai-fine-tune-card__status",
23
+ children: a[u]
24
+ })] }),
25
+ l && /* @__PURE__ */ r("div", {
26
+ className: "dishui-ai-fine-tune-card__description",
27
+ children: l
28
+ }),
29
+ S && /* @__PURE__ */ i("div", {
30
+ className: "dishui-ai-fine-tune-card__progress",
31
+ children: [/* @__PURE__ */ i("div", { children: [/* @__PURE__ */ r("span", { children: "Training progress" }), /* @__PURE__ */ i("strong", { children: [x, "%"] })] }), /* @__PURE__ */ i("progress", {
32
+ max: 100,
33
+ value: x,
34
+ children: [x, "%"]
35
+ })]
36
+ }),
37
+ f.length > 0 && /* @__PURE__ */ r("dl", { children: f.map((e) => /* @__PURE__ */ i("div", { children: [/* @__PURE__ */ r("dt", { children: e.label }), /* @__PURE__ */ r("dd", { children: e.value })] }, `${String(e.label)}-${String(e.value)}`)) }),
38
+ u === "failed" && p && /* @__PURE__ */ r("div", {
39
+ role: "alert",
40
+ className: "dishui-ai-fine-tune-card__error",
41
+ children: p
42
+ }),
43
+ /* @__PURE__ */ i("footer", { children: [
44
+ u === "draft" && m && /* @__PURE__ */ r(t, {
45
+ type: "button",
46
+ variant: "primary",
47
+ size: "sm",
48
+ disabled: _,
49
+ onClick: m,
50
+ children: v?.start ?? "Start training"
51
+ }),
52
+ S && h && /* @__PURE__ */ r(t, {
53
+ type: "button",
54
+ variant: "secondary",
55
+ size: "sm",
56
+ disabled: _,
57
+ onClick: h,
58
+ children: v?.cancel ?? "Cancel"
59
+ }),
60
+ u === "failed" && g && /* @__PURE__ */ r(t, {
61
+ type: "button",
62
+ variant: "primary",
63
+ size: "sm",
64
+ disabled: _,
65
+ onClick: g,
66
+ children: v?.retry ?? "Retry"
67
+ })
68
+ ] })
69
+ ]
70
+ });
71
+ }
72
+ //#endregion
73
+ export { s as default };
74
+
75
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/FineTuneCard/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../../utils/cn';\nimport Button from '../../Button';\nimport { clamp } from '../shared';\nimport './FineTuneCard.css';\n\nexport type FineTuneMetric = {\n label: React.ReactNode;\n value: React.ReactNode;\n};\n\nexport type FineTuneCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> & {\n title: React.ReactNode;\n model?: string;\n description?: React.ReactNode;\n status?: 'draft' | 'queued' | 'training' | 'ready' | 'failed';\n progress?: number;\n metrics?: FineTuneMetric[];\n error?: React.ReactNode;\n onStart?: () => void;\n onCancel?: () => void;\n onRetry?: () => void;\n disabled?: boolean;\n labels?: { start?: string; cancel?: string; retry?: string };\n};\n\nconst STATUS = {\n draft: 'Draft',\n queued: 'Queued',\n training: 'Training',\n ready: 'Ready',\n failed: 'Failed',\n} as const;\nconst EMPTY_METRICS: FineTuneMetric[] = [];\n\nexport default function FineTuneCard({\n title,\n model,\n description,\n status = 'draft',\n progress = 0,\n metrics = EMPTY_METRICS,\n error,\n onStart,\n onCancel,\n onRetry,\n disabled = false,\n labels,\n className,\n ...rest\n}: FineTuneCardProps) {\n const pct = Math.round(clamp(progress, 0, 1) * 100);\n const active = status === 'queued' || status === 'training';\n\n return (\n <article {...rest} className={cn('dishui-ai-fine-tune-card', `dishui-ai-fine-tune-card--${status}`, className)}>\n <header>\n <div>\n <h3>{title}</h3>\n {model && <code>{model}</code>}\n </div>\n <span className=\"dishui-ai-fine-tune-card__status\">{STATUS[status]}</span>\n </header>\n\n {description && <div className=\"dishui-ai-fine-tune-card__description\">{description}</div>}\n\n {active && (\n <div className=\"dishui-ai-fine-tune-card__progress\">\n <div><span>Training progress</span><strong>{pct}%</strong></div>\n <progress max={100} value={pct}>{pct}%</progress>\n </div>\n )}\n\n {metrics.length > 0 && (\n <dl>\n {metrics.map(metric => (\n <div key={`${String(metric.label)}-${String(metric.value)}`}>\n <dt>{metric.label}</dt>\n <dd>{metric.value}</dd>\n </div>\n ))}\n </dl>\n )}\n\n {status === 'failed' && error && (\n <div role=\"alert\" className=\"dishui-ai-fine-tune-card__error\">{error}</div>\n )}\n\n <footer>\n {status === 'draft' && onStart && (\n <Button type=\"button\" variant=\"primary\" size=\"sm\" disabled={disabled} onClick={onStart}>\n {labels?.start ?? 'Start training'}\n </Button>\n )}\n {active && onCancel && (\n <Button type=\"button\" variant=\"secondary\" size=\"sm\" disabled={disabled} onClick={onCancel}>\n {labels?.cancel ?? 'Cancel'}\n </Button>\n )}\n {status === 'failed' && onRetry && (\n <Button type=\"button\" variant=\"primary\" size=\"sm\" disabled={disabled} onClick={onRetry}>\n {labels?.retry ?? 'Retry'}\n </Button>\n )}\n </footer>\n </article>\n );\n}\n"],"mappings":";;;;;;;AA0BA,IAAM,IAAS;CACb,OAAO;CACP,QAAQ;CACR,UAAU;CACV,OAAO;CACP,QAAQ;AACV,GACM,IAAkC,CAAC;AAEzC,SAAwB,EAAa,EACnC,UACA,UACA,gBACA,YAAS,SACT,cAAW,GACX,aAAU,GACV,UACA,YACA,aACA,YACA,cAAW,IACX,WACA,cACA,GAAG,KACiB;CACpB,IAAM,IAAM,KAAK,MAAM,EAAM,GAAU,GAAG,CAAC,IAAI,GAAG,GAC5C,IAAS,MAAW,YAAY,MAAW;CAEjD,OACE,kBAAC,WAAD;EAAS,GAAI;EAAM,WAAW,EAAG,4BAA4B,6BAA6B,KAAU,CAAS;EAA7G,UAAA;GACE,kBAAC,UAAD,EAAA,UAAA,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD,EAAA,UAAK,EAAU,CAAA,GACd,KAAS,kBAAC,QAAD,EAAA,UAAO,EAAY,CAAA,CAC1B,EAAA,CAAA,GACL,kBAAC,QAAD;IAAM,WAAU;IAAoC,UAAA,EAAO;GAAc,CAAA,CACnE,EAAA,CAAA;GAEP,KAAe,kBAAC,OAAD;IAAK,WAAU;IAAyC,UAAA;GAAiB,CAAA;GAExF,KACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,OAAD,EAAA,UAAA,CAAK,kBAAC,QAAD,EAAA,UAAM,oBAAuB,CAAA,GAAC,kBAAC,UAAD,EAAA,UAAA,CAAS,GAAI,GAAS,EAAA,CAAA,CAAM,EAAA,CAAA,GAC/D,kBAAC,YAAD;KAAU,KAAK;KAAK,OAAO;KAA3B,UAAA,CAAiC,GAAI,GAAW;IAC7C,CAAA,CAAA;;GAGN,EAAQ,SAAS,KAChB,kBAAC,MAAD,EAAA,UACG,EAAQ,KAAI,MACX,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD,EAAA,UAAK,EAAO,MAAU,CAAA,GACtB,kBAAC,MAAD,EAAA,UAAK,EAAO,MAAU,CAAA,CACnB,EAAA,GAHK,GAAG,OAAO,EAAO,KAAK,EAAE,GAAG,OAAO,EAAO,KAAK,GAGnD,CACN,EACC,CAAA;GAGL,MAAW,YAAY,KACtB,kBAAC,OAAD;IAAK,MAAK;IAAQ,WAAU;IAAmC,UAAA;GAAW,CAAA;GAG5E,kBAAC,UAAD,EAAA,UAAA;IACG,MAAW,WAAW,KACrB,kBAAC,GAAD;KAAQ,MAAK;KAAS,SAAQ;KAAU,MAAK;KAAe;KAAU,SAAS;KAC5E,UAAA,GAAQ,SAAS;IACZ,CAAA;IAET,KAAU,KACT,kBAAC,GAAD;KAAQ,MAAK;KAAS,SAAQ;KAAY,MAAK;KAAe;KAAU,SAAS;KAC9E,UAAA,GAAQ,UAAU;IACb,CAAA;IAET,MAAW,YAAY,KACtB,kBAAC,GAAD;KAAQ,MAAK;KAAS,SAAQ;KAAU,MAAK;KAAe;KAAU,SAAS;KAC5E,UAAA,GAAQ,SAAS;IACZ,CAAA;GAEJ,EAAA,CAAA;EACD;;AAEb"}
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ export type InsightCardItem = {
3
+ id: string;
4
+ label: React.ReactNode;
5
+ value: React.ReactNode;
6
+ detail?: React.ReactNode;
7
+ trend?: {
8
+ value: string;
9
+ direction: 'up' | 'down' | 'flat';
10
+ label?: string;
11
+ };
12
+ status?: 'neutral' | 'success' | 'warning' | 'danger' | 'info';
13
+ };
14
+ export type InsightCardsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'onSelect'> & {
15
+ items: InsightCardItem[];
16
+ columns?: 2 | 3 | 4;
17
+ selectedId?: string;
18
+ defaultSelectedId?: string;
19
+ onSelect?: (item: InsightCardItem) => void;
20
+ loading?: boolean;
21
+ emptyText?: React.ReactNode;
22
+ };
23
+ export default function InsightCards({ items, columns, selectedId, defaultSelectedId, onSelect, loading, emptyText, className, ...rest }: InsightCardsProps): React.JSX.Element;
@@ -0,0 +1,64 @@
1
+ import { cn as e } from "../../../utils/cn.js";
2
+ /* empty css */
3
+ import { useState as t } from "react";
4
+ import { Fragment as n, jsx as r, jsxs as i } from "react/jsx-runtime";
5
+ //#region src/components/ai/InsightCards/index.tsx
6
+ function a({ items: a, columns: o = 3, selectedId: s, defaultSelectedId: c, onSelect: l, loading: u = !1, emptyText: d = "No insights available", className: f, ...p }) {
7
+ let [m, h] = t(c), g = s ?? m, _ = (e) => {
8
+ s === void 0 && h(e.id), l?.(e);
9
+ };
10
+ if (!u && !a.length) return /* @__PURE__ */ r("div", {
11
+ ...p,
12
+ className: e("dishui-ai-insight-cards dishui-ai-insight-cards--empty", f),
13
+ children: d
14
+ });
15
+ let v = u ? Array.from({ length: o }, (e, t) => ({
16
+ id: `loading-${t}`,
17
+ label: "",
18
+ value: ""
19
+ })) : a;
20
+ return /* @__PURE__ */ r("div", {
21
+ ...p,
22
+ className: e("dishui-ai-insight-cards", `dishui-ai-insight-cards--${o}`, f),
23
+ children: v.map((t) => {
24
+ let a = /* @__PURE__ */ i(n, { children: [
25
+ /* @__PURE__ */ r("span", {
26
+ className: "dishui-ai-insight-cards__label",
27
+ children: t.label
28
+ }),
29
+ /* @__PURE__ */ r("strong", {
30
+ className: "dishui-ai-insight-cards__value",
31
+ children: t.value
32
+ }),
33
+ t.trend && /* @__PURE__ */ i("span", {
34
+ className: e("dishui-ai-insight-cards__trend", `dishui-ai-insight-cards__trend--${t.trend.direction}`),
35
+ children: [
36
+ t.trend.direction === "up" ? "↑" : t.trend.direction === "down" ? "↓" : "→",
37
+ " ",
38
+ t.trend.value,
39
+ t.trend.label && /* @__PURE__ */ i("span", { children: [" ", t.trend.label] })
40
+ ]
41
+ }),
42
+ t.detail && /* @__PURE__ */ r("span", {
43
+ className: "dishui-ai-insight-cards__detail",
44
+ children: t.detail
45
+ }),
46
+ u && /* @__PURE__ */ i(n, { children: [/* @__PURE__ */ r("span", { className: "dishui-ai-insight-cards__skeleton" }), /* @__PURE__ */ r("span", { className: "dishui-ai-insight-cards__skeleton dishui-ai-insight-cards__skeleton--short" })] })
47
+ ] });
48
+ return l ? /* @__PURE__ */ r("button", {
49
+ type: "button",
50
+ className: e("dishui-ai-insight-cards__card", t.status && `dishui-ai-insight-cards__card--${t.status}`, g === t.id && "dishui-ai-insight-cards__card--selected"),
51
+ "aria-pressed": g === t.id,
52
+ onClick: () => _(t),
53
+ children: a
54
+ }, t.id) : /* @__PURE__ */ r("article", {
55
+ className: e("dishui-ai-insight-cards__card", t.status && `dishui-ai-insight-cards__card--${t.status}`),
56
+ children: a
57
+ }, t.id);
58
+ })
59
+ });
60
+ }
61
+ //#endregion
62
+ export { a as default };
63
+
64
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/InsightCards/index.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport './InsightCards.css';\n\nexport type InsightCardItem = { id: string; label: React.ReactNode; value: React.ReactNode; detail?: React.ReactNode; trend?: { value: string; direction: 'up' | 'down' | 'flat'; label?: string }; status?: 'neutral' | 'success' | 'warning' | 'danger' | 'info' };\nexport type InsightCardsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'onSelect'> & { items: InsightCardItem[]; columns?: 2 | 3 | 4; selectedId?: string; defaultSelectedId?: string; onSelect?: (item: InsightCardItem) => void; loading?: boolean; emptyText?: React.ReactNode };\n\nexport default function InsightCards({ items, columns = 3, selectedId, defaultSelectedId, onSelect, loading = false, emptyText = 'No insights available', className, ...rest }: InsightCardsProps) {\n const [internal, setInternal] = useState(defaultSelectedId); const selected = selectedId ?? internal;\n const select = (item: InsightCardItem) => { if (selectedId === undefined) setInternal(item.id); onSelect?.(item); };\n if (!loading && !items.length) return <div {...rest} className={cn('dishui-ai-insight-cards dishui-ai-insight-cards--empty', className)}>{emptyText}</div>;\n const content = loading ? Array.from({ length: columns }, (_, i) => ({ id: `loading-${i}`, label: '', value: '' } as InsightCardItem)) : items;\n return <div {...rest} className={cn('dishui-ai-insight-cards', `dishui-ai-insight-cards--${columns}`, className)}>{content.map(item => { const body = <><span className=\"dishui-ai-insight-cards__label\">{item.label}</span><strong className=\"dishui-ai-insight-cards__value\">{item.value}</strong>{item.trend && <span className={cn('dishui-ai-insight-cards__trend', `dishui-ai-insight-cards__trend--${item.trend.direction}`)}>{item.trend.direction === 'up' ? '↑' : item.trend.direction === 'down' ? '↓' : '→'} {item.trend.value}{item.trend.label && <span> {item.trend.label}</span>}</span>}{item.detail && <span className=\"dishui-ai-insight-cards__detail\">{item.detail}</span>}{loading && <><span className=\"dishui-ai-insight-cards__skeleton\"/><span className=\"dishui-ai-insight-cards__skeleton dishui-ai-insight-cards__skeleton--short\"/></>}</>; return onSelect ? <button type=\"button\" key={item.id} className={cn('dishui-ai-insight-cards__card', item.status && `dishui-ai-insight-cards__card--${item.status}`, selected === item.id && 'dishui-ai-insight-cards__card--selected')} aria-pressed={selected === item.id} onClick={() => select(item)}>{body}</button> : <article key={item.id} className={cn('dishui-ai-insight-cards__card', item.status && `dishui-ai-insight-cards__card--${item.status}`)}>{body}</article>; })}</div>;\n}\n"],"mappings":";;;;;AAOA,SAAwB,EAAa,EAAE,UAAO,aAAU,GAAG,eAAY,sBAAmB,aAAU,aAAU,IAAO,eAAY,yBAAyB,cAAW,GAAG,KAA2B;CACjM,IAAM,CAAC,GAAU,KAAe,EAAS,CAAiB,GAAS,IAAW,KAAc,GACtF,KAAU,MAA0B;EAAsD,AAAhD,MAAe,KAAA,KAAW,EAAY,EAAK,EAAE,GAAG,IAAW,CAAI;CAAG;CAClH,IAAI,CAAC,KAAW,CAAC,EAAM,QAAQ,OAAO,kBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,EAAG,0DAA0D,CAAS;EAAI,UAAA;CAAe,CAAA;CACzJ,IAAM,IAAU,IAAU,MAAM,KAAK,EAAE,QAAQ,EAAQ,IAAI,GAAG,OAAO;EAAE,IAAI,WAAW;EAAK,OAAO;EAAI,OAAO;CAAG,EAAqB,IAAI;CACzI,OAAO,kBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,EAAG,2BAA2B,4BAA4B,KAAW,CAAS;EAAI,UAAA,EAAQ,KAAI,MAAQ;GAAE,IAAM,IAAO,kBAAA,GAAA,EAAA,UAAA;IAAE,kBAAC,QAAD;KAAM,WAAU;KAAkC,UAAA,EAAK;IAAY,CAAA;IAAC,kBAAC,UAAD;KAAQ,WAAU;KAAkC,UAAA,EAAK;IAAc,CAAA;IAAE,EAAK,SAAS,kBAAC,QAAD;KAAM,WAAW,EAAG,kCAAkC,mCAAmC,EAAK,MAAM,WAAW;KAA/G,UAAA;MAAmH,EAAK,MAAM,cAAc,OAAO,MAAM,EAAK,MAAM,cAAc,SAAS,MAAM;MAAI;MAAE,EAAK,MAAM;MAAO,EAAK,MAAM,SAAS,kBAAC,QAAD,EAAA,UAAA,CAAM,KAAE,EAAK,MAAM,KAAY,EAAA,CAAA;KAAQ;;IAAG,EAAK,UAAU,kBAAC,QAAD;KAAM,WAAU;KAAmC,UAAA,EAAK;IAAa,CAAA;IAAG,KAAW,kBAAA,GAAA,EAAA,UAAA,CAAE,kBAAC,QAAD,EAAM,WAAU,oCAAoC,CAAA,GAAC,kBAAC,QAAD,EAAM,WAAU,6EAA6E,CAAA,CAAG,EAAA,CAAA;GAAI,EAAA,CAAA;GAAG,OAAO,IAAW,kBAAC,UAAD;IAAQ,MAAK;IAAuB,WAAW,EAAG,iCAAiC,EAAK,UAAU,kCAAkC,EAAK,UAAU,MAAa,EAAK,MAAM,yCAAyC;IAAG,gBAAc,MAAa,EAAK;IAAI,eAAe,EAAO,CAAI;IAAI,UAAA;GAAa,GAA3Q,EAAK,EAAsQ,IAAI,kBAAC,WAAD;IAAuB,WAAW,EAAG,iCAAiC,EAAK,UAAU,kCAAkC,EAAK,QAAQ;IAAI,UAAA;GAAc,GAAxI,EAAK,EAAmI;EAAG,CAAC;CAAO,CAAA;AACzyC"}