@openviking/react 0.1.5 → 0.1.6

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 (101) hide show
  1. package/README.md +13 -11
  2. package/dist/37~0.js +27 -0
  3. package/dist/3c~0.js +14 -8
  4. package/dist/3~0.js +1 -1
  5. package/dist/a~0.js +2 -2
  6. package/dist/ck~0.js +4 -0
  7. package/dist/client/paths.d.ts +4 -0
  8. package/dist/components/agent-connect/style.css +48 -4
  9. package/dist/components/directory-tour/style.css +46 -2
  10. package/dist/components/experience-dashboard/dashboard-tabs.d.ts +11 -0
  11. package/dist/components/experience-dashboard/experience-dashboard.d.ts +2 -0
  12. package/dist/components/experience-dashboard/experience-impact.d.ts +11 -0
  13. package/dist/components/experience-dashboard/experience-list.d.ts +9 -0
  14. package/dist/components/experience-dashboard/experience-pagination.d.ts +8 -0
  15. package/dist/components/experience-dashboard/experience-tests.d.ts +6 -0
  16. package/dist/components/experience-dashboard/experience-trajectories.d.ts +6 -0
  17. package/dist/components/experience-dashboard/index.d.ts +2 -0
  18. package/dist/components/experience-dashboard/labels.d.ts +2 -0
  19. package/dist/components/experience-dashboard/style.css +699 -0
  20. package/dist/components/experience-dashboard/style.js +0 -0
  21. package/dist/components/experience-dashboard/types.d.ts +106 -0
  22. package/dist/components/experience-dashboard.js +1 -0
  23. package/dist/components/file-browser-entries/style.css +144 -12
  24. package/dist/components/file-preview/style.css +48 -4
  25. package/dist/components/file-tree/style.css +63 -4
  26. package/dist/components/scope-switcher/style.css +48 -4
  27. package/dist/components/scope-switcher.js +1 -1
  28. package/dist/components/style.css +2168 -84
  29. package/dist/components/tui/style.css +122 -36
  30. package/dist/components/viking-bot/style.css +159 -12
  31. package/dist/components/wiki-dashboard/index.d.ts +2 -0
  32. package/dist/components/wiki-dashboard/labels.d.ts +2 -0
  33. package/dist/components/wiki-dashboard/style.css +741 -0
  34. package/dist/components/wiki-dashboard/style.js +0 -0
  35. package/dist/components/wiki-dashboard/types.d.ts +92 -0
  36. package/dist/components/wiki-dashboard/wiki-action-button.d.ts +9 -0
  37. package/dist/components/wiki-dashboard/wiki-conflict-card.d.ts +15 -0
  38. package/dist/components/wiki-dashboard/wiki-dashboard.d.ts +2 -0
  39. package/dist/components/wiki-dashboard/wiki-file-icon.d.ts +3 -0
  40. package/dist/components/wiki-dashboard/wiki-severity-filter.d.ts +8 -0
  41. package/dist/components/wiki-dashboard.js +1 -0
  42. package/dist/c~0.js +1 -1
  43. package/dist/fi~0.js +354 -0
  44. package/dist/fj~0.js +503 -0
  45. package/dist/f~0.js +661 -315
  46. package/dist/icons/index.d.ts +28 -0
  47. package/dist/icons.js +1 -1
  48. package/dist/index.d.ts +4 -0
  49. package/dist/index.js +3 -1
  50. package/dist/k~0.js +277 -1
  51. package/dist/lk~0.js +52 -13
  52. package/dist/l~0.js +1021 -118
  53. package/dist/modules/console/index.d.ts +1 -2
  54. package/dist/modules/console/style.css +377 -56
  55. package/dist/modules/console.js +1 -1
  56. package/dist/modules/file-browser/dashboard-data.d.ts +9 -0
  57. package/dist/modules/file-browser/dashboard-indicator.d.ts +8 -0
  58. package/dist/modules/file-browser/dashboard-labels.d.ts +9 -0
  59. package/dist/modules/file-browser/dashboard-model.d.ts +14 -0
  60. package/dist/modules/file-browser/dashboard-resource.d.ts +12 -0
  61. package/dist/modules/file-browser/experience-dashboard-pane.d.ts +8 -0
  62. package/dist/modules/file-browser/experience-data.d.ts +31 -0
  63. package/dist/modules/file-browser/file-browser-labels.d.ts +1 -1
  64. package/dist/modules/file-browser/file-browser-tree-pane.d.ts +3 -2
  65. package/dist/modules/file-browser/file-browser.d.ts +1 -1
  66. package/dist/modules/file-browser/fs-directories.d.ts +8 -0
  67. package/dist/modules/file-browser/fs-lines.d.ts +36 -0
  68. package/dist/modules/file-browser/fs-memory-fields.d.ts +65 -0
  69. package/dist/modules/file-browser/fs-model.d.ts +12 -2
  70. package/dist/modules/file-browser/fs-read-file.d.ts +14 -0
  71. package/dist/modules/file-browser/fs-selection.d.ts +4 -0
  72. package/dist/modules/file-browser/index.d.ts +2 -2
  73. package/dist/modules/file-browser/style.css +1768 -24
  74. package/dist/modules/file-browser/types.d.ts +62 -0
  75. package/dist/modules/file-browser/use-browser-dashboards.d.ts +31 -0
  76. package/dist/modules/file-browser/use-dashboard-query.d.ts +9 -0
  77. package/dist/modules/file-browser/use-experience-dashboard.d.ts +27 -0
  78. package/dist/modules/file-browser/use-file-browser.d.ts +2 -45
  79. package/dist/modules/file-browser/use-fs-tree.d.ts +2 -0
  80. package/dist/modules/file-browser/use-wiki-dashboard.d.ts +17 -0
  81. package/dist/modules/file-browser/wiki-conflicts.d.ts +12 -0
  82. package/dist/modules/file-browser/wiki-dashboard-pane.d.ts +14 -0
  83. package/dist/modules/file-browser.js +1 -1
  84. package/dist/modules/scope-cascade/controller.d.ts +2 -2
  85. package/dist/modules/scope-cascade/index.d.ts +1 -2
  86. package/dist/modules/scope-cascade/scope-cascade.d.ts +1 -1
  87. package/dist/modules/scope-cascade/style.css +48 -4
  88. package/dist/modules/scope-cascade/types.d.ts +8 -3
  89. package/dist/modules/scope-cascade/use-scope-cascade.d.ts +2 -2
  90. package/dist/modules/scope-cascade.js +1 -1
  91. package/dist/modules/style.css +2344 -191
  92. package/dist/n~0.js +13 -129
  93. package/dist/rt~0.js +152 -0
  94. package/dist/r~0.js +17 -38
  95. package/dist/shared/components/popover/popover.d.ts +1 -1
  96. package/dist/shared/components/popover/types.d.ts +7 -1
  97. package/dist/shared/dashboard/dashboard-state.d.ts +12 -0
  98. package/dist/static/image/dashboard-background.png +0 -0
  99. package/dist/style.css +8897 -4616
  100. package/dist/viking-bot-composer~0.js +1 -1
  101. package/package.json +12 -2
package/dist/f~0.js CHANGED
@@ -1,354 +1,700 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useId, useRef, useState } from "react";
3
- import { resolveLocale } from "./nx~0.js";
4
- import { checkreact } from "./0~0.js";
5
- import { searchreact } from "./p~0.js";
6
- import { useLocale, LocaleProvider } from "./28~0.js";
7
- const SvgChevronDown = (props)=>/*#__PURE__*/ jsx("svg", {
8
- xmlns: "http://www.w3.org/2000/svg",
9
- width: 14,
10
- height: 14,
11
- fill: "none",
12
- viewBox: "0 0 14 14",
13
- ...props,
14
- children: /*#__PURE__*/ jsx("path", {
15
- fill: "currentColor",
16
- d: "M9.607 5.232a.437.437 0 1 1 .619.619L7.309 8.768a.437.437 0 0 1-.618 0L3.774 5.85a.437.437 0 1 1 .619-.619L7 7.84z"
17
- })
2
+ import { useId, useState } from "react";
3
+ import { mergeLabels } from "./nx~0.js";
4
+ import { FileInputIcon, ScanSearchIcon, ActivityIcon } from "./k~0.js";
5
+ import { DashboardState } from "./37~0.js";
6
+ import { useLocale } from "./28~0.js";
7
+ function DashboardTabs({ tabs, active, label, onChange, children }) {
8
+ const id = useId();
9
+ return /*#__PURE__*/ jsxs(Fragment, {
10
+ children: [
11
+ /*#__PURE__*/ jsx("div", {
12
+ className: "ov-dashboard-tabs",
13
+ role: "tablist",
14
+ tabIndex: -1,
15
+ "aria-label": label,
16
+ onKeyDown: (event)=>{
17
+ const delta = 'ArrowRight' === event.key ? 1 : 'ArrowLeft' === event.key ? -1 : 0;
18
+ if (!delta && 'Home' !== event.key && 'End' !== event.key) return;
19
+ event.preventDefault();
20
+ const index = 'Home' === event.key ? 0 : 'End' === event.key ? tabs.length - 1 : (tabs.findIndex((tab)=>tab.key === active) + delta + tabs.length) % tabs.length;
21
+ onChange(tabs[index].key);
22
+ const buttons = event.currentTarget.querySelectorAll('[role="tab"]');
23
+ buttons[index]?.focus();
24
+ },
25
+ children: tabs.map((tab)=>/*#__PURE__*/ jsx("button", {
26
+ type: "button",
27
+ id: `${id}-${tab.key}`,
28
+ role: "tab",
29
+ "aria-selected": active === tab.key,
30
+ "aria-controls": `${id}-panel`,
31
+ tabIndex: active === tab.key ? 0 : -1,
32
+ onClick: ()=>onChange(tab.key),
33
+ children: tab.title
34
+ }, tab.key))
35
+ }),
36
+ /*#__PURE__*/ jsx("div", {
37
+ role: "tabpanel",
38
+ id: `${id}-panel`,
39
+ "aria-labelledby": `${id}-${active}`,
40
+ className: "ov-dashboard-tabpanel",
41
+ children: children
42
+ })
43
+ ]
18
44
  });
19
- const chevron_downreact = SvgChevronDown;
20
- const messages = {
45
+ }
46
+ const en = {
47
+ latest: 'Latest experience',
48
+ sourceCount: 'Generated from {count} trajectories',
49
+ sourceUri: 'Source Trajectory URI',
50
+ task: 'Task',
51
+ copy: 'Copy',
52
+ copied: 'Copied',
53
+ copyFailed: 'Copy failed',
54
+ title: 'Agent experiences',
55
+ allExperiences: 'All experiences',
56
+ index: 'No.',
57
+ impact: 'Application impact',
58
+ source: 'Source trace',
59
+ test: 'Test',
60
+ application: 'Experience application data',
61
+ notice: 'AI-generated data may contain errors',
62
+ injection: 'Context injections',
63
+ recall: 'Retrieval recalls',
64
+ listRecall: 'Experience recalls',
65
+ rate: 'Injection rate',
66
+ outcomes: 'Outcome distribution',
67
+ trajectories: 'Application trajectories',
68
+ empty: 'No experiences',
69
+ emptySource: 'No source records',
70
+ emptyTests: 'No test materials',
71
+ emptyOutcomes: 'No distribution data',
21
72
  loading: 'Loading…',
22
- searchPlaceholder: 'Search',
23
- empty: 'No options',
24
- noMatch: 'No matches',
25
- error: 'Unable to load options'
73
+ failed: 'Could not load data',
74
+ retry: 'Retry',
75
+ previous: 'Previous',
76
+ next: 'Next',
77
+ all: 'All time',
78
+ week: 'Last 7 days',
79
+ month: 'Last 30 days',
80
+ range: 'Statistics period',
81
+ updated: 'Updated',
82
+ name: 'Experience',
83
+ success: 'Task success',
84
+ partial: 'Partial success',
85
+ unfinished: 'Unfinished',
86
+ failure: 'Failure',
87
+ unknown: 'Unknown',
88
+ unsupportedMetric: 'Metric not provided',
89
+ open: 'Open'
26
90
  };
27
- const en_US = messages;
28
- const zh_CN_messages = {
91
+ const zh = {
92
+ latest: '最新经验',
93
+ sourceCount: '由 {count} 条轨迹生成',
94
+ sourceUri: '来源 Trajectory URI',
95
+ task: '任务描述',
96
+ copy: '复制',
97
+ copied: '已复制',
98
+ copyFailed: '复制失败',
99
+ title: 'Agent 经验',
100
+ allExperiences: '全部经验',
101
+ index: '序号',
102
+ impact: '应用效果',
103
+ source: '来源追溯',
104
+ test: '测试',
105
+ application: '经验应用数据',
106
+ notice: '数据由 AI 生成,可能有误',
107
+ injection: '注入上下文次数',
108
+ recall: '检索召回次数',
109
+ listRecall: '经验召回次数',
110
+ rate: '注入率',
111
+ outcomes: '任务结果分布',
112
+ trajectories: '应用轨迹记录',
113
+ empty: '暂无经验',
114
+ emptySource: '暂无来源记录',
115
+ emptyTests: '暂无测试材料',
116
+ emptyOutcomes: '暂无可用分布数据',
29
117
  loading: '加载中…',
30
- searchPlaceholder: '搜索',
31
- empty: '暂无选项',
32
- noMatch: '没有匹配项',
33
- error: '选项加载失败'
34
- };
35
- const zh_CN = zh_CN_messages;
36
- const LOCALES = {
37
- 'en-US': en_US,
38
- 'zh-CN': zh_CN
118
+ failed: '数据加载失败',
119
+ retry: '重试',
120
+ previous: '上一页',
121
+ next: '下一页',
122
+ all: '全部时间',
123
+ week: '最近 7 天',
124
+ month: '最近 30 天',
125
+ range: '选择统计时间范围',
126
+ updated: '更新于',
127
+ name: '经验文件',
128
+ success: '任务成功',
129
+ partial: '部分成功',
130
+ unfinished: '未完成',
131
+ failure: '失败',
132
+ unknown: '未知',
133
+ unsupportedMetric: '未提供此指标',
134
+ open: '打开'
39
135
  };
40
- function resolveScopeLabels(locale = 'en-US', labels) {
41
- const defaults = resolveLocale(LOCALES, locale, labels);
42
- return {
43
- ...defaults,
44
- noMatch: labels?.noMatch ?? labels?.empty ?? defaults.noMatch
45
- };
46
- }
47
- function moveScopeFocus(event) {
48
- if (![
49
- 'ArrowDown',
50
- 'ArrowUp',
51
- 'Home',
52
- 'End'
53
- ].includes(event.key)) return;
54
- const target = event.target;
55
- const isSearch = target.matches('input.ov-scope-switcher__search');
56
- if (event.defaultPrevented || !target.matches('[role="option"]') && !isSearch || isSearch && !event.key.startsWith('Arrow')) return;
57
- const options = Array.from(event.currentTarget.querySelectorAll('[role="option"]:not([aria-disabled="true"])'));
58
- if (!options.length) return;
59
- event.preventDefault();
60
- const current = options.indexOf(document.activeElement);
61
- const next = 'Home' === event.key ? 0 : 'End' === event.key ? options.length - 1 : 'ArrowDown' === event.key ? (current + 1) % options.length : current < 0 ? options.length - 1 : (current - 1 + options.length) % options.length;
62
- options[next]?.focus();
63
- }
64
- function Highlight({ text, keyword }) {
65
- const needle = keyword.trim().toLocaleLowerCase();
66
- if (!needle) return /*#__PURE__*/ jsx(Fragment, {
67
- children: text
68
- });
69
- const haystack = text.toLocaleLowerCase();
70
- const parts = [];
71
- let cursor = 0;
72
- let hit = haystack.indexOf(needle);
73
- while(hit >= 0){
74
- if (hit > cursor) parts.push(text.slice(cursor, hit));
75
- const end = hit + needle.length;
76
- parts.push(/*#__PURE__*/ jsx("mark", {
77
- children: text.slice(hit, end)
78
- }, `${hit}-${end}`));
79
- cursor = end;
80
- hit = haystack.indexOf(needle, cursor);
81
- }
82
- if (cursor < text.length) parts.push(text.slice(cursor));
83
- return /*#__PURE__*/ jsx(Fragment, {
84
- children: parts
85
- });
136
+ const experienceLabels = (locale, labels)=>mergeLabels('zh-CN' === locale ? zh : en, labels);
137
+ function updatedAt(value, locale) {
138
+ const time = Date.parse(value);
139
+ if (!Number.isFinite(time)) return value;
140
+ const seconds = (time - Date.now()) / 1000;
141
+ const absolute = Math.abs(seconds);
142
+ if (absolute >= 604800) return new Intl.DateTimeFormat(locale).format(time);
143
+ const [unit, size] = absolute < 3600 ? [
144
+ 'minute',
145
+ 60
146
+ ] : absolute < 86400 ? [
147
+ 'hour',
148
+ 3600
149
+ ] : [
150
+ 'day',
151
+ 86400
152
+ ];
153
+ return new Intl.RelativeTimeFormat(locale, {
154
+ numeric: 'always'
155
+ }).format(Math.round(seconds / size), unit);
86
156
  }
87
- function ScopePanel({ label, data, state, slots, actions, onSelect, labels }) {
88
- const focusPanel = useCallback((node)=>{
89
- const target = node?.querySelector('input') ?? node?.querySelector('[role="option"][aria-selected="true"]:not([aria-disabled="true"])') ?? node?.querySelector('[role="option"]:not([aria-disabled="true"])');
90
- (target ?? node)?.focus();
91
- }, []);
92
- const options = data.visibleOptions ?? data.options;
93
- const keyword = state?.searchKeyword ?? '';
94
- const hasKeyword = keyword.trim().length > 0;
95
- const searchVisible = actions?.onSearchKeywordChange && (hasKeyword || Math.max(options.length, data.options.length, data.total ?? 0) > 10);
96
- const search = searchVisible ? /*#__PURE__*/ jsxs("div", {
97
- className: "ov-scope-switcher__search-field",
157
+ function ExperienceList({ items, total, startIndex = 0, locale = 'en-US', labels: t, onOpenUri }) {
158
+ return /*#__PURE__*/ jsxs(Fragment, {
98
159
  children: [
99
- /*#__PURE__*/ jsx(searchreact, {
100
- className: "ov-scope-switcher__search-icon"
160
+ /*#__PURE__*/ jsxs("h2", {
161
+ className: "ov-experience-dashboard__list-title",
162
+ children: [
163
+ t.allExperiences,
164
+ void 0 === total ? '' : ` · ${total}`
165
+ ]
101
166
  }),
102
- /*#__PURE__*/ jsx("input", {
103
- type: "search",
104
- className: "ov-scope-switcher__search",
105
- value: keyword,
106
- "aria-label": labels.searchPlaceholder,
107
- placeholder: labels.searchPlaceholder,
108
- onChange: (event)=>actions?.onSearchKeywordChange?.(event.currentTarget.value)
167
+ /*#__PURE__*/ jsx("div", {
168
+ className: "ov-experience-dashboard__table-scroll",
169
+ tabIndex: 0,
170
+ role: "region",
171
+ "aria-label": t.title,
172
+ children: /*#__PURE__*/ jsxs("table", {
173
+ className: "ov-experience-dashboard__table",
174
+ children: [
175
+ /*#__PURE__*/ jsx("caption", {
176
+ children: t.title
177
+ }),
178
+ /*#__PURE__*/ jsx("thead", {
179
+ children: /*#__PURE__*/ jsxs("tr", {
180
+ children: [
181
+ /*#__PURE__*/ jsx("th", {
182
+ scope: "col",
183
+ children: t.index
184
+ }),
185
+ /*#__PURE__*/ jsx("th", {
186
+ scope: "col",
187
+ children: t.name
188
+ }),
189
+ /*#__PURE__*/ jsx("th", {
190
+ scope: "col",
191
+ children: t.injection
192
+ }),
193
+ /*#__PURE__*/ jsx("th", {
194
+ scope: "col",
195
+ children: t.listRecall
196
+ })
197
+ ]
198
+ })
199
+ }),
200
+ /*#__PURE__*/ jsx("tbody", {
201
+ children: items.map((item, index)=>/*#__PURE__*/ jsxs("tr", {
202
+ children: [
203
+ /*#__PURE__*/ jsxs("td", {
204
+ children: [
205
+ "# ",
206
+ startIndex + index + 1
207
+ ]
208
+ }),
209
+ /*#__PURE__*/ jsxs("th", {
210
+ scope: "row",
211
+ children: [
212
+ /*#__PURE__*/ jsx("button", {
213
+ type: "button",
214
+ disabled: !onOpenUri,
215
+ onClick: ()=>onOpenUri?.(item.uri),
216
+ children: item.name
217
+ }),
218
+ /*#__PURE__*/ jsxs("span", {
219
+ children: [
220
+ /*#__PURE__*/ jsx("code", {
221
+ title: item.uri,
222
+ children: item.uri
223
+ }),
224
+ item.modTime ? /*#__PURE__*/ jsxs("time", {
225
+ dateTime: item.modTime,
226
+ title: item.modTime,
227
+ children: [
228
+ "\xb7 ",
229
+ t.updated,
230
+ " ",
231
+ updatedAt(item.modTime, locale)
232
+ ]
233
+ }) : null
234
+ ]
235
+ })
236
+ ]
237
+ }),
238
+ /*#__PURE__*/ jsx("td", {
239
+ children: item.injectionCount ?? '—'
240
+ }),
241
+ /*#__PURE__*/ jsx("td", {
242
+ children: item.recallCount ?? '—'
243
+ })
244
+ ]
245
+ }, item.uri))
246
+ })
247
+ ]
248
+ })
109
249
  })
110
250
  ]
111
- }) : null;
112
- let list;
113
- list = state?.loading ? /*#__PURE__*/ jsx("div", {
114
- className: "ov-scope-switcher__state",
115
- role: "status",
116
- children: labels.loading
117
- }) : state?.error ? /*#__PURE__*/ jsx("div", {
118
- className: "ov-scope-switcher__state",
119
- role: "alert",
120
- children: slots?.errorFallback ?? labels.error
121
- }) : options.length ? /*#__PURE__*/ jsx("div", {
122
- className: "ov-scope-switcher__list",
123
- role: "listbox",
124
- "aria-label": label,
125
- "aria-busy": state?.busy,
126
- onScroll: (event)=>{
127
- const { scrollTop, scrollHeight, clientHeight } = event.currentTarget;
128
- actions?.onScroll?.({
129
- scrollTop,
130
- scrollHeight,
131
- clientHeight
132
- });
133
- },
134
- children: options.map((option)=>{
135
- const selected = option.id === data.selectedId;
136
- const content = /*#__PURE__*/ jsxs(Fragment, {
251
+ });
252
+ }
253
+ function ExperienceTrajectories({ items, onOpenUri, source = false }) {
254
+ return /*#__PURE__*/ jsx("ul", {
255
+ className: `ov-experience-dashboard__timeline${source ? ' ov-experience-dashboard__timeline--source' : ''}`,
256
+ children: items.map((item)=>/*#__PURE__*/ jsxs("li", {
137
257
  children: [
138
- option.icon && /*#__PURE__*/ jsx("span", {
139
- className: "ov-scope-switcher__icon",
140
- "aria-hidden": "true",
141
- children: option.icon
258
+ item.created_at ? /*#__PURE__*/ jsx("time", {
259
+ dateTime: item.created_at,
260
+ children: item.created_at
261
+ }) : null,
262
+ /*#__PURE__*/ jsx("button", {
263
+ type: "button",
264
+ disabled: !onOpenUri,
265
+ onClick: ()=>onOpenUri?.(item.uri),
266
+ children: item.name
267
+ }),
268
+ /*#__PURE__*/ jsx("code", {
269
+ children: item.uri
142
270
  }),
143
- /*#__PURE__*/ jsxs("span", {
144
- className: "ov-scope-switcher__option-text",
271
+ item.description ? /*#__PURE__*/ jsx("p", {
272
+ children: item.description
273
+ }) : null
274
+ ]
275
+ }, item.uri))
276
+ });
277
+ }
278
+ const ORDER = [
279
+ 'success',
280
+ 'partial',
281
+ 'unfinished',
282
+ 'failure',
283
+ 'unknown'
284
+ ];
285
+ function ExperienceImpact({ data, labels: t, days, onDaysChange, outcomesState, trajectoriesState, onOpenUri }) {
286
+ const total = data.outcomes?.reduce((sum, item)=>sum + item.count, 0) ?? 0;
287
+ const metrics = [
288
+ {
289
+ label: t.injection,
290
+ value: data.effect?.injectionCount,
291
+ icon: /*#__PURE__*/ jsx(FileInputIcon, {
292
+ width: 14,
293
+ height: 14
294
+ })
295
+ },
296
+ {
297
+ label: t.recall,
298
+ value: data.effect?.recallCount,
299
+ icon: /*#__PURE__*/ jsx(ScanSearchIcon, {
300
+ width: 14,
301
+ height: 14
302
+ })
303
+ },
304
+ {
305
+ label: t.rate,
306
+ value: data.effect ? new Intl.NumberFormat('en-US', {
307
+ style: 'percent',
308
+ maximumFractionDigits: 1
309
+ }).format(data.effect.injectionRate) : void 0,
310
+ icon: /*#__PURE__*/ jsx(ActivityIcon, {
311
+ width: 14,
312
+ height: 14
313
+ })
314
+ }
315
+ ];
316
+ return /*#__PURE__*/ jsxs("div", {
317
+ className: "ov-experience-dashboard__impact",
318
+ children: [
319
+ /*#__PURE__*/ jsxs("div", {
320
+ className: "ov-experience-dashboard__heading",
321
+ children: [
322
+ /*#__PURE__*/ jsxs("div", {
145
323
  children: [
324
+ /*#__PURE__*/ jsx("h2", {
325
+ children: t.application
326
+ }),
146
327
  /*#__PURE__*/ jsx("span", {
147
- children: /*#__PURE__*/ jsx(Highlight, {
148
- text: option.label,
149
- keyword: keyword
150
- })
328
+ children: t.notice
329
+ })
330
+ ]
331
+ }),
332
+ /*#__PURE__*/ jsxs("select", {
333
+ "aria-label": t.range,
334
+ value: days,
335
+ onChange: (event)=>onDaysChange(Number(event.target.value)),
336
+ children: [
337
+ /*#__PURE__*/ jsx("option", {
338
+ value: 7,
339
+ children: t.week
340
+ }),
341
+ /*#__PURE__*/ jsx("option", {
342
+ value: 30,
343
+ children: t.month
344
+ }),
345
+ /*#__PURE__*/ jsx("option", {
346
+ value: 0,
347
+ children: t.all
348
+ })
349
+ ]
350
+ })
351
+ ]
352
+ }),
353
+ /*#__PURE__*/ jsx("dl", {
354
+ className: "ov-experience-dashboard__metrics",
355
+ children: metrics.map((metric)=>/*#__PURE__*/ jsxs("div", {
356
+ title: void 0 === metric.value ? t.unsupportedMetric : void 0,
357
+ children: [
358
+ metric.icon,
359
+ /*#__PURE__*/ jsx("dd", {
360
+ children: metric.value ?? '—'
361
+ }),
362
+ /*#__PURE__*/ jsx("dt", {
363
+ children: metric.label
364
+ })
365
+ ]
366
+ }, metric.label))
367
+ }),
368
+ /*#__PURE__*/ jsx("section", {
369
+ className: "ov-experience-dashboard__distribution",
370
+ "aria-label": t.outcomes,
371
+ children: data.outcomes?.length ? ORDER.map((outcome)=>{
372
+ const count = data.outcomes?.find((item)=>item.outcome === outcome)?.count ?? 0;
373
+ return /*#__PURE__*/ jsxs("div", {
374
+ className: "ov-experience-dashboard__outcome",
375
+ children: [
376
+ /*#__PURE__*/ jsxs("div", {
377
+ children: [
378
+ /*#__PURE__*/ jsx("span", {
379
+ children: t[outcome]
380
+ }),
381
+ /*#__PURE__*/ jsx("strong", {
382
+ children: count
383
+ })
384
+ ]
151
385
  }),
152
- option.description && /*#__PURE__*/ jsx("small", {
153
- children: option.description
386
+ /*#__PURE__*/ jsx("div", {
387
+ className: "ov-experience-dashboard__outcome-track",
388
+ "aria-hidden": "true",
389
+ children: /*#__PURE__*/ jsx("span", {
390
+ style: {
391
+ width: `${total > 0 ? Math.max(count / total * 100, count ? 2 : 0) : 0}%`
392
+ }
393
+ })
154
394
  })
155
395
  ]
396
+ }, outcome);
397
+ }) : /*#__PURE__*/ jsx(DashboardState, {
398
+ state: outcomesState,
399
+ empty: t.emptyOutcomes,
400
+ loading: t.loading,
401
+ failed: t.failed,
402
+ retry: t.retry
403
+ })
404
+ }),
405
+ /*#__PURE__*/ jsxs("section", {
406
+ className: "ov-experience-dashboard__trajectories",
407
+ children: [
408
+ /*#__PURE__*/ jsxs("h3", {
409
+ children: [
410
+ t.trajectories,
411
+ void 0 === data.trajectoryTotal ? '' : ` · ${data.trajectoryTotal}`
412
+ ]
156
413
  }),
157
- selected && /*#__PURE__*/ jsx("span", {
158
- className: "ov-scope-switcher__check",
159
- "aria-hidden": "true",
160
- children: /*#__PURE__*/ jsx(checkreact, {})
414
+ data.trajectories?.length ? /*#__PURE__*/ jsx(ExperienceTrajectories, {
415
+ items: data.trajectories,
416
+ onOpenUri: onOpenUri
417
+ }) : /*#__PURE__*/ jsx(DashboardState, {
418
+ state: trajectoriesState,
419
+ empty: t.empty,
420
+ loading: t.loading,
421
+ failed: t.failed,
422
+ retry: t.retry
161
423
  })
162
424
  ]
425
+ })
426
+ ]
427
+ });
428
+ }
429
+ function CopyButton({ value, labels: t }) {
430
+ const [result, setResult] = useState();
431
+ const state = result?.value === value ? result.state : void 0;
432
+ const copy = async ()=>{
433
+ setResult({
434
+ value,
435
+ state: 'pending'
436
+ });
437
+ try {
438
+ await navigator.clipboard.writeText(value);
439
+ setResult({
440
+ value,
441
+ state: 'copied'
163
442
  });
164
- return /*#__PURE__*/ jsx("div", {
165
- tabIndex: option.disabled || state?.busy ? -1 : 0,
166
- role: "option",
167
- "aria-selected": selected,
168
- className: "ov-scope-switcher__option",
169
- title: option.label,
170
- "aria-disabled": option.disabled || state?.busy || void 0,
171
- onClick: (event)=>{
172
- const target = event.target;
173
- if (option.disabled || state?.busy || target.closest('button, a, input, select, textarea, [role="button"]')) return;
174
- onSelect(option);
175
- },
176
- onKeyDown: (event)=>{
177
- if (event.target !== event.currentTarget || option.disabled || state?.busy) return;
178
- if ('Enter' === event.key || ' ' === event.key) {
179
- event.preventDefault();
180
- onSelect(option);
181
- }
182
- },
183
- children: slots?.renderOption ? slots?.renderOption(content, option) : content
184
- }, option.id);
185
- })
186
- }, keyword) : /*#__PURE__*/ jsx("div", {
187
- className: "ov-scope-switcher__state",
188
- role: "status",
189
- children: slots?.emptyFallback ?? (hasKeyword ? labels.noMatch : labels.empty)
443
+ } catch {
444
+ setResult({
445
+ value,
446
+ state: 'failed'
447
+ });
448
+ }
449
+ };
450
+ return /*#__PURE__*/ jsx("button", {
451
+ type: "button",
452
+ disabled: !value || 'pending' === state,
453
+ "aria-live": "polite",
454
+ onClick: ()=>void copy(),
455
+ children: 'copied' === state ? t.copied : 'failed' === state ? t.copyFailed : t.copy
190
456
  });
457
+ }
458
+ function ExperienceTests({ items, labels: t, onOpenUri }) {
191
459
  return /*#__PURE__*/ jsx("div", {
192
- role: "group",
193
- tabIndex: -1,
194
- ref: focusPanel,
195
- className: "ov-scope-switcher__panel-inner",
196
- onKeyDownCapture: moveScopeFocus,
197
- children: slots?.renderPanel ? slots?.renderPanel({
198
- search,
199
- list
200
- }) : /*#__PURE__*/ jsxs("div", {
201
- className: "ov-scope-switcher__panel-body",
202
- children: [
203
- search,
204
- list
205
- ]
206
- })
460
+ className: "ov-experience-dashboard__tests",
461
+ children: items.map((item)=>/*#__PURE__*/ jsxs("article", {
462
+ children: [
463
+ /*#__PURE__*/ jsxs("header", {
464
+ children: [
465
+ /*#__PURE__*/ jsxs("div", {
466
+ className: "ov-experience-dashboard__test-heading",
467
+ children: [
468
+ /*#__PURE__*/ jsx("strong", {
469
+ children: item.title
470
+ }),
471
+ /*#__PURE__*/ jsxs("div", {
472
+ className: "ov-experience-dashboard__test-meta",
473
+ children: [
474
+ /*#__PURE__*/ jsx("span", {
475
+ children: t.sourceUri
476
+ }),
477
+ /*#__PURE__*/ jsx("code", {
478
+ title: item.uri,
479
+ children: item.uri ?? '—'
480
+ }),
481
+ item.uri ? /*#__PURE__*/ jsxs(Fragment, {
482
+ children: [
483
+ /*#__PURE__*/ jsx(CopyButton, {
484
+ value: item.uri,
485
+ labels: t
486
+ }),
487
+ /*#__PURE__*/ jsx("button", {
488
+ type: "button",
489
+ disabled: !onOpenUri,
490
+ onClick: ()=>item.uri && onOpenUri?.(item.uri),
491
+ children: t.open
492
+ })
493
+ ]
494
+ }) : null
495
+ ]
496
+ }),
497
+ item.taskQuery ? /*#__PURE__*/ jsxs("div", {
498
+ className: "ov-experience-dashboard__test-meta",
499
+ children: [
500
+ /*#__PURE__*/ jsx("span", {
501
+ children: t.task
502
+ }),
503
+ /*#__PURE__*/ jsx("p", {
504
+ children: item.taskQuery
505
+ })
506
+ ]
507
+ }) : null
508
+ ]
509
+ }),
510
+ /*#__PURE__*/ jsx(CopyButton, {
511
+ value: item.content,
512
+ labels: t
513
+ })
514
+ ]
515
+ }),
516
+ /*#__PURE__*/ jsx("div", {
517
+ className: "ov-experience-dashboard__test-content",
518
+ children: item.content.split('\n').map((line, index)=>{
519
+ const role = line.match(/^(User|Assistant):(.*)$/);
520
+ return /*#__PURE__*/ jsx("div", {
521
+ children: role ? /*#__PURE__*/ jsxs(Fragment, {
522
+ children: [
523
+ /*#__PURE__*/ jsxs("strong", {
524
+ children: [
525
+ role[1],
526
+ ":"
527
+ ]
528
+ }),
529
+ role[2]
530
+ ]
531
+ }) : line.startsWith('# ') ? /*#__PURE__*/ jsx("strong", {
532
+ children: line
533
+ }) : line || '\u00a0'
534
+ }, index);
535
+ })
536
+ })
537
+ ]
538
+ }, item.id))
207
539
  });
208
540
  }
209
- function ScopeSelector(props) {
210
- const { identity, trigger: triggerContent } = props;
211
- const locale = useLocale(props.locale);
212
- const labels = resolveScopeLabels(locale, props.labels);
213
- const selectable = 'selectable' === props.kind ? props : void 0;
214
- const data = selectable?.data;
215
- const state = selectable?.state;
216
- const actions = selectable?.actions;
217
- const slots = selectable?.slots;
218
- const [localVisible, setLocalVisible] = useState(false);
219
- const root = useRef(null);
220
- const trigger = useRef(null);
221
- const restoreSelectionFocus = useRef(false);
222
- const panelId = useId();
223
- const open = void 0 !== selectable && (state?.visible ?? localVisible) && !state?.disabled;
224
- const onVisibleChange = actions?.onVisibleChange;
225
- const changeVisible = useCallback((visible)=>{
226
- setLocalVisible(visible);
227
- onVisibleChange?.(visible);
228
- }, [
229
- onVisibleChange
230
- ]);
231
- useEffect(()=>{
232
- if (!open) return;
233
- const dismiss = (event)=>{
234
- if (event.target instanceof Node && !root.current?.contains(event.target)) changeVisible(false);
235
- };
236
- const escape = (event)=>{
237
- if ('Escape' === event.key) {
238
- event.preventDefault();
239
- changeVisible(false);
240
- trigger.current?.focus();
241
- }
242
- };
243
- document.addEventListener('pointerdown', dismiss);
244
- document.addEventListener('keydown', escape);
245
- return ()=>{
246
- document.removeEventListener('pointerdown', dismiss);
247
- document.removeEventListener('keydown', escape);
248
- };
249
- }, [
250
- open,
251
- changeVisible
252
- ]);
253
- useEffect(()=>{
254
- if (open || !restoreSelectionFocus.current) return;
255
- restoreSelectionFocus.current = false;
256
- if (document.activeElement === document.body || root.current?.contains(document.activeElement)) trigger.current?.focus();
257
- }, [
258
- open
259
- ]);
260
- const selected = data?.options.find((o)=>o.id === data.selectedId);
261
- const label = triggerContent?.label ?? selected?.label ?? '';
262
- const icon = triggerContent?.icon ?? selected?.icon;
263
- const content = /*#__PURE__*/ jsxs(Fragment, {
541
+ function ExperiencePagination({ page, hasMore, loading, labels: t, onPageChange }) {
542
+ if (!page && !hasMore) return null;
543
+ return /*#__PURE__*/ jsxs("div", {
544
+ className: "ov-experience-dashboard__pagination",
264
545
  children: [
265
- icon && /*#__PURE__*/ jsx("span", {
266
- className: "ov-scope-switcher__icon",
267
- "aria-hidden": "true",
268
- children: icon
546
+ /*#__PURE__*/ jsx("button", {
547
+ type: "button",
548
+ disabled: !page || loading || !onPageChange,
549
+ onClick: ()=>onPageChange?.(page - 1),
550
+ children: t.previous
269
551
  }),
270
552
  /*#__PURE__*/ jsx("span", {
271
- className: "ov-scope-switcher__label",
272
- children: label
553
+ children: page + 1
273
554
  }),
274
- identity.tag && /*#__PURE__*/ jsx("span", {
275
- className: "ov-scope-switcher__tag",
276
- children: identity.tag
277
- })
278
- ]
279
- });
280
- return /*#__PURE__*/ jsxs("div", {
281
- ref: root,
282
- role: "group",
283
- className: "ov-scope-switcher__level",
284
- onBlur: (event)=>{
285
- if (open && event.relatedTarget instanceof Node && !event.currentTarget.contains(event.relatedTarget)) changeVisible(false);
286
- },
287
- children: [
288
- void 0 === selectable ? /*#__PURE__*/ jsx("span", {
289
- className: "ov-scope-switcher__trigger",
290
- "aria-label": identity.ariaLabel,
291
- title: label,
292
- children: content
293
- }) : /*#__PURE__*/ jsxs("button", {
294
- ref: trigger,
555
+ /*#__PURE__*/ jsx("button", {
295
556
  type: "button",
296
- className: "ov-scope-switcher__trigger",
297
- "aria-label": identity.ariaLabel,
298
- title: label,
299
- disabled: state?.disabled,
300
- "aria-expanded": open,
301
- "aria-haspopup": "dialog",
302
- "aria-controls": open ? panelId : void 0,
303
- onClick: ()=>changeVisible(!open),
304
- onKeyDown: (event)=>{
305
- if ('ArrowDown' === event.key || 'ArrowUp' === event.key) {
306
- event.preventDefault();
307
- if (open) root.current?.querySelector('[role="option"]:not([aria-disabled="true"])')?.focus();
308
- else changeVisible(true);
309
- }
310
- },
311
- children: [
312
- content,
313
- /*#__PURE__*/ jsx("span", {
314
- className: "ov-scope-switcher__arrow",
315
- "aria-hidden": "true",
316
- children: /*#__PURE__*/ jsx(chevron_downreact, {})
317
- })
318
- ]
319
- }),
320
- open && void 0 !== selectable && void 0 !== data && /*#__PURE__*/ jsx("div", {
321
- id: panelId,
322
- className: slots?.renderPanel ? 'ov-scope-switcher__panel ov-scope-switcher__panel--custom' : 'ov-scope-switcher__panel',
323
- role: "dialog",
324
- "aria-label": identity.ariaLabel ?? label,
325
- children: /*#__PURE__*/ jsx(ScopePanel, {
326
- label: identity.ariaLabel ?? label,
327
- data: data,
328
- state: state,
329
- slots: slots,
330
- actions: actions,
331
- onSelect: (option)=>{
332
- restoreSelectionFocus.current = true;
333
- changeVisible(false);
334
- actions?.onSelect?.(option);
335
- },
336
- labels: labels
337
- })
557
+ disabled: !hasMore || loading || !onPageChange,
558
+ onClick: ()=>onPageChange?.(page + 1),
559
+ children: t.next
338
560
  })
339
561
  ]
340
562
  });
341
563
  }
342
- function ScopeSwitcher({ locale: localeProp, children, className = '', ...props }) {
564
+ function ExperienceDashboard(props) {
565
+ return /*#__PURE__*/ jsx(ExperienceDashboardContent, {
566
+ ...props
567
+ }, props.uri);
568
+ }
569
+ function ExperienceDashboardContent({ uri, data = {}, kind, tab: controlledTab, days: controlledDays, page = 0, hasMore = false, startIndex = 0, states = {}, onTabChange, onDaysChange, onPageChange, locale: localeProp, onOpenUri, labels, className, ...rest }) {
343
570
  const locale = useLocale(localeProp);
344
- return /*#__PURE__*/ jsx(LocaleProvider, {
345
- locale: locale,
346
- children: /*#__PURE__*/ jsx("div", {
347
- lang: locale,
348
- ...props,
349
- className: `ov-scope-switcher ${className}`,
350
- children: children
571
+ const [localTab, setLocalTab] = useState('impact');
572
+ const [localDays, setLocalDays] = useState(7);
573
+ const selectedTab = controlledTab ?? localTab;
574
+ const missingTest = void 0 === data.testMaterials;
575
+ const tab = 'test' === selectedTab && missingTest ? 'impact' : selectedTab;
576
+ if ('test' === localTab && missingTest) setLocalTab('impact');
577
+ const days = controlledDays ?? localDays;
578
+ const setTab = (value)=>{
579
+ setLocalTab(value);
580
+ onTabChange?.(value);
581
+ };
582
+ const setDays = (value)=>{
583
+ setLocalDays(value);
584
+ onDaysChange?.(value);
585
+ };
586
+ const t = experienceLabels(locale, labels);
587
+ const directory = 'directory' === kind;
588
+ const result = data;
589
+ const tabs = [
590
+ {
591
+ key: 'impact',
592
+ title: t.impact
593
+ },
594
+ {
595
+ key: 'source',
596
+ title: t.source
597
+ },
598
+ ...void 0 === result.testMaterials ? [] : [
599
+ {
600
+ key: 'test',
601
+ title: t.test
602
+ }
603
+ ]
604
+ ];
605
+ const activeState = directory ? states.list : 'source' === tab ? states.sources : states.trajectories;
606
+ const pagination = /*#__PURE__*/ jsx(ExperiencePagination, {
607
+ page: page,
608
+ hasMore: hasMore,
609
+ loading: activeState?.loading,
610
+ labels: t,
611
+ onPageChange: onPageChange
612
+ });
613
+ return /*#__PURE__*/ jsx("div", {
614
+ ...rest,
615
+ "data-resource-uri": uri,
616
+ className: [
617
+ 'ov-experience-dashboard',
618
+ className
619
+ ].filter(Boolean).join(' '),
620
+ children: directory ? /*#__PURE__*/ jsxs("div", {
621
+ className: "ov-experience-dashboard__body",
622
+ children: [
623
+ result.experiences?.length ? /*#__PURE__*/ jsx(ExperienceList, {
624
+ items: result.experiences,
625
+ total: result.total,
626
+ locale: locale,
627
+ startIndex: startIndex,
628
+ labels: t,
629
+ onOpenUri: onOpenUri
630
+ }) : /*#__PURE__*/ jsx(DashboardState, {
631
+ state: states.list,
632
+ empty: t.empty,
633
+ loading: t.loading,
634
+ failed: t.failed,
635
+ retry: t.retry
636
+ }),
637
+ pagination
638
+ ]
639
+ }) : /*#__PURE__*/ jsx(DashboardTabs, {
640
+ tabs: tabs,
641
+ active: tab,
642
+ label: t.title,
643
+ onChange: setTab,
644
+ children: /*#__PURE__*/ jsx("div", {
645
+ className: "ov-experience-dashboard__body",
646
+ children: 'impact' === tab ? /*#__PURE__*/ jsxs(Fragment, {
647
+ children: [
648
+ /*#__PURE__*/ jsx(ExperienceImpact, {
649
+ data: result,
650
+ labels: t,
651
+ days: days,
652
+ onDaysChange: setDays,
653
+ outcomesState: states.outcomes ?? {},
654
+ trajectoriesState: states.trajectories ?? {},
655
+ onOpenUri: onOpenUri
656
+ }),
657
+ pagination
658
+ ]
659
+ }) : 'source' === tab ? result.sources?.length ? /*#__PURE__*/ jsxs("details", {
660
+ open: true,
661
+ className: "ov-experience-dashboard__source-group",
662
+ children: [
663
+ /*#__PURE__*/ jsxs("summary", {
664
+ children: [
665
+ /*#__PURE__*/ jsx("strong", {
666
+ children: t.latest
667
+ }),
668
+ /*#__PURE__*/ jsx("span", {
669
+ children: t.sourceCount.replace('{count}', String(result.sources.length))
670
+ })
671
+ ]
672
+ }),
673
+ /*#__PURE__*/ jsx(ExperienceTrajectories, {
674
+ items: result.sources,
675
+ source: true,
676
+ onOpenUri: onOpenUri
677
+ })
678
+ ]
679
+ }) : /*#__PURE__*/ jsx(DashboardState, {
680
+ state: states.sources,
681
+ empty: t.emptySource,
682
+ loading: t.loading,
683
+ failed: t.failed,
684
+ retry: t.retry
685
+ }) : result.testMaterials?.length ? /*#__PURE__*/ jsx(ExperienceTests, {
686
+ items: result.testMaterials,
687
+ labels: t,
688
+ onOpenUri: onOpenUri
689
+ }) : /*#__PURE__*/ jsx(DashboardState, {
690
+ state: states.tests,
691
+ empty: t.emptyTests,
692
+ loading: t.loading,
693
+ failed: t.failed,
694
+ retry: t.retry
695
+ })
696
+ })
351
697
  })
352
698
  });
353
699
  }
354
- export { ScopeSelector, ScopeSwitcher };
700
+ export { ExperienceDashboard };