@openviking/react 0.1.6 → 0.1.8-beta.10.1.g8e5299efeb0a

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 (172) hide show
  1. package/README.md +13 -1
  2. package/dist/1~0.js +57 -0
  3. package/dist/2~0.js +6 -5
  4. package/dist/3c~0.js +10 -4
  5. package/dist/3~0.js +189 -13
  6. package/dist/5~0.js +181 -0
  7. package/dist/6~0.js +48 -0
  8. package/dist/ae~0.js +8 -1
  9. package/dist/ark-message-list-view~0.js +9 -4
  10. package/dist/a~0.js +12 -6
  11. package/dist/c7r~0.js +50 -0
  12. package/dist/ck~0.js +3 -0
  13. package/dist/client/paths.d.ts +6 -0
  14. package/dist/client/provider.d.ts +6 -1
  15. package/dist/components/agent-connect/style.css +224 -35
  16. package/dist/components/api-key-login-form/api-key-login-form.d.ts +2 -0
  17. package/dist/components/api-key-login-form/index.d.ts +3 -0
  18. package/dist/components/api-key-login-form/style.css +438 -0
  19. package/dist/components/api-key-login-form/style.js +0 -0
  20. package/dist/components/api-key-login-form/types.d.ts +7 -0
  21. package/dist/components/api-key-login-form.js +1 -0
  22. package/dist/components/directory-tour/directory-tour-intro.d.ts +3 -0
  23. package/dist/components/directory-tour/index.d.ts +2 -1
  24. package/dist/components/directory-tour/style.css +367 -39
  25. package/dist/components/directory-tour/tour-card.d.ts +14 -0
  26. package/dist/components/directory-tour/types.d.ts +24 -1
  27. package/dist/components/directory-tour/use-tour-anchor.d.ts +1 -0
  28. package/dist/components/directory-tour/use-tour-position.d.ts +4 -1
  29. package/dist/components/directory-tour/use-tour-theme.d.ts +2 -0
  30. package/dist/components/directory-tour.js +53 -2
  31. package/dist/components/email-login-form/email-login-form.d.ts +2 -0
  32. package/dist/components/email-login-form/index.d.ts +3 -0
  33. package/dist/components/email-login-form/style.css +438 -0
  34. package/dist/components/email-login-form/style.js +0 -0
  35. package/dist/components/email-login-form/types.d.ts +11 -0
  36. package/dist/components/email-login-form.js +1 -0
  37. package/dist/components/experience-dashboard/experience-impact.d.ts +3 -1
  38. package/dist/components/experience-dashboard/style.css +229 -12
  39. package/dist/components/experience-dashboard.js +1 -1
  40. package/dist/components/file-browser-entries/style.css +331 -80
  41. package/dist/components/file-preview/file-preview-header.d.ts +4 -21
  42. package/dist/components/file-preview/file-preview-toolbar.d.ts +7 -0
  43. package/dist/components/file-preview/locales/en-US.d.ts +9 -0
  44. package/dist/components/file-preview/locales/zh-CN.d.ts +9 -0
  45. package/dist/components/file-preview/style.css +335 -76
  46. package/dist/components/file-preview/types.d.ts +14 -21
  47. package/dist/components/file-tree/file-tree-toolbar.d.ts +3 -3
  48. package/dist/components/file-tree/locales/en-US.d.ts +3 -0
  49. package/dist/components/file-tree/locales/zh-CN.d.ts +3 -0
  50. package/dist/components/file-tree/style.css +313 -86
  51. package/dist/components/file-tree/types.d.ts +13 -4
  52. package/dist/components/invitation-confirmation/index.d.ts +3 -0
  53. package/dist/components/invitation-confirmation/invitation-confirmation.d.ts +2 -0
  54. package/dist/components/invitation-confirmation/style.css +438 -0
  55. package/dist/components/invitation-confirmation/style.js +0 -0
  56. package/dist/components/invitation-confirmation/types.d.ts +20 -0
  57. package/dist/components/invitation-confirmation.js +1 -0
  58. package/dist/components/login-method-selector/index.d.ts +2 -0
  59. package/dist/components/login-method-selector/login-method-selector.d.ts +2 -0
  60. package/dist/components/login-method-selector/style.css +438 -0
  61. package/dist/components/login-method-selector/style.js +0 -0
  62. package/dist/components/login-method-selector/types.d.ts +14 -0
  63. package/dist/components/login-method-selector.js +1 -0
  64. package/dist/components/password-reset-request-form/index.d.ts +3 -0
  65. package/dist/components/password-reset-request-form/password-reset-request-form.d.ts +2 -0
  66. package/dist/components/password-reset-request-form/style.css +438 -0
  67. package/dist/components/password-reset-request-form/style.js +0 -0
  68. package/dist/components/password-reset-request-form/types.d.ts +13 -0
  69. package/dist/components/password-reset-request-form.js +1 -0
  70. package/dist/components/password-setup-form/index.d.ts +3 -0
  71. package/dist/components/password-setup-form/password-setup-form.d.ts +2 -0
  72. package/dist/components/password-setup-form/style.css +438 -0
  73. package/dist/components/password-setup-form/style.js +0 -0
  74. package/dist/components/password-setup-form/types.d.ts +10 -0
  75. package/dist/components/password-setup-form.js +1 -0
  76. package/dist/components/scope-switcher/style.css +368 -37
  77. package/dist/components/style.css +13071 -7474
  78. package/dist/components/tui/style.css +271 -35
  79. package/dist/components/viking-bot/interaction/style.css +143 -22
  80. package/dist/components/viking-bot/style.css +951 -295
  81. package/dist/components/wiki-dashboard/index.d.ts +1 -1
  82. package/dist/components/wiki-dashboard/style.css +241 -14
  83. package/dist/components/wiki-dashboard/types.d.ts +12 -16
  84. package/dist/components/wiki-dashboard/wiki-action-button.d.ts +2 -9
  85. package/dist/components/wiki-dashboard/wiki-conflict-card.d.ts +3 -10
  86. package/dist/c~0.js +16 -8
  87. package/dist/d~0.js +28 -0
  88. package/dist/ep~0.js +493 -0
  89. package/dist/e~0.js +33 -328
  90. package/dist/fi~0.js +13 -28
  91. package/dist/fj~0.js +38 -69
  92. package/dist/fl~0.js +710 -0
  93. package/dist/f~0.js +61 -685
  94. package/dist/g~0.js +135 -0
  95. package/dist/icons/index.d.ts +2 -0
  96. package/dist/icons.js +1 -1
  97. package/dist/index.d.ts +12 -0
  98. package/dist/index.js +9 -3
  99. package/dist/k~0.js +44 -4
  100. package/dist/l5~0.js +3813 -0
  101. package/dist/lk~0.js +5 -2
  102. package/dist/l~0.js +49 -2369
  103. package/dist/modules/console/style.css +1485 -351
  104. package/dist/modules/file-browser/acl/acl-add-principal.d.ts +12 -0
  105. package/dist/modules/file-browser/acl/acl-candidate.d.ts +8 -0
  106. package/dist/modules/file-browser/acl/acl-client.d.ts +13 -0
  107. package/dist/modules/file-browser/acl/acl-confirmation.d.ts +6 -0
  108. package/dist/modules/file-browser/acl/acl-entry.d.ts +13 -0
  109. package/dist/modules/file-browser/acl/acl-labels.d.ts +47 -0
  110. package/dist/modules/file-browser/acl/acl-menu.d.ts +10 -0
  111. package/dist/modules/file-browser/acl/acl-modal.d.ts +17 -0
  112. package/dist/modules/file-browser/acl/acl-model.d.ts +17 -0
  113. package/dist/modules/file-browser/acl/acl-principal-tabs.d.ts +6 -0
  114. package/dist/modules/file-browser/acl/acl-tag.d.ts +7 -0
  115. package/dist/modules/file-browser/acl/locales/en-US.d.ts +44 -0
  116. package/dist/modules/file-browser/acl/locales/zh-CN.d.ts +44 -0
  117. package/dist/modules/file-browser/acl/use-acl-principals.d.ts +17 -0
  118. package/dist/modules/file-browser/acl/use-acl-report.d.ts +27 -0
  119. package/dist/modules/file-browser/acl-types.d.ts +86 -0
  120. package/dist/modules/file-browser/dashboard-model.d.ts +3 -0
  121. package/dist/modules/file-browser/file-browser-detail-icons.d.ts +0 -6
  122. package/dist/modules/file-browser/file-browser-detail.d.ts +5 -23
  123. package/dist/modules/file-browser/file-browser-labels.d.ts +1 -1
  124. package/dist/modules/file-browser/file-browser-search.d.ts +20 -0
  125. package/dist/modules/file-browser/file-browser-toolbar.d.ts +3 -10
  126. package/dist/modules/file-browser/file-browser-tree-pane.d.ts +2 -6
  127. package/dist/modules/file-browser/file-browser.d.ts +1 -1
  128. package/dist/modules/file-browser/fs-directories.d.ts +1 -0
  129. package/dist/modules/file-browser/fs-file-editing.d.ts +4 -0
  130. package/dist/modules/file-browser/fs-model.d.ts +3 -1
  131. package/dist/modules/file-browser/fs-preview-images.d.ts +3 -0
  132. package/dist/modules/file-browser/fs-read-file.d.ts +1 -1
  133. package/dist/modules/file-browser/index.d.ts +1 -0
  134. package/dist/modules/file-browser/locales/en-US.d.ts +5 -0
  135. package/dist/modules/file-browser/locales/zh-CN.d.ts +5 -0
  136. package/dist/modules/file-browser/style.css +2595 -703
  137. package/dist/modules/file-browser/types.d.ts +22 -20
  138. package/dist/modules/file-browser/use-file-browser-acl.d.ts +16 -0
  139. package/dist/modules/file-browser/use-file-browser.d.ts +5 -7
  140. package/dist/modules/file-browser/use-fs-tree.d.ts +1 -0
  141. package/dist/modules/file-browser/wiki-dashboard-pane.d.ts +2 -4
  142. package/dist/modules/file-browser.js +1 -1
  143. package/dist/modules/scope-cascade/style.css +537 -37
  144. package/dist/modules/style.css +12429 -8855
  145. package/dist/n~0.js +61 -37
  146. package/dist/p0~0.js +27 -0
  147. package/dist/p~0.js +34 -25
  148. package/dist/rt~0.js +107 -4
  149. package/dist/r~0.js +1 -1
  150. package/dist/shared/auth/agreements.d.ts +10 -0
  151. package/dist/shared/auth/fields.d.ts +15 -0
  152. package/dist/shared/auth/form-frame.d.ts +12 -0
  153. package/dist/shared/auth/locales/en-US.d.ts +24 -0
  154. package/dist/shared/auth/locales/zh-CN.d.ts +24 -0
  155. package/dist/shared/auth/types.d.ts +61 -0
  156. package/dist/shared/auth/use-auth-labels.d.ts +3 -0
  157. package/dist/shared/auth/use-form.d.ts +8 -0
  158. package/dist/shared/components/button/button.d.ts +20 -0
  159. package/dist/shared/components/input/input.d.ts +17 -0
  160. package/dist/shared/components/modal/locales/en-US.d.ts +4 -0
  161. package/dist/shared/components/modal/locales/zh-CN.d.ts +4 -0
  162. package/dist/shared/components/modal/modal.d.ts +2 -0
  163. package/dist/shared/components/modal/types.d.ts +18 -0
  164. package/dist/shared/components/overlay/lock-body-scroll.d.ts +1 -0
  165. package/dist/style.css +15477 -6258
  166. package/dist/s~0.js +16 -0
  167. package/dist/u~0.js +15 -6
  168. package/dist/viking-bot-composer~0.js +29 -11
  169. package/dist/viking-bot-interaction~0.js +2 -1
  170. package/package.json +34 -3
  171. package/dist/modules/file-browser/fs-selection.d.ts +0 -4
  172. package/dist/o~0.js +0 -106
package/dist/l~0.js CHANGED
@@ -1,2375 +1,55 @@
1
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { createElement, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
3
- import { FilePreview as file_preview_FilePreview } from "./3~0.js";
4
- import { Tooltip } from "./rt~0.js";
5
- import { getFileTypeColor, getFileTypeIcon, WikiBookIcon, ExperienceBoardIcon, WikiConflictBoardIcon, FolderIcon, WikiBoardIcon, resolveFileTypeIconKey } from "./k~0.js";
6
- import { FileBrowserEntries } from "./2~0.js";
7
- import { FileTree as file_tree_FileTree } from "./n~0.js";
8
- import { resolveLocale } from "./nx~0.js";
9
- import { OV_PATHS } from "./ck~0.js";
10
- import { isOvClientError, useOvSignal, useOvClient } from "./ae~0.js";
11
- import { ExperienceDashboard } from "./f~0.js";
12
- import { WikiDashboard } from "./fj~0.js";
13
- import { useLocale, LocaleProvider } from "./28~0.js";
14
- function clampResizableWidth(width, min, max) {
15
- const rounded = Math.round(width);
16
- const lower = Math.max(min, rounded);
17
- return Math.min(Math.max(min, max), lower);
18
- }
19
- function ResizableHandle({ label, min, max, value, step = 16, direction = 1, onResize, className, ...rest }) {
20
- const dragRef = useRef(null);
21
- const [dragging, setDragging] = useState(false);
22
- const endDrag = (event)=>{
23
- if (!dragRef.current) return;
24
- dragRef.current = null;
25
- setDragging(false);
26
- if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
27
- };
28
- const handlePointerDown = (event)=>{
29
- if (!onResize) return;
30
- if (0 !== event.button) return;
31
- event.preventDefault();
32
- event.currentTarget.setPointerCapture(event.pointerId);
33
- dragRef.current = {
34
- pointerId: event.pointerId,
35
- x: event.clientX,
36
- width: value
37
- };
38
- setDragging(true);
39
- };
40
- const handlePointerMove = (event)=>{
41
- const drag = dragRef.current;
42
- if (!drag || !onResize || drag.pointerId !== event.pointerId) return;
43
- onResize(clampResizableWidth(drag.width + (event.clientX - drag.x) * direction, min, max));
44
- };
45
- const handleKeyDown = (event)=>{
46
- if (!onResize) return;
47
- if ('ArrowLeft' !== event.key && 'ArrowRight' !== event.key) return;
48
- event.preventDefault();
49
- const delta = ('ArrowRight' === event.key ? step : -step) * direction;
50
- onResize(clampResizableWidth(value + delta, min, max));
51
- };
52
- return /*#__PURE__*/ jsx("div", {
53
- ...rest,
54
- role: "separator",
55
- tabIndex: onResize ? 0 : void 0,
56
- "aria-label": label,
57
- "aria-orientation": "vertical",
58
- "aria-valuemin": min,
59
- "aria-valuemax": max,
60
- "aria-valuenow": Math.round(value),
61
- "data-dragging": dragging || void 0,
62
- className: [
63
- 'ov-resizable-handle',
64
- className
65
- ].filter(Boolean).join(' '),
66
- onPointerDown: handlePointerDown,
67
- onPointerMove: handlePointerMove,
68
- onPointerUp: endDrag,
69
- onPointerCancel: endDrag,
70
- onKeyDown: handleKeyDown,
71
- children: /*#__PURE__*/ jsx("span", {
72
- "aria-hidden": "true",
73
- className: "ov-resizable-handle__line"
74
- })
75
- });
76
- }
77
- const SIZE = 14;
78
- function iconProps(size = SIZE) {
79
- return {
80
- width: size,
81
- height: size,
82
- viewBox: '0 0 16 16',
83
- fill: 'none',
84
- stroke: 'currentColor',
85
- strokeWidth: 1.4,
86
- strokeLinecap: 'round',
87
- strokeLinejoin: 'round',
88
- 'aria-hidden': true,
89
- focusable: 'false'
90
- };
91
- }
92
- function CopyIcon({ size = 12 }) {
93
- return /*#__PURE__*/ jsxs("svg", {
94
- ...iconProps(size),
95
- children: [
96
- /*#__PURE__*/ jsx("rect", {
97
- x: "5.5",
98
- y: "5.5",
99
- width: "8",
100
- height: "8",
101
- rx: "1.5"
102
- }),
103
- /*#__PURE__*/ jsx("path", {
104
- d: "M10.5 5.5v-1a1.5 1.5 0 0 0-1.5-1.5H4a1.5 1.5 0 0 0-1.5 1.5v5A1.5 1.5 0 0 0 4 11h1"
105
- })
106
- ]
107
- });
108
- }
109
- function DownloadIcon() {
110
- return /*#__PURE__*/ jsxs("svg", {
111
- ...iconProps(),
112
- children: [
113
- /*#__PURE__*/ jsx("path", {
114
- d: "M8 2.5v8"
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useId } from "react";
3
+ import { useAuthLabels, Field } from "./g~0.js";
4
+ import { validEmail, useForm, FormFrame } from "./5~0.js";
5
+ function EmailLoginForm({ defaultEmail = '', readOnlyEmail, forgotPassword, alternateLogin, onSubmit, locale, labels: overrides, ...options }) {
6
+ const id = useId();
7
+ const labels = useAuthLabels(locale, overrides);
8
+ const form = useForm({
9
+ email: defaultEmail,
10
+ password: ''
11
+ }, (values)=>({
12
+ email: validEmail(values.email) ? void 0 : {
13
+ key: 'invalidEmail'
14
+ },
15
+ password: values.password ? void 0 : {
16
+ key: 'required'
17
+ }
18
+ }));
19
+ return /*#__PURE__*/ jsxs(FormFrame, {
20
+ ...options,
21
+ labels: labels,
22
+ submitLabel: labels.login,
23
+ validate: form.validate,
24
+ secondaryAction: alternateLogin,
25
+ onSubmit: ()=>onSubmit?.({
26
+ ...form.values,
27
+ email: form.values.email.trim()
115
28
  }),
116
- /*#__PURE__*/ jsx("path", {
117
- d: "M5 7.5 8 10.5l3-3"
118
- }),
119
- /*#__PURE__*/ jsx("path", {
120
- d: "M2.5 12.5h11"
121
- })
122
- ]
123
- });
124
- }
125
- function FileBrowserDetail({ tabs, activeKey, locale, labels, footer, viewLabels, onActiveKeyChange }) {
126
- return /*#__PURE__*/ jsx("div", {
127
- className: "ov-file-browser__detail",
128
- children: /*#__PURE__*/ jsx(file_preview_FilePreview, {
129
- tabs: decorateTabs(tabs, viewLabels, footer),
130
- activeKey: activeKey ?? void 0,
131
- locale: locale,
132
- labels: labels,
133
- onActiveKeyChange: onActiveKeyChange
134
- })
135
- });
136
- }
137
- function decorateTabs(tabs, viewLabels, footer) {
138
- return tabs.map((tab)=>{
139
- if ('content' === tab.kind) return tab;
140
- return {
141
- ...tab,
142
- slots: {
143
- ...tab.slots,
144
- footer,
145
- actions: (actions)=>/*#__PURE__*/ jsxs("div", {
146
- className: "ov-file-browser__detail-actions",
147
- children: [
148
- actions.canSwitchView ? /*#__PURE__*/ jsxs("div", {
149
- className: "ov-file-browser__segmented",
150
- role: "group",
151
- "aria-label": viewLabels.viewSwitch,
152
- children: [
153
- /*#__PURE__*/ jsx("button", {
154
- type: "button",
155
- className: "ov-file-browser__segment",
156
- "data-active": 'preview' === actions.viewMode || void 0,
157
- onClick: ()=>actions.setViewMode('preview'),
158
- children: viewLabels.preview
159
- }),
160
- /*#__PURE__*/ jsx("button", {
161
- type: "button",
162
- className: "ov-file-browser__segment",
163
- "data-active": 'source' === actions.viewMode || void 0,
164
- onClick: ()=>actions.setViewMode('source'),
165
- children: viewLabels.source
166
- })
167
- ]
168
- }) : null,
169
- actions.canCopyContent || actions.canDownload ? /*#__PURE__*/ jsx("span", {
170
- "aria-hidden": "true",
171
- className: "ov-file-browser__detail-sep"
172
- }) : null,
173
- actions.canCopyContent ? /*#__PURE__*/ jsx("button", {
174
- type: "button",
175
- className: "ov-file-browser__detail-icon",
176
- "aria-label": viewLabels.copyContent,
177
- title: viewLabels.copyContent,
178
- onClick: ()=>void actions.copyContent(),
179
- children: /*#__PURE__*/ jsx(CopyIcon, {})
180
- }) : null,
181
- actions.canDownload ? /*#__PURE__*/ jsx("button", {
182
- type: "button",
183
- className: "ov-file-browser__detail-icon",
184
- "aria-label": viewLabels.download,
185
- title: viewLabels.download,
186
- onClick: ()=>actions.download(),
187
- children: /*#__PURE__*/ jsx(DownloadIcon, {})
188
- }) : null
189
- ]
190
- })
191
- }
192
- };
193
- });
194
- }
195
- const empty_state_namespaceObject = "data:image/png;base64,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";
196
- function FileBrowserEmpty({ label }) {
197
- return /*#__PURE__*/ jsxs("div", {
198
- className: "ov-file-browser__empty",
199
29
  children: [
200
- /*#__PURE__*/ jsx("img", {
201
- className: "ov-file-browser__empty-art",
202
- src: empty_state_namespaceObject,
203
- alt: "",
204
- "aria-hidden": "true"
205
- }),
206
- /*#__PURE__*/ jsx("p", {
207
- className: "ov-file-browser__empty-label",
208
- children: label
30
+ /*#__PURE__*/ jsx(Field, {
31
+ id: `${id}-email`,
32
+ label: labels.email,
33
+ labels: labels,
34
+ value: form.values.email,
35
+ readOnly: readOnlyEmail,
36
+ type: "email",
37
+ autoComplete: "username",
38
+ error: form.errors.email,
39
+ onChange: (value)=>form.update('email', value)
40
+ }),
41
+ /*#__PURE__*/ jsx(Field, {
42
+ id: `${id}-password`,
43
+ label: labels.password,
44
+ labels: labels,
45
+ value: form.values.password,
46
+ secret: true,
47
+ autoComplete: "current-password",
48
+ action: forgotPassword,
49
+ error: form.errors.password,
50
+ onChange: (value)=>form.update('password', value)
209
51
  })
210
52
  ]
211
53
  });
212
54
  }
213
- function FileBrowserFailure({ message, detail, retryLabel, onRetry }) {
214
- return /*#__PURE__*/ jsxs("div", {
215
- className: "ov-file-browser__failure",
216
- role: "alert",
217
- children: [
218
- /*#__PURE__*/ jsx("p", {
219
- className: "ov-file-browser__failure-title",
220
- children: message
221
- }),
222
- detail ? /*#__PURE__*/ jsx("p", {
223
- className: "ov-file-browser__failure-detail",
224
- children: detail
225
- }) : null,
226
- /*#__PURE__*/ jsx("button", {
227
- type: "button",
228
- className: "ov-file-browser__failure-retry",
229
- onClick: onRetry,
230
- children: retryLabel
231
- })
232
- ]
233
- });
234
- }
235
- const TREE_MIN_WIDTH = 200;
236
- const DETAIL_MIN_WIDTH = 320;
237
- const RESIZE_FOOTPRINT = 24;
238
- const TREE_MAX_WIDTH = 520;
239
- function resolveTreeMaxWidth(containerWidth) {
240
- if (!containerWidth) return TREE_MAX_WIDTH;
241
- return Math.max(TREE_MIN_WIDTH, Math.min(TREE_MAX_WIDTH, containerWidth - DETAIL_MIN_WIDTH - RESIZE_FOOTPRINT));
242
- }
243
- const en = {
244
- experienceTitle: 'Experience dashboard',
245
- wikiTitle: 'Dashboard',
246
- openExperience: 'Open experience dashboard',
247
- openWiki: 'Open Wiki dashboard',
248
- wikiConflicts: 'View pending Wiki conflicts',
249
- failed: 'Could not load dashboard information'
250
- };
251
- const zh = {
252
- experienceTitle: '经验看板',
253
- wikiTitle: '看板',
254
- openExperience: '打开经验看板',
255
- openWiki: '打开 Wiki 看板',
256
- wikiConflicts: '查看 Wiki 待确认冲突',
257
- failed: '看板信息加载失败'
258
- };
259
- const dashboard_labels_dashboardLabels = (locale, labels)=>({
260
- ...'zh-CN' === locale ? zh : en,
261
- ...labels
262
- });
263
- const file_browser_icons_SIZE = 16;
264
- const strokeProps = {
265
- width: file_browser_icons_SIZE,
266
- height: file_browser_icons_SIZE,
267
- viewBox: '0 0 48 48',
268
- fill: 'none',
269
- stroke: 'currentColor',
270
- strokeWidth: 4,
271
- 'aria-hidden': true,
272
- focusable: 'false'
273
- };
274
- function SearchIcon() {
275
- return /*#__PURE__*/ jsx("svg", {
276
- ...strokeProps,
277
- children: /*#__PURE__*/ jsx("path", {
278
- d: "M33.072 33.071c6.248-6.248 6.248-16.379 0-22.627-6.249-6.249-16.38-6.249-22.628 0-6.248 6.248-6.248 16.379 0 22.627 6.248 6.248 16.38 6.248 22.628 0Zm0 0 8.485 8.485"
279
- })
280
- });
281
- }
282
- function RefreshIcon() {
283
- return /*#__PURE__*/ jsx("svg", {
284
- ...strokeProps,
285
- children: /*#__PURE__*/ jsx("path", {
286
- d: "M38.837 18C36.463 12.136 30.715 8 24 8 15.163 8 8 15.163 8 24s7.163 16 16 16c7.455 0 13.72-5.1 15.496-12M40 8v10H30"
287
- })
288
- });
289
- }
290
- function FileBrowserToolbar({ searchId, query, refreshing, canRefresh, placeholder, refreshLabel, onQueryChange, onRefresh }) {
291
- return /*#__PURE__*/ jsxs("div", {
292
- className: "ov-file-browser__toolbar",
293
- children: [
294
- /*#__PURE__*/ jsxs("label", {
295
- className: "ov-file-browser__search",
296
- htmlFor: searchId,
297
- children: [
298
- /*#__PURE__*/ jsx("span", {
299
- className: "ov-file-browser__search-icon",
300
- children: /*#__PURE__*/ jsx(SearchIcon, {})
301
- }),
302
- /*#__PURE__*/ jsx("input", {
303
- id: searchId,
304
- type: "search",
305
- className: "ov-file-browser__search-input",
306
- placeholder: placeholder,
307
- value: query,
308
- onChange: (event)=>onQueryChange(event.target.value)
309
- })
310
- ]
311
- }),
312
- /*#__PURE__*/ jsx(Tooltip, {
313
- content: refreshLabel,
314
- children: /*#__PURE__*/ jsx("button", {
315
- type: "button",
316
- className: [
317
- 'ov-file-browser__refresh',
318
- refreshing ? 'ov-file-browser__refresh--spinning' : ''
319
- ].filter(Boolean).join(' '),
320
- "aria-label": refreshLabel,
321
- disabled: !canRefresh,
322
- onClick: onRefresh,
323
- children: /*#__PURE__*/ jsx(RefreshIcon, {})
324
- })
325
- })
326
- ]
327
- });
328
- }
329
- function DashboardIndicator({ dashboard, locale, labels, onOpen }) {
330
- const text = dashboard_labels_dashboardLabels(locale, labels);
331
- const label = 'experience' === dashboard.kind ? text.openExperience : dashboard.pendingConflicts ? text.wikiConflicts : text.openWiki;
332
- const Icon = 'experience' === dashboard.kind ? ExperienceBoardIcon : dashboard.pendingConflicts ? WikiConflictBoardIcon : WikiBoardIcon;
333
- return /*#__PURE__*/ jsx("button", {
334
- type: "button",
335
- className: `ov-file-browser__dashboard${dashboard.pendingConflicts ? ' ov-file-browser__dashboard--pending' : ''}`,
336
- "aria-label": label,
337
- title: label,
338
- onClick: (event)=>{
339
- event.stopPropagation();
340
- onOpen(dashboard.uri);
341
- },
342
- children: /*#__PURE__*/ jsx(Icon, {
343
- width: 12,
344
- height: 12
345
- })
346
- });
347
- }
348
- function fileTypeIcon(name) {
349
- const Icon = getFileTypeIcon(name);
350
- const key = resolveFileTypeIconKey(name);
351
- return /*#__PURE__*/ jsx(Icon, {
352
- className: "ov-file-tree__file-type-icon",
353
- style: {
354
- '--ov-file-tree-icon-light': getFileTypeColor(key, 'light'),
355
- '--ov-file-tree-icon-dark': getFileTypeColor(key, 'dark')
356
- }
357
- });
358
- }
359
- function directoryIcon() {
360
- return /*#__PURE__*/ jsx(FolderIcon, {
361
- className: "ov-file-tree__file-type-icon"
362
- });
363
- }
364
- function FileBrowserTreePane({ entries, locale, dashboardLabels, searchId, browser, treeLabels, searchPlaceholder, refreshLabel, searchLoading, searchEmpty, searchErrorLabel, retryLabel }) {
365
- return /*#__PURE__*/ jsxs(Fragment, {
366
- children: [
367
- /*#__PURE__*/ jsx(FileBrowserEntries, {
368
- ...entries,
369
- locale: locale,
370
- className: "ov-file-browser__entries"
371
- }),
372
- /*#__PURE__*/ jsx(FileBrowserToolbar, {
373
- searchId: searchId,
374
- query: browser.query,
375
- refreshing: browser.refreshing,
376
- canRefresh: browser.isReady,
377
- placeholder: searchPlaceholder,
378
- refreshLabel: refreshLabel,
379
- onQueryChange: browser.actions.setQuery,
380
- onRefresh: ()=>void browser.actions.refresh()
381
- }),
382
- /*#__PURE__*/ jsxs("div", {
383
- className: "ov-file-browser__tree-scroll",
384
- children: [
385
- browser.dashboardError ? /*#__PURE__*/ jsxs("div", {
386
- className: "ov-file-browser__hint ov-file-browser__hint--error",
387
- "aria-live": "polite",
388
- children: [
389
- /*#__PURE__*/ jsxs("p", {
390
- children: [
391
- dashboard_labels_dashboardLabels(locale, dashboardLabels).failed,
392
- ":",
393
- ' ',
394
- browser.dashboardError.message
395
- ]
396
- }),
397
- /*#__PURE__*/ jsx("button", {
398
- type: "button",
399
- onClick: ()=>void browser.actions.refresh(),
400
- children: retryLabel
401
- })
402
- ]
403
- }) : null,
404
- /*#__PURE__*/ jsx(file_tree_FileTree, {
405
- locale: locale,
406
- rows: browser.rows,
407
- selectedId: browser.selectedId,
408
- isReady: browser.isReady,
409
- labels: treeLabels,
410
- emptyFallback: browser.searching ? browser.searchError ? /*#__PURE__*/ jsxs("div", {
411
- className: "ov-file-browser__hint ov-file-browser__hint--error",
412
- children: [
413
- /*#__PURE__*/ jsx("p", {
414
- className: "ov-file-browser__failure-title",
415
- children: searchErrorLabel
416
- }),
417
- /*#__PURE__*/ jsx("p", {
418
- className: "ov-file-browser__failure-detail",
419
- children: browser.searchError.message
420
- }),
421
- /*#__PURE__*/ jsx("button", {
422
- type: "button",
423
- className: "ov-file-browser__retry",
424
- onClick: ()=>void browser.actions.refresh(),
425
- children: retryLabel
426
- })
427
- ]
428
- }) : /*#__PURE__*/ jsx("p", {
429
- className: "ov-file-browser__hint",
430
- children: browser.searchLoading ? searchLoading : searchEmpty
431
- }) : void 0,
432
- renderRowIcon: (row)=>browser.dashboards.get(row.uri)?.isRoot ? /*#__PURE__*/ jsx(WikiBookIcon, {
433
- width: 14,
434
- height: 14
435
- }) : fileTypeIcon(row.name),
436
- renderDashboard: (row)=>{
437
- const dashboard = browser.dashboards.get(row.uri);
438
- return dashboard ? /*#__PURE__*/ jsx(DashboardIndicator, {
439
- dashboard: dashboard,
440
- locale: locale,
441
- labels: dashboardLabels,
442
- onOpen: browser.actions.openDashboard
443
- }) : null;
444
- },
445
- operations: {
446
- select: browser.actions.select,
447
- toggleExpand: browser.actions.toggleExpand,
448
- loadMore: browser.actions.loadMore,
449
- retry: browser.actions.retry
450
- }
451
- })
452
- ]
453
- })
454
- ]
455
- });
456
- }
457
- const messages = {
458
- formatCharacterCount: (count)=>`${count.toLocaleString('en-US')} ${1 === count ? 'character' : 'characters'}`,
459
- empty: 'Select a file to preview',
460
- error: 'Failed to load the directory',
461
- retry: 'Retry',
462
- refresh: 'Refresh',
463
- searchPlaceholder: 'Search files ⌘+K...',
464
- searchEmpty: 'No matching resources',
465
- searchFailed: 'Failed to run the search',
466
- loading: 'Loading…',
467
- searchLoading: 'Searching…',
468
- previewMode: 'Preview',
469
- sourceMode: 'Source',
470
- copyPath: 'Copy path',
471
- copyContent: 'Copy content',
472
- download: 'Download',
473
- history: 'Version history',
474
- viewSwitch: 'Switch view',
475
- resizeTree: 'Resize the directory tree',
476
- l0Summary: 'L0 Summary',
477
- l1Overview: 'L1 Overview',
478
- summaryEmpty: 'No summary generated yet',
479
- summaryFailed: 'The summary could not be loaded.'
480
- };
481
- const en_US = messages;
482
- const zh_CN_messages = {
483
- formatCharacterCount: (count)=>`${count.toLocaleString('zh-CN')} 个字符`,
484
- empty: '选择一个文件查看内容',
485
- error: '目录加载失败',
486
- retry: '重试',
487
- refresh: '刷新',
488
- searchPlaceholder: '搜索文件 ⌘+K...',
489
- searchEmpty: '没有匹配的资源',
490
- searchFailed: '搜索失败',
491
- loading: '加载中…',
492
- searchLoading: '搜索中…',
493
- previewMode: '预览',
494
- sourceMode: '源码',
495
- copyPath: '复制路径',
496
- copyContent: '复制正文',
497
- download: '下载',
498
- history: '版本历史',
499
- viewSwitch: '切换视图',
500
- resizeTree: '调整目录树宽度',
501
- l0Summary: 'L0 摘要',
502
- l1Overview: 'L1 总览',
503
- summaryEmpty: '暂无生成内容',
504
- summaryFailed: '摘要加载失败。'
505
- };
506
- const zh_CN = zh_CN_messages;
507
- const LOCALES = {
508
- 'en-US': en_US,
509
- 'zh-CN': zh_CN
510
- };
511
- function resolveLabels(labels, locale) {
512
- return {
513
- ...resolveLocale(LOCALES, locale, labels),
514
- tree: labels?.tree,
515
- previewLabels: labels?.preview
516
- };
517
- }
518
- function resolvePreviewLabels(text) {
519
- return {
520
- loading: text.loading,
521
- copyPath: text.copyPath,
522
- download: text.download,
523
- ...text.previewLabels
524
- };
525
- }
526
- function resolveSummaryLabels(locale, labels) {
527
- const text = resolveLabels(labels, locale);
528
- return {
529
- l0: text.l0Summary,
530
- l1: text.l1Overview,
531
- failure: text.summaryFailed
532
- };
533
- }
534
- function useContainerWidth() {
535
- const ref = useRef(null);
536
- const [width, setWidth] = useState(0);
537
- useEffect(()=>{
538
- const element = ref.current;
539
- if (!element) return;
540
- const update = (next)=>setWidth((current)=>current === next ? current : next);
541
- update(Math.round(element.getBoundingClientRect().width));
542
- const observer = new ResizeObserver(([entry])=>{
543
- if (entry) update(Math.round(entry.contentRect.width));
544
- });
545
- observer.observe(element);
546
- return ()=>observer.disconnect();
547
- }, []);
548
- return {
549
- ref,
550
- width
551
- };
552
- }
553
- function selectedRowId(uri, results) {
554
- if (!uri || null === results) return uri;
555
- const index = results.findIndex((entry)=>entry.uri === uri);
556
- return index < 0 ? uri : `${uri}#${index}`;
557
- }
558
- const emptyDir = ()=>({
559
- entries: [],
560
- hasMore: false,
561
- loading: false,
562
- error: null
563
- });
564
- function mergePage(current, page, offset) {
565
- const previous = current ?? emptyDir();
566
- return {
567
- entries: 0 === offset ? page.entries : [
568
- ...previous.entries,
569
- ...page.entries
570
- ],
571
- hasMore: page.hasMore,
572
- loading: false,
573
- error: null
574
- };
575
- }
576
- function nameFromUri(uri) {
577
- const trimmed = uri.replace(/\/+$/, '');
578
- const index = trimmed.lastIndexOf('/');
579
- const name = index < 0 ? trimmed : trimmed.slice(index + 1);
580
- return name || trimmed;
581
- }
582
- function toEntryRow(entry, depth, expanded, index, busy) {
583
- const isDir = true === entry.isDir;
584
- return {
585
- tags: entry.tags,
586
- kind: 'entry',
587
- id: void 0 === index ? entry.uri : `${entry.uri}#${index}`,
588
- depth,
589
- uri: entry.uri,
590
- name: nameFromUri(entry.uri),
591
- type: isDir ? 'directory' : 'file',
592
- expanded: isDir ? expanded : void 0,
593
- busy: busy || void 0
594
- };
595
- }
596
- function toFileTab(entry, content, maxLines, icon, openParent, truncated = content.split('\n').length >= maxLines) {
597
- const name = nameFromUri(entry.uri);
598
- return {
599
- kind: 'file',
600
- key: entry.uri,
601
- title: name,
602
- icon,
603
- operations: {
604
- openParent
605
- },
606
- source: {
607
- content,
608
- fileName: name,
609
- path: entry.uri,
610
- truncated
611
- }
612
- };
613
- }
614
- function toDirectoryTab(uri, summary, labels, openParent, icon) {
615
- const name = nameFromUri(uri);
616
- const levelBody = (body, failure)=>void 0 === failure ? body : `> ${failure || labels.failure}`;
617
- return {
618
- kind: 'directory',
619
- key: uri,
620
- title: name,
621
- icon,
622
- levels: [
623
- {
624
- key: 'l0',
625
- label: labels.l0,
626
- source: {
627
- content: levelBody(summary.abstract, summary.abstractError),
628
- fileName: `${name}.md`,
629
- path: uri,
630
- fileType: 'markdown'
631
- }
632
- },
633
- {
634
- key: 'l1',
635
- label: labels.l1,
636
- source: {
637
- content: levelBody(summary.overview, summary.overviewError),
638
- fileName: `${name}.md`,
639
- path: uri,
640
- fileType: 'markdown'
641
- }
642
- }
643
- ],
644
- operations: {
645
- openParent
646
- }
647
- };
648
- }
649
- function flattenTree(uri, depth, dirs, expanded) {
650
- const dir = dirs[uri];
651
- if (!dir) return [];
652
- const rows = [];
653
- for (const entry of dir.entries){
654
- const isOpen = expanded.has(entry.uri);
655
- const loadingChildren = isOpen && dirs[entry.uri]?.loading === true;
656
- rows.push(toEntryRow(entry, depth, isOpen, void 0, loadingChildren));
657
- if (isOpen) {
658
- const children = flattenTree(entry.uri, depth + 1, dirs, expanded);
659
- if (children.length > 0) rows.push(...children);
660
- else if (loadingChildren) rows.push({
661
- kind: 'loading',
662
- id: `${entry.uri}::loading`,
663
- depth: depth + 1,
664
- parentId: entry.uri
665
- });
666
- else rows.push({
667
- kind: 'empty',
668
- id: `${entry.uri}::empty`,
669
- depth: depth + 1,
670
- parentId: entry.uri
671
- });
672
- }
673
- }
674
- if (dir.error) rows.push({
675
- kind: 'error',
676
- id: `${uri}::error`,
677
- depth,
678
- parentId: uri
679
- });
680
- else if (dir.hasMore) rows.push({
681
- kind: 'load-more',
682
- id: `${uri}::more`,
683
- depth,
684
- parentId: uri,
685
- loading: dir.loading
686
- });
687
- return rows;
688
- }
689
- function isAbort(error) {
690
- return 'object' == typeof error && null !== error && 'AbortError' === error.name;
691
- }
692
- function toError(cause) {
693
- return cause instanceof Error ? cause : new Error(String(cause));
694
- }
695
- async function readDirectory(client, uri, options) {
696
- const read = (path)=>client.request({
697
- method: 'GET',
698
- path,
699
- query: {
700
- uri
701
- },
702
- options
703
- }).then((value)=>({
704
- ok: true,
705
- text: 'string' == typeof value ? value : ''
706
- })).catch((cause)=>({
707
- ok: false,
708
- cause
709
- }));
710
- const [abstractResult, overviewResult] = await Promise.all([
711
- read(OV_PATHS.contentAbstract),
712
- read(OV_PATHS.contentOverview)
713
- ]);
714
- const aborted = [
715
- abstractResult,
716
- overviewResult
717
- ].find((result)=>!result.ok && isAbort(result.cause));
718
- if (aborted && !aborted.ok) throw aborted.cause;
719
- if (!abstractResult.ok && !overviewResult.ok) throw abstractResult.cause;
720
- const reason = (result)=>result.ok ? void 0 : result.cause instanceof Error ? result.cause.message : String(result.cause);
721
- return {
722
- abstract: abstractResult.ok ? abstractResult.text : '',
723
- overview: overviewResult.ok ? overviewResult.text : '',
724
- abstractError: reason(abstractResult),
725
- overviewError: reason(overviewResult)
726
- };
727
- }
728
- const BINARY_EXTENSIONS = new Set([
729
- 'png',
730
- 'jpg',
731
- 'jpeg',
732
- 'gif',
733
- 'webp',
734
- 'avif',
735
- 'bmp',
736
- 'ico',
737
- 'svg',
738
- 'pdf',
739
- 'doc',
740
- 'docx',
741
- 'ppt',
742
- 'pptx',
743
- 'xls',
744
- 'xlsx',
745
- 'mp4',
746
- 'webm',
747
- 'mov',
748
- 'mp3',
749
- 'wav',
750
- 'ogg',
751
- 'm4a',
752
- 'zip',
753
- 'gz',
754
- 'tar',
755
- 'ovpack'
756
- ]);
757
- function isBinaryFile(name) {
758
- const dot = name.lastIndexOf('.');
759
- if (dot < 0 || dot === name.length - 1) return false;
760
- return BINARY_EXTENSIONS.has(name.slice(dot + 1).toLowerCase());
761
- }
762
- const MIME_BY_EXTENSION = {
763
- png: 'image/png',
764
- jpg: 'image/jpeg',
765
- jpeg: 'image/jpeg',
766
- gif: 'image/gif',
767
- webp: 'image/webp',
768
- avif: 'image/avif',
769
- bmp: 'image/bmp',
770
- ico: 'image/x-icon',
771
- svg: 'image/svg+xml',
772
- pdf: 'application/pdf',
773
- doc: 'application/msword',
774
- docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
775
- ppt: 'application/vnd.ms-powerpoint',
776
- pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
777
- xls: 'application/vnd.ms-excel',
778
- xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
779
- mp4: 'video/mp4',
780
- webm: 'video/webm',
781
- mov: 'video/quicktime',
782
- mp3: 'audio/mpeg',
783
- wav: 'audio/wav',
784
- ogg: 'audio/ogg',
785
- m4a: 'audio/mp4',
786
- zip: 'application/zip',
787
- gz: 'application/gzip',
788
- tar: 'application/x-tar'
789
- };
790
- function mimeTypeOf(name) {
791
- const dot = name.lastIndexOf('.');
792
- if (dot < 0) return 'application/octet-stream';
793
- return MIME_BY_EXTENSION[name.slice(dot + 1).toLowerCase()] ?? 'application/octet-stream';
794
- }
795
- function toBinaryTab(uri, name, file, icon, openParent) {
796
- return {
797
- kind: 'file',
798
- key: uri,
799
- title: name,
800
- icon,
801
- operations: {
802
- openParent
803
- },
804
- source: {
805
- file,
806
- fileName: name,
807
- path: uri
808
- }
809
- };
810
- }
811
- const LINE_BREAK_CODES = new Set([
812
- 0x0a,
813
- 0x0b,
814
- 0x0c,
815
- 0x0d,
816
- 0x1c,
817
- 0x1d,
818
- 0x1e,
819
- 0x85,
820
- 0x2028,
821
- 0x2029
822
- ]);
823
- function splitLines(text) {
824
- if (!text) return [];
825
- const lines = [];
826
- let start = 0;
827
- for(let index = 0; index < text.length; index++){
828
- if (!LINE_BREAK_CODES.has(text.charCodeAt(index))) continue;
829
- const paired = 0x0d === text.charCodeAt(index) && 0x0a === text.charCodeAt(index + 1);
830
- const end = index + (paired ? 2 : 1);
831
- lines.push(text.slice(start, end));
832
- start = end;
833
- index = end - 1;
834
- }
835
- if (start < text.length) lines.push(text.slice(start));
836
- return lines;
837
- }
838
- function joinLines(lines) {
839
- return lines.join('');
840
- }
841
- const PY_WHITESPACE_CODES = [
842
- 0x09,
843
- 0x0a,
844
- 0x0b,
845
- 0x0c,
846
- 0x0d,
847
- 0x1c,
848
- 0x1d,
849
- 0x1e,
850
- 0x1f,
851
- 0x20,
852
- 0x85,
853
- 0xa0,
854
- 0x1680,
855
- 0x2000,
856
- 0x2001,
857
- 0x2002,
858
- 0x2003,
859
- 0x2004,
860
- 0x2005,
861
- 0x2006,
862
- 0x2007,
863
- 0x2008,
864
- 0x2009,
865
- 0x200a,
866
- 0x2028,
867
- 0x2029,
868
- 0x202f,
869
- 0x205f,
870
- 0x3000
871
- ];
872
- const PY_WHITESPACE = String.fromCharCode(...PY_WHITESPACE_CODES);
873
- const PY_WORD = '\\p{L}\\p{N}_';
874
- const MEMORY_FIELDS_COMMENT = new RegExp(`<!--[${PY_WHITESPACE}]*MEMORY_FIELDS(?![${PY_WORD}])[\\s\\S]*?[${PY_WHITESPACE}]*-->`, 'gu');
875
- function isPythonBlank(text) {
876
- for (const char of text)if (!PY_WHITESPACE.includes(char)) return false;
877
- return true;
878
- }
879
- function trimPythonEnd(text) {
880
- let end = text.length;
881
- while(end > 0 && PY_WHITESPACE.includes(text[end - 1] ?? ''))end--;
882
- return text.slice(0, end);
883
- }
884
- function uriParts(uri) {
885
- const [beforeQuery = ''] = uri.split('?');
886
- const path = beforeQuery.replace(/\/+$/, '');
887
- if (!path.startsWith('viking://')) return [];
888
- return path.slice(9).split('/').filter(Boolean);
889
- }
890
- function isMemoryUri(uri) {
891
- const parts = uriParts(uri);
892
- if (parts.length < 3) return false;
893
- if ('user' !== parts[0] && '~' !== parts[0]) return false;
894
- const scoped = '~' === parts[0] ? [
895
- 'user',
896
- '~',
897
- ...parts.slice(1)
898
- ] : parts;
899
- if ('memories' === scoped[2]) return true;
900
- return scoped.length >= 5 && 'peers' === scoped[2] && 'memories' === scoped[4];
901
- }
902
- function stripMemoryFieldsTrailer(text) {
903
- let visible = text;
904
- for(;;){
905
- let start = -1;
906
- MEMORY_FIELDS_COMMENT.lastIndex = 0;
907
- let match;
908
- while(null !== (match = MEMORY_FIELDS_COMMENT.exec(visible))){
909
- const after = visible.slice(match.index + match[0].length);
910
- if (isPythonBlank(after)) start = match.index;
911
- }
912
- if (start < 0) return visible;
913
- visible = trimPythonEnd(visible.slice(0, start));
914
- }
915
- }
916
- const MAX_LINES = 2000;
917
- async function readFile(client, uri, options, openParent) {
918
- const name = nameFromUri(uri);
919
- const icon = fileTypeIcon(name);
920
- if (isBinaryFile(name)) {
921
- const blob = await client.request({
922
- method: 'GET',
923
- path: OV_PATHS.contentDownload,
924
- query: {
925
- uri
926
- },
927
- responseType: 'blob',
928
- options
929
- });
930
- const typed = new Blob([
931
- blob
932
- ], {
933
- type: mimeTypeOf(name)
934
- });
935
- return toBinaryTab(uri, name, typed, icon, openParent);
936
- }
937
- const read = (limit)=>client.request({
938
- method: 'GET',
939
- path: OV_PATHS.contentRead,
940
- query: {
941
- uri,
942
- limit
943
- },
944
- options
945
- }).then((value)=>'string' == typeof value ? value : '');
946
- const first = await read(MAX_LINES);
947
- if (!isMemoryUri(uri)) return toFileTab({
948
- uri
949
- }, first, MAX_LINES, icon, openParent, splitLines(first).length >= MAX_LINES);
950
- const full = splitLines(first).length < MAX_LINES ? first : await read(-1);
951
- const lines = splitLines(stripMemoryFieldsTrailer(full));
952
- const truncated = lines.length > MAX_LINES;
953
- const visible = joinLines(truncated ? lines.slice(0, MAX_LINES) : lines);
954
- return toFileTab({
955
- uri
956
- }, visible, MAX_LINES, icon, openParent, truncated);
957
- }
958
- async function resolveIsDirectory(client, uri, options) {
959
- try {
960
- const result = await client.request({
961
- method: 'GET',
962
- path: OV_PATHS.fsStat,
963
- query: {
964
- uri
965
- },
966
- options
967
- });
968
- return result?.isDir === true || result?.is_dir === true;
969
- } catch {
970
- return false;
971
- }
972
- }
973
- function abortError() {
974
- const error = new Error('Aborted');
975
- error.name = 'AbortError';
976
- return error;
977
- }
978
- function useFsPreview({ client, uri, resourceType = 'file', labels = resolveSummaryLabels('en-US'), formatCharacterCount = resolveLabels(void 0, 'en-US').formatCharacterCount, openParent, generation = 0, requestOptions }) {
979
- const [directory, setDirectory] = useState(null);
980
- const [tabs, setTabs] = useState(null);
981
- const [activeKey, setActiveKey] = useState(null);
982
- const [error, setError] = useState(null);
983
- const [characterCount, setCharacterCount] = useState();
984
- useEffect(()=>{
985
- setDirectory(null);
986
- if (!client || !uri) {
987
- setTabs(null);
988
- setActiveKey(null);
989
- setError(null);
990
- setCharacterCount(void 0);
991
- return;
992
- }
993
- const controller = new AbortController();
994
- setTabs([
995
- loadingTab(uri, 'file' !== resourceType)
996
- ]);
997
- setActiveKey(uri);
998
- setActiveKey(null);
999
- setError(null);
1000
- setCharacterCount(void 0);
1001
- const options = {
1002
- ...requestOptions,
1003
- signal: controller.signal
1004
- };
1005
- const read = (async ()=>{
1006
- const isDir = 'unknown' === resourceType ? await resolveIsDirectory(client, uri, options) : 'directory' === resourceType;
1007
- if (controller.signal.aborted) throw abortError();
1008
- return isDir ? {
1009
- summary: await readDirectory(client, uri, options)
1010
- } : {
1011
- tab: await readFile(client, uri, options, openParent)
1012
- };
1013
- })();
1014
- read.then((result)=>{
1015
- if (controller.signal.aborted) return;
1016
- if (result.summary) {
1017
- setDirectory({
1018
- uri,
1019
- summary: result.summary
1020
- });
1021
- setActiveKey(uri);
1022
- return;
1023
- }
1024
- const tab = result.tab;
1025
- setTabs([
1026
- tab
1027
- ]);
1028
- setActiveKey(tab.key);
1029
- const body = tab.source.content ?? '';
1030
- setCharacterCount(body.length);
1031
- }, (cause)=>{
1032
- if (isAbort(cause) || controller.signal.aborted) return;
1033
- setTabs([]);
1034
- setError(cause instanceof Error ? cause : new Error(String(cause)));
1035
- });
1036
- return ()=>controller.abort();
1037
- }, [
1038
- client,
1039
- uri,
1040
- resourceType,
1041
- openParent,
1042
- generation,
1043
- requestOptions
1044
- ]);
1045
- const directoryTab = directory?.uri === uri ? toDirectoryTab(directory.uri, directory.summary, labels, openParent, directoryIcon()) : void 0;
1046
- const count = directoryTab ? (directoryTab.levels[0].source.content ?? '').length : characterCount;
1047
- return {
1048
- tabs: directoryTab ? [
1049
- directoryTab
1050
- ] : tabs,
1051
- activeKey,
1052
- error,
1053
- footer: void 0 === count ? void 0 : formatCharacterCount(count),
1054
- setActiveKey
1055
- };
1056
- }
1057
- function loadingTab(uri, isDirectory) {
1058
- if (isDirectory) return {
1059
- kind: 'directory',
1060
- key: uri,
1061
- loading: true,
1062
- levels: [
1063
- {
1064
- key: 'l0',
1065
- label: '',
1066
- source: {
1067
- fileName: `${nameFromUri(uri)}.md`,
1068
- path: uri,
1069
- fileType: 'markdown',
1070
- content: ''
1071
- }
1072
- },
1073
- {
1074
- key: 'l1',
1075
- label: '',
1076
- source: {
1077
- fileName: `${nameFromUri(uri)}.md`,
1078
- path: uri,
1079
- fileType: 'markdown',
1080
- content: ''
1081
- }
1082
- }
1083
- ]
1084
- };
1085
- return {
1086
- kind: 'file',
1087
- key: uri,
1088
- loading: true,
1089
- source: {
1090
- fileName: nameFromUri(uri),
1091
- path: uri,
1092
- content: ''
1093
- }
1094
- };
1095
- }
1096
- function mergeFindResult(result) {
1097
- const seen = new Set();
1098
- const entries = [];
1099
- for (const group of [
1100
- result?.memories,
1101
- result?.resources,
1102
- result?.skills
1103
- ])for (const item of group ?? []){
1104
- const uri = item?.uri;
1105
- if (!(!uri || seen.has(uri))) {
1106
- seen.add(uri);
1107
- entries.push({
1108
- uri,
1109
- isDir: false,
1110
- abstract: item.abstract?.trim() || void 0
1111
- });
1112
- }
1113
- }
1114
- return entries;
1115
- }
1116
- const LIMIT = 20;
1117
- function useFsSearch({ client, query, targetUri, generation = 0, requestOptions }) {
1118
- const [results, setResults] = useState(null);
1119
- const [loading, setLoading] = useState(false);
1120
- const [error, setError] = useState(null);
1121
- useEffect(()=>{
1122
- if (!client || !query) {
1123
- setResults(null);
1124
- setLoading(false);
1125
- setError(null);
1126
- return;
1127
- }
1128
- const controller = new AbortController();
1129
- setLoading(true);
1130
- setError(null);
1131
- client.request({
1132
- method: 'POST',
1133
- path: OV_PATHS.searchFind,
1134
- body: {
1135
- query,
1136
- target_uri: targetUri,
1137
- limit: LIMIT
1138
- },
1139
- options: {
1140
- ...requestOptions,
1141
- signal: controller.signal
1142
- }
1143
- }).then((result)=>{
1144
- if (controller.signal.aborted) return;
1145
- setResults(mergeFindResult(result));
1146
- setLoading(false);
1147
- }, (cause)=>{
1148
- if (isAbort(cause) || controller.signal.aborted) return;
1149
- setResults([]);
1150
- setError(toError(cause));
1151
- setLoading(false);
1152
- });
1153
- return ()=>controller.abort();
1154
- }, [
1155
- client,
1156
- query,
1157
- targetUri,
1158
- generation,
1159
- requestOptions
1160
- ]);
1161
- return {
1162
- results,
1163
- loading,
1164
- error
1165
- };
1166
- }
1167
- const isHomeUri = (uri)=>'viking://~' === uri || uri.startsWith('viking://~/');
1168
- async function readDashboardStat(client, uri, options) {
1169
- const stat = await client.request({
1170
- method: 'GET',
1171
- path: OV_PATHS.fsStat,
1172
- query: {
1173
- uri
1174
- },
1175
- options
1176
- });
1177
- const canonical = stat?.uri ?? uri;
1178
- if ('boolean' != typeof stat?.isDir || 'string' != typeof canonical || !canonical || isHomeUri(canonical)) throw new TypeError('Invalid canonical resource stat');
1179
- return {
1180
- uri: canonical,
1181
- isDir: stat.isDir
1182
- };
1183
- }
1184
- async function resolveDashboardUri(client, uri, options) {
1185
- return isHomeUri(uri) ? (await readDashboardStat(client, uri, options)).uri : uri;
1186
- }
1187
- async function readDashboardHint(client, uri, options) {
1188
- const result = await client.request({
1189
- method: 'GET',
1190
- path: OV_PATHS.fsAttrs,
1191
- query: {
1192
- uri
1193
- },
1194
- options
1195
- });
1196
- return {
1197
- uri: await resolveDashboardUri(client, result?.uri ?? uri, options),
1198
- tags: result?.attrs?.tags ?? []
1199
- };
1200
- }
1201
- const EXPERIENCE_PAGE_SIZE = 20;
1202
- const isExperienceDirectory = (uri)=>/^viking:\/\/(?:user\/[^/]+|~)\/memories\/experiences\/?$/.test(uri);
1203
- const isExperienceFile = (uri)=>/^viking:\/\/(?:user\/[^/]+|~)\/memories\/experiences\/[^/]+\.md$/i.test(uri);
1204
- function experienceDateRange(days, now = new Date()) {
1205
- if (!days) return {};
1206
- const start = new Date(now);
1207
- start.setUTCDate(start.getUTCDate() - days + 1);
1208
- return {
1209
- start_date: start.toISOString().slice(0, 10),
1210
- end_date: now.toISOString().slice(0, 10)
1211
- };
1212
- }
1213
- async function readExperiences(client, uri, page, options) {
1214
- uri = await resolveDashboardUri(client, uri, options);
1215
- const result = await client.requestEnvelope({
1216
- method: 'GET',
1217
- path: OV_PATHS.fsLs,
1218
- query: {
1219
- uri,
1220
- output: 'original',
1221
- limit: EXPERIENCE_PAGE_SIZE,
1222
- offset: page * EXPERIENCE_PAGE_SIZE,
1223
- sort_by: 'mtime',
1224
- sort_order: 'desc'
1225
- },
1226
- options
1227
- });
1228
- if (!Array.isArray(result.result)) throw new TypeError('Invalid Experience listing');
1229
- const prefix = `${uri.replace(/\/+$/, '')}/`;
1230
- return {
1231
- items: result.result.filter((item)=>!item.isDir && item.uri.startsWith(prefix) && isExperienceFile(item.uri)),
1232
- hasMore: result.hasMore
1233
- };
1234
- }
1235
- async function readExperienceSources(client, uri, options) {
1236
- uri = await resolveDashboardUri(client, uri, options);
1237
- const result = await client.request({
1238
- method: 'GET',
1239
- path: OV_PATHS.fsAttrs,
1240
- query: {
1241
- uri
1242
- },
1243
- options
1244
- });
1245
- const links = result?.attrs?.memory?.links;
1246
- if (void 0 !== links && !Array.isArray(links)) throw new TypeError('Invalid Experience links');
1247
- const prefix = uri.slice(0, uri.indexOf('/memories/experiences/')) + '/memories/trajectories/';
1248
- const seen = new Set();
1249
- return (links ?? []).flatMap((link)=>{
1250
- if ('derived_from' !== link.link_type || 'string' != typeof link.to_uri || !link.to_uri.startsWith(prefix) || seen.has(link.to_uri)) return [];
1251
- seen.add(link.to_uri);
1252
- return [
1253
- {
1254
- uri: link.to_uri,
1255
- name: link.to_uri.split('/').pop() ?? link.to_uri,
1256
- description: link.description ?? link.match_text
1257
- }
1258
- ];
1259
- });
1260
- }
1261
- const dashboardKey = (uri)=>`dashboard:${uri}`;
1262
- const within = (uri, root)=>uri === root || uri.startsWith(`${root.replace(/\/+$/, '')}/`);
1263
- function resolveDashboard(uri, rows, targets) {
1264
- if (isExperienceDirectory(uri) || isExperienceFile(uri)) return {
1265
- kind: 'experience',
1266
- uri
1267
- };
1268
- const entries = rows.filter((row)=>'entry' === row.kind);
1269
- const row = entries.find((item)=>item.uri === uri);
1270
- const hasWiki = entries.some((item)=>item.tags?.includes('compile_target=true') && within(uri, item.uri));
1271
- const owner = targets.filter((item)=>within(uri, item.to)).sort((a, b)=>b.to.length - a.to.length)[0];
1272
- if (!hasWiki && !owner) return;
1273
- const tagged = row?.tags?.find((tag)=>tag.startsWith('has_conflict='));
1274
- return {
1275
- kind: 'wiki',
1276
- uri,
1277
- isRoot: Boolean(row?.tags?.includes('compile_target=true') || owner?.to === uri),
1278
- pendingConflicts: tagged ? 'has_conflict=true' === tagged : owner?.to === uri && void 0 !== owner.conflicts_num ? owner.conflicts_num > 0 : void 0
1279
- };
1280
- }
1281
- async function readCompileTargets(client, rootUri, options) {
1282
- rootUri = await resolveDashboardUri(client, rootUri, options);
1283
- const targets = [];
1284
- let cursor;
1285
- const seen = new Set();
1286
- do {
1287
- const result = await client.request({
1288
- method: 'GET',
1289
- path: OV_PATHS.compileConfigs,
1290
- query: {
1291
- limit: 100,
1292
- cursor
1293
- },
1294
- options
1295
- });
1296
- if (!Array.isArray(result?.targets)) throw new TypeError('Invalid Compile target registry');
1297
- targets.push(...result.targets.filter((item)=>'string' == typeof item.to && 'memory' !== item.compile_type && false !== item.initialized && (within(item.to, rootUri) || within(rootUri, item.to))));
1298
- cursor = result.next_cursor ?? void 0;
1299
- if (cursor && seen.has(cursor)) throw new TypeError('Compile target cursor did not advance');
1300
- if (cursor) seen.add(cursor);
1301
- }while (cursor)
1302
- return targets;
1303
- }
1304
- function useDashboardQuery(load, requestOptions, enabled = true, refreshGeneration = 0) {
1305
- const client = useOvClient();
1306
- const inheritedSignal = useOvSignal();
1307
- const { baseURL, apiKey, accountId, userId, resourceId, signal } = requestOptions ?? {};
1308
- const [generation, setGeneration] = useState(0);
1309
- const [state, setState] = useState({
1310
- owner: [],
1311
- error: null
1312
- });
1313
- const owner = useMemo(()=>[
1314
- client,
1315
- load,
1316
- baseURL,
1317
- apiKey,
1318
- accountId,
1319
- userId,
1320
- resourceId,
1321
- signal,
1322
- inheritedSignal,
1323
- generation,
1324
- enabled,
1325
- refreshGeneration
1326
- ], [
1327
- client,
1328
- load,
1329
- baseURL,
1330
- apiKey,
1331
- accountId,
1332
- userId,
1333
- resourceId,
1334
- signal,
1335
- inheritedSignal,
1336
- generation,
1337
- enabled,
1338
- refreshGeneration
1339
- ]);
1340
- const current = owner.every((value, i)=>value === state.owner[i]);
1341
- useEffect(()=>{
1342
- if (!enabled) return;
1343
- if (!client) return void setState({
1344
- owner,
1345
- error: new Error('OpenVikingProvider is required')
1346
- });
1347
- const controller = new AbortController();
1348
- const signals = [
1349
- controller.signal,
1350
- signal,
1351
- inheritedSignal
1352
- ].filter((value)=>Boolean(value));
1353
- const options = {
1354
- baseURL,
1355
- apiKey,
1356
- accountId,
1357
- userId,
1358
- resourceId,
1359
- signal: AbortSignal.any(signals)
1360
- };
1361
- load(client, options).then((data)=>{
1362
- if (!options.signal.aborted) setState({
1363
- owner,
1364
- data,
1365
- error: null
1366
- });
1367
- }, (cause)=>{
1368
- if (!options.signal.aborted) setState({
1369
- owner,
1370
- error: cause instanceof Error ? cause : new Error(String(cause))
1371
- });
1372
- });
1373
- return ()=>controller.abort();
1374
- }, [
1375
- client,
1376
- load,
1377
- baseURL,
1378
- apiKey,
1379
- accountId,
1380
- userId,
1381
- resourceId,
1382
- signal,
1383
- inheritedSignal,
1384
- generation,
1385
- enabled,
1386
- owner
1387
- ]);
1388
- return {
1389
- data: current ? state.data : void 0,
1390
- loading: enabled && !current,
1391
- error: current ? state.error : null,
1392
- retry: ()=>setGeneration((value)=>value + 1)
1393
- };
1394
- }
1395
- function useExperienceDashboard({ uri, requestOptions, enabled = true, refreshGeneration = 0 }) {
1396
- const client = useOvClient();
1397
- const signal = useOvSignal();
1398
- const owner = useMemo(()=>[
1399
- uri,
1400
- client,
1401
- signal,
1402
- requestOptions?.baseURL,
1403
- requestOptions?.apiKey,
1404
- requestOptions?.accountId,
1405
- requestOptions?.userId,
1406
- requestOptions?.resourceId
1407
- ], [
1408
- uri,
1409
- client,
1410
- signal,
1411
- requestOptions?.baseURL,
1412
- requestOptions?.apiKey,
1413
- requestOptions?.accountId,
1414
- requestOptions?.userId,
1415
- requestOptions?.resourceId
1416
- ]);
1417
- const [state, setState] = useState({
1418
- owner,
1419
- page: 0,
1420
- days: 7,
1421
- tab: 'impact'
1422
- });
1423
- const current = state.owner === owner ? state : {
1424
- owner,
1425
- page: 0,
1426
- days: 7,
1427
- tab: 'impact'
1428
- };
1429
- const { page, days, tab } = current;
1430
- const setPage = (value)=>setState({
1431
- ...current,
1432
- page: Math.max(0, value)
1433
- });
1434
- const setDays = (value)=>setState({
1435
- ...current,
1436
- days: value,
1437
- page: 0
1438
- });
1439
- const setTab = (value)=>setState({
1440
- ...current,
1441
- tab: value,
1442
- page: 0
1443
- });
1444
- const directory = isExperienceDirectory(uri);
1445
- const loadList = useCallback((client, options)=>readExperiences(client, uri, page, options), [
1446
- uri,
1447
- page
1448
- ]);
1449
- const loadSources = useCallback((client, options)=>readExperienceSources(client, uri, options), [
1450
- uri
1451
- ]);
1452
- const loadTrajectories = useCallback(async (client, options)=>{
1453
- const result = await client.request({
1454
- method: 'GET',
1455
- path: OV_PATHS.experienceTrajectories,
1456
- query: {
1457
- experience_uri: uri,
1458
- offset: 20 * page,
1459
- limit: 20,
1460
- ...experienceDateRange(days)
1461
- },
1462
- options
1463
- });
1464
- if (!Array.isArray(result?.items) || !Number.isSafeInteger(result.total) || result.total < 0 || result.items.some((item)=>'string' != typeof item?.uri || 'string' != typeof item.name)) throw new TypeError('Invalid Experience trajectories');
1465
- return result;
1466
- }, [
1467
- uri,
1468
- page,
1469
- days
1470
- ]);
1471
- const loadOutcomes = useCallback(async (client, options)=>{
1472
- const result = await client.request({
1473
- method: 'GET',
1474
- path: OV_PATHS.experienceOutcomes,
1475
- query: {
1476
- experience_uri: uri,
1477
- ...experienceDateRange(days)
1478
- },
1479
- options
1480
- });
1481
- if (!Array.isArray(result?.outcome_distribution) || result.outcome_distribution.some((entry)=>![
1482
- 'success',
1483
- 'partial',
1484
- 'unfinished',
1485
- 'failure',
1486
- 'unknown'
1487
- ].includes(entry?.outcome) || !Number.isSafeInteger(entry.count) || entry.count < 0)) throw new TypeError('Invalid Experience outcomes');
1488
- return result.outcome_distribution;
1489
- }, [
1490
- uri,
1491
- days
1492
- ]);
1493
- const list = useDashboardQuery(loadList, requestOptions, enabled && directory, refreshGeneration);
1494
- const sources = useDashboardQuery(loadSources, requestOptions, enabled && !directory && 'source' === tab, refreshGeneration);
1495
- const trajectories = useDashboardQuery(loadTrajectories, requestOptions, enabled && !directory && 'impact' === tab, refreshGeneration);
1496
- const outcomes = useDashboardQuery(loadOutcomes, requestOptions, enabled && !directory && 'impact' === tab, refreshGeneration);
1497
- return {
1498
- list,
1499
- sources,
1500
- trajectories,
1501
- outcomes,
1502
- page,
1503
- setPage,
1504
- days,
1505
- setDays,
1506
- tab,
1507
- setTab
1508
- };
1509
- }
1510
- function ExperienceDashboardPane({ uri, locale, requestOptions, refreshGeneration, onOpenUri }) {
1511
- const browser = useExperienceDashboard({
1512
- uri,
1513
- requestOptions,
1514
- refreshGeneration
1515
- });
1516
- const directory = isExperienceDirectory(uri);
1517
- const status = (query)=>({
1518
- loading: query.loading,
1519
- error: query.error,
1520
- onRetry: query.retry
1521
- });
1522
- return /*#__PURE__*/ jsx(ExperienceDashboard, {
1523
- uri: uri,
1524
- kind: directory ? 'directory' : 'file',
1525
- locale: locale,
1526
- onOpenUri: onOpenUri,
1527
- data: {
1528
- experiences: browser.list.data?.items,
1529
- outcomes: browser.outcomes.data,
1530
- trajectories: browser.trajectories.data?.items,
1531
- trajectoryTotal: browser.trajectories.data?.total,
1532
- sources: browser.sources.data
1533
- },
1534
- tab: browser.tab,
1535
- days: browser.days,
1536
- page: browser.page,
1537
- startIndex: 20 * browser.page,
1538
- hasMore: Boolean(directory ? browser.list.data?.hasMore : 'impact' === browser.tab && browser.trajectories.data?.has_more),
1539
- states: {
1540
- list: status(browser.list),
1541
- sources: status(browser.sources),
1542
- outcomes: status(browser.outcomes),
1543
- trajectories: status(browser.trajectories)
1544
- },
1545
- onTabChange: browser.setTab,
1546
- onDaysChange: browser.setDays,
1547
- onPageChange: browser.setPage
1548
- });
1549
- }
1550
- const wiki_conflicts_prefix = '<!-- CONFLICTS_CONTENT';
1551
- const manualResolutionBasis = '\u4eba\u5de5\u4fee\u590d';
1552
- const timestamp = (value)=>'number' == typeof value && Number.isSafeInteger(value) && value >= 0 && Number.isFinite(new Date(1000 * value).getTime());
1553
- const locateWikiConflict = (document, matchText)=>{
1554
- const mask = (value)=>value.replace(/[^\r\n]/g, ' ');
1555
- const body = document.replace(/^(?:\uFEFF)?---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/, mask).replace(/<!--[\s\S]*?(?:-->|$)/g, mask);
1556
- const start = matchText ? body.indexOf(matchText) : -1;
1557
- if (start < 0) return {
1558
- status: 'missing'
1559
- };
1560
- if (body.indexOf(matchText, start + 1) >= 0) return {
1561
- status: 'ambiguous'
1562
- };
1563
- return {
1564
- status: 'unique',
1565
- start,
1566
- end: start + matchText.length,
1567
- line: document.slice(0, start).split('\n').length
1568
- };
1569
- };
1570
- const parseWikiFileConflicts = (content)=>{
1571
- const start = content.lastIndexOf(wiki_conflicts_prefix);
1572
- if (start < 0) return {
1573
- status: 'missing'
1574
- };
1575
- const footer = content.slice(start).trimEnd();
1576
- if (!footer.endsWith('-->')) return {
1577
- status: 'invalid'
1578
- };
1579
- const document = content.slice(0, start);
1580
- const source = footer.slice(wiki_conflicts_prefix.length, -3).trim();
1581
- let parsed;
1582
- try {
1583
- parsed = source ? JSON.parse(`[${source}]`) : [];
1584
- } catch {
1585
- return {
1586
- status: 'invalid'
1587
- };
1588
- }
1589
- if (!Array.isArray(parsed)) return {
1590
- status: 'invalid'
1591
- };
1592
- const records = [];
1593
- for (const [index, raw] of parsed.entries()){
1594
- if (!raw || 'object' != typeof raw || Array.isArray(raw)) return {
1595
- status: 'invalid'
1596
- };
1597
- const value = raw;
1598
- if ('string' != typeof value.match_text || !value.match_text || 'string' != typeof value.problem_description || 'string' != typeof value.reason || ![
1599
- 'high',
1600
- 'medium',
1601
- 'low'
1602
- ].includes(value.severity) || ![
1603
- 'unfixed',
1604
- 'fixed'
1605
- ].includes(value.state) || !timestamp(value.begin_time) || 'string' != typeof value.fix_plan || 'string' != typeof value.resolution_basis) return {
1606
- status: 'invalid'
1607
- };
1608
- if ('fixed' === value.state ? !timestamp(value.fix_time) || value.fix_time < value.begin_time : null !== value.fix_time) return {
1609
- status: 'invalid'
1610
- };
1611
- const matchText = value.match_text;
1612
- const location = locateWikiConflict(document, matchText);
1613
- records.push({
1614
- id: JSON.stringify([
1615
- index,
1616
- value.begin_time,
1617
- matchText
1618
- ]),
1619
- matchText,
1620
- description: value.problem_description,
1621
- reason: value.reason,
1622
- severity: value.severity,
1623
- state: value.state,
1624
- beginTime: value.begin_time,
1625
- fixTime: value.fix_time,
1626
- fixPlan: value.fix_plan,
1627
- resolutionBasis: value.resolution_basis,
1628
- resolutionSource: 'fixed' === value.state && value.resolution_basis.trim() ? value.resolution_basis.trim() === manualResolutionBasis ? 'manual' : 'automatic' : void 0,
1629
- location
1630
- });
1631
- }
1632
- return {
1633
- status: 'available',
1634
- document,
1635
- records
1636
- };
1637
- };
1638
- async function readWikiDashboard(client, uri, options) {
1639
- const stat = await readDashboardStat(client, uri, options);
1640
- uri = stat.uri;
1641
- if (!stat.isDir) {
1642
- const result = await client.request({
1643
- method: 'GET',
1644
- path: OV_PATHS.contentRead,
1645
- query: {
1646
- uri,
1647
- limit: -1
1648
- },
1649
- options
1650
- });
1651
- if ('string' != typeof result) throw new TypeError('Invalid Wiki content response');
1652
- const parsed = parseWikiFileConflicts(result);
1653
- if ('invalid' === parsed.status) throw new TypeError('Invalid CONFLICTS_CONTENT metadata');
1654
- return {
1655
- kind: 'file',
1656
- data: {
1657
- path: uri,
1658
- conflicts: 'available' === parsed.status ? parsed.records : []
1659
- }
1660
- };
1661
- }
1662
- const page = await client.requestEnvelope({
1663
- method: 'GET',
1664
- path: OV_PATHS.fsLs,
1665
- query: {
1666
- uri,
1667
- recursive: true,
1668
- output: 'agent',
1669
- tags: [
1670
- 'has_conflict=true'
1671
- ],
1672
- limit: 100,
1673
- sort_by: 'mtime',
1674
- sort_order: 'desc'
1675
- },
1676
- options
1677
- });
1678
- if (!Array.isArray(page.result)) throw new TypeError('Invalid Wiki conflict listing');
1679
- const prefix = `${uri.replace(/\/+$/, '')}/`;
1680
- const files = page.result.filter((entry)=>!entry.isDir && entry.uri.startsWith(prefix)).map((entry)=>entry.uri);
1681
- return {
1682
- kind: 'directory',
1683
- data: {
1684
- files,
1685
- conflictFileCount: files.length,
1686
- limited: page.hasMore || files.length >= 100
1687
- }
1688
- };
1689
- }
1690
- function useWikiDashboard({ uri, requestOptions, enabled = true, refreshGeneration = 0 }) {
1691
- const load = useCallback((client, options)=>readWikiDashboard(client, uri, options), [
1692
- uri
1693
- ]);
1694
- return useDashboardQuery(load, requestOptions, enabled, refreshGeneration);
1695
- }
1696
- function WikiDashboardPane({ uri, kind, requestOptions, refreshGeneration, onOpenUri, onOpenDashboard, onEdit, onDiscuss, ...props }) {
1697
- const query = useWikiDashboard({
1698
- uri,
1699
- requestOptions,
1700
- refreshGeneration
1701
- });
1702
- const common = {
1703
- ...props,
1704
- loading: query.loading,
1705
- error: query.error,
1706
- onRetry: query.retry
1707
- };
1708
- if ((query.data?.kind ?? kind) === 'file') return /*#__PURE__*/ createElement(WikiDashboard, {
1709
- ...common,
1710
- key: uri,
1711
- kind: "file",
1712
- data: query.data?.kind === 'file' ? query.data.data : void 0,
1713
- onOpenUri: onOpenUri && (()=>onOpenUri(uri)),
1714
- onEdit: onEdit && ((conflict)=>onEdit(uri, conflict)),
1715
- onDiscuss: onDiscuss && ((conflict)=>onDiscuss(uri, conflict))
1716
- });
1717
- return /*#__PURE__*/ createElement(WikiDashboard, {
1718
- ...common,
1719
- key: uri,
1720
- kind: "directory",
1721
- data: query.data?.kind === 'directory' ? query.data.data : void 0,
1722
- onOpenUri: onOpenUri,
1723
- onOpenDashboard: onOpenDashboard,
1724
- onEdit: onEdit
1725
- });
1726
- }
1727
- function useBrowserDashboards({ rows, metadataRows, uri, rootUri, generation, locale, requestOptions, onOpenUri, dashboardKinds, renderDashboard, dashboardLabels }) {
1728
- const [opened, setOpened] = useState(null);
1729
- const load = useCallback((client, options)=>readCompileTargets(client, rootUri, options), [
1730
- rootUri
1731
- ]);
1732
- const wikiEnabled = void 0 === dashboardKinds || dashboardKinds.includes('wiki');
1733
- const catalog = useDashboardQuery(load, requestOptions, wikiEnabled, generation);
1734
- const loadHint = useCallback(async (client, options)=>uri ? readDashboardHint(client, uri, options) : void 0, [
1735
- uri
1736
- ]);
1737
- const hint = useDashboardQuery(loadHint, requestOptions, wikiEnabled && Boolean(uri), generation);
1738
- const canonicalUri = hint.data?.uri ?? uri;
1739
- const knownRows = canonicalUri && hint.data?.tags.includes('compile_target=true') ? [
1740
- ...metadataRows,
1741
- {
1742
- kind: 'entry',
1743
- uri: canonicalUri,
1744
- id: canonicalUri,
1745
- name: canonicalUri,
1746
- depth: 0,
1747
- type: 'directory',
1748
- tags: hint.data.tags
1749
- }
1750
- ] : metadataRows;
1751
- const unsupported = isOvClientError(catalog.error) && 404 === catalog.error.statusCode;
1752
- const targets = catalog.data ?? [];
1753
- const resolve = (target)=>{
1754
- const match = resolveDashboard(target === uri ? canonicalUri ?? target : target, knownRows, targets);
1755
- return match ? {
1756
- ...match,
1757
- uri: target
1758
- } : void 0;
1759
- };
1760
- const dashboards = new Map(rows.filter((row)=>'entry' === row.kind).flatMap((row)=>{
1761
- const dashboard = resolve(row.uri);
1762
- return dashboard && (void 0 === dashboardKinds || dashboardKinds.includes(dashboard.kind)) ? [
1763
- [
1764
- row.uri,
1765
- dashboard
1766
- ]
1767
- ] : [];
1768
- }));
1769
- const resolved = uri ? resolve(uri) : void 0;
1770
- const current = resolved && (void 0 === dashboardKinds || dashboardKinds.includes(resolved.kind)) ? resolved : void 0;
1771
- const open = useCallback((target)=>{
1772
- setOpened(target);
1773
- onOpenUri(target);
1774
- }, [
1775
- onOpenUri
1776
- ]);
1777
- const close = useCallback(()=>setOpened(null), []);
1778
- const text = dashboard_labels_dashboardLabels(locale, dashboardLabels);
1779
- const title = current?.kind === 'experience' ? text.experienceTitle : text.wikiTitle;
1780
- const tab = current && uri ? {
1781
- key: dashboardKey(uri),
1782
- title,
1783
- icon: createElement('experience' === current.kind ? ExperienceBoardIcon : WikiBoardIcon, {
1784
- width: 14,
1785
- height: 14
1786
- }),
1787
- kind: 'content',
1788
- content: renderDashboard?.(current) ?? ('experience' === current.kind ? createElement(ExperienceDashboardPane, {
1789
- uri,
1790
- locale,
1791
- requestOptions,
1792
- refreshGeneration: generation,
1793
- onOpenUri: (target)=>{
1794
- setOpened(null);
1795
- onOpenUri(target);
1796
- }
1797
- }) : createElement(WikiDashboardPane, {
1798
- uri,
1799
- kind: knownRows.some((row)=>'entry' === row.kind && row.uri === canonicalUri && 'file' === row.type) ? 'file' : 'directory',
1800
- locale,
1801
- requestOptions,
1802
- refreshGeneration: generation,
1803
- onOpenUri: (target)=>{
1804
- setOpened(null);
1805
- onOpenUri(target);
1806
- },
1807
- onOpenDashboard: open
1808
- }))
1809
- } : void 0;
1810
- return {
1811
- dashboards,
1812
- tab,
1813
- isOpen: null !== uri && opened === uri && Boolean(current),
1814
- open,
1815
- close,
1816
- error: unsupported ? null : catalog.error,
1817
- retry: catalog.retry
1818
- };
1819
- }
1820
- function knownDirectories(rootUri, dirs) {
1821
- const known = new Set([
1822
- rootUri
1823
- ]);
1824
- for (const [parent, level] of Object.entries(dirs)){
1825
- known.add(parent);
1826
- for (const entry of level.entries)if (true === entry.isDir) known.add(entry.uri);
1827
- }
1828
- return known;
1829
- }
1830
- function knownFiles(dirs) {
1831
- const known = new Set();
1832
- for (const level of Object.values(dirs))for (const entry of level.entries)if (true !== entry.isDir) known.add(entry.uri);
1833
- return known;
1834
- }
1835
- function useKnownFile(dirs) {
1836
- const files = useMemo(()=>knownFiles(dirs), [
1837
- dirs
1838
- ]);
1839
- return useCallback((uri)=>files.has(uri), [
1840
- files
1841
- ]);
1842
- }
1843
- function useTreeMetadata(rootUri, dirs) {
1844
- const directoryUris = useMemo(()=>knownDirectories(rootUri, dirs), [
1845
- rootUri,
1846
- dirs
1847
- ]);
1848
- const isKnownFile = useKnownFile(dirs);
1849
- const metadataRows = useMemo(()=>Object.values(dirs).flatMap((dir)=>dir.entries.map((entry)=>toEntryRow(entry, 0, false))), [
1850
- dirs
1851
- ]);
1852
- return {
1853
- directoryUris,
1854
- isKnownFile,
1855
- metadataRows
1856
- };
1857
- }
1858
- const ids = new WeakMap();
1859
- let nextId = 1;
1860
- function idOf(value) {
1861
- if (!value) return 0;
1862
- const existing = ids.get(value);
1863
- if (void 0 !== existing) return existing;
1864
- const assigned = nextId++;
1865
- ids.set(value, assigned);
1866
- return assigned;
1867
- }
1868
- function fieldKey(value) {
1869
- if (void 0 === value) return 'inherit';
1870
- if ('function' == typeof value) return `fn#${idOf(value)}`;
1871
- return `value:${value}`;
1872
- }
1873
- function scopeKeyOf(client, options, rootUri) {
1874
- return JSON.stringify([
1875
- idOf(client),
1876
- void 0 === rootUri ? 'inherit-root' : `root:${rootUri}`,
1877
- options?.baseURL === void 0 ? 'inherit-base' : `base:${options.baseURL}`,
1878
- fieldKey(options?.apiKey),
1879
- fieldKey(options?.accountId),
1880
- fieldKey(options?.userId),
1881
- fieldKey(options?.resourceId)
1882
- ]);
1883
- }
1884
- function useRequestScope(client, requestOptions, rootUri) {
1885
- const scopeKey = scopeKeyOf(client, requestOptions, rootUri);
1886
- const scopeRef = useRef({
1887
- key: scopeKey,
1888
- controller: new AbortController()
1889
- });
1890
- const handleRef = useRef({
1891
- current: ()=>scopeRef.current
1892
- });
1893
- useEffect(()=>{
1894
- const current = scopeRef.current;
1895
- if (current.key === scopeKey) return;
1896
- current.controller.abort();
1897
- scopeRef.current = {
1898
- key: scopeKey,
1899
- controller: new AbortController()
1900
- };
1901
- }, [
1902
- scopeKey
1903
- ]);
1904
- useEffect(()=>()=>{
1905
- scopeRef.current.controller.abort();
1906
- scopeRef.current = {
1907
- key: scopeRef.current.key,
1908
- controller: new AbortController()
1909
- };
1910
- }, []);
1911
- return handleRef.current;
1912
- }
1913
- function expandChain(rootUri, targetUri) {
1914
- if (!targetUri) return [];
1915
- const base = rootUri.endsWith('/') ? rootUri : `${rootUri}/`;
1916
- if (!targetUri.startsWith(base)) return [];
1917
- const rest = targetUri.slice(base.length).split('/').filter(Boolean);
1918
- return rest.map((_, index)=>`${base}${rest.slice(0, index + 1).join('/')}`);
1919
- }
1920
- const PAGE_SIZE = 200;
1921
- async function loadPage(client, uri, offset, signal, requestOptions) {
1922
- const envelope = await client.requestEnvelope({
1923
- method: 'GET',
1924
- path: OV_PATHS.fsLs,
1925
- query: {
1926
- uri,
1927
- output: 'agent',
1928
- include_tags: true,
1929
- node_limit: PAGE_SIZE,
1930
- offset
1931
- },
1932
- options: {
1933
- ...requestOptions,
1934
- signal
1935
- }
1936
- });
1937
- return {
1938
- entries: envelope.result ?? [],
1939
- hasMore: envelope.hasMore
1940
- };
1941
- }
1942
- function useFsTree({ client, rootUri, defaultExpandedUri, requestOptions }) {
1943
- const [dirs, setDirs] = useState({});
1944
- const [expanded, setExpanded] = useState(()=>new Set([
1945
- rootUri
1946
- ]));
1947
- const [isReady, setReady] = useState(false);
1948
- const [error, setError] = useState(null);
1949
- const dirsRef = useRef(dirs);
1950
- dirsRef.current = dirs;
1951
- const expandedRef = useRef(expanded);
1952
- expandedRef.current = expanded;
1953
- useEffect(()=>{
1954
- if (!client) return;
1955
- const controller = new AbortController();
1956
- setReady(false);
1957
- setError(null);
1958
- setExpanded(new Set([
1959
- rootUri
1960
- ]));
1961
- setDirs({
1962
- [rootUri]: {
1963
- ...emptyDir(),
1964
- loading: true
1965
- }
1966
- });
1967
- const run = async ()=>{
1968
- const root = await loadPage(client, rootUri, 0, controller.signal, requestOptions);
1969
- if (controller.signal.aborted) return;
1970
- setDirs({
1971
- [rootUri]: mergePage(void 0, root, 0)
1972
- });
1973
- const chain = expandChain(rootUri, defaultExpandedUri);
1974
- for (const uri of chain){
1975
- let page;
1976
- try {
1977
- page = await loadPage(client, uri, 0, controller.signal, requestOptions);
1978
- } catch (cause) {
1979
- if (isAbort(cause) || controller.signal.aborted) return;
1980
- break;
1981
- }
1982
- if (controller.signal.aborted) return;
1983
- setExpanded((prev)=>new Set(prev).add(uri));
1984
- setDirs((prev)=>({
1985
- ...prev,
1986
- [uri]: mergePage(prev[uri], page, 0)
1987
- }));
1988
- }
1989
- if (controller.signal.aborted) return;
1990
- setReady(true);
1991
- };
1992
- run().catch((cause)=>{
1993
- if (isAbort(cause) || controller.signal.aborted) return;
1994
- const failure = toError(cause);
1995
- setError(failure);
1996
- setDirs({
1997
- [rootUri]: {
1998
- ...emptyDir(),
1999
- loading: false,
2000
- error: failure
2001
- }
2002
- });
2003
- setReady(true);
2004
- });
2005
- return ()=>controller.abort();
2006
- }, [
2007
- client,
2008
- rootUri,
2009
- defaultExpandedUri,
2010
- requestOptions
2011
- ]);
2012
- const scope = useRequestScope(client, requestOptions, rootUri);
2013
- const state = useMemo(()=>{
2014
- const fetchPage = async (uri, offset)=>{
2015
- if (!client) return;
2016
- const current = scope.current();
2017
- const { signal } = current.controller;
2018
- if (signal.aborted) return;
2019
- if (uri === rootUri) setError(null);
2020
- setDirs((prev)=>({
2021
- ...prev,
2022
- [uri]: {
2023
- ...prev[uri] ?? emptyDir(),
2024
- loading: true,
2025
- error: null
2026
- }
2027
- }));
2028
- try {
2029
- const page = await loadPage(client, uri, offset, signal, requestOptions);
2030
- if (signal.aborted || scope.current().key !== current.key) return;
2031
- setDirs((prev)=>({
2032
- ...prev,
2033
- [uri]: mergePage(prev[uri], page, offset)
2034
- }));
2035
- } catch (cause) {
2036
- if (isAbort(cause) || signal.aborted) return;
2037
- const failure = toError(cause);
2038
- if (uri === rootUri) setError(failure);
2039
- setDirs((prev)=>({
2040
- ...prev,
2041
- [uri]: {
2042
- ...prev[uri] ?? emptyDir(),
2043
- loading: false,
2044
- error: failure
2045
- }
2046
- }));
2047
- }
2048
- };
2049
- return {
2050
- open: async (uri)=>{
2051
- setExpanded((prev)=>new Set(prev).add(uri));
2052
- if (!dirsRef.current[uri]) await fetchPage(uri, 0);
2053
- },
2054
- openPath: async (uri)=>{
2055
- const current = scope.current();
2056
- for (const parent of expandChain(rootUri, uri)){
2057
- if (current.controller.signal.aborted || scope.current().key !== current.key) return;
2058
- setExpanded((prev)=>new Set(prev).add(parent));
2059
- if (!dirsRef.current[parent]) await fetchPage(parent, 0);
2060
- }
2061
- },
2062
- toggleExpand: async (row)=>{
2063
- const isOpen = expandedRef.current.has(row.uri);
2064
- setExpanded((prev)=>{
2065
- const next = new Set(prev);
2066
- if (isOpen) next.delete(row.uri);
2067
- else next.add(row.uri);
2068
- return next;
2069
- });
2070
- if (!isOpen && !dirsRef.current[row.uri]) await fetchPage(row.uri, 0);
2071
- },
2072
- loadMore: (parentId)=>fetchPage(parentId, dirsRef.current[parentId]?.entries.length ?? 0),
2073
- retry: (parentId)=>fetchPage(parentId, 0),
2074
- refresh: async ()=>{
2075
- if (!client) return;
2076
- const current = scope.current();
2077
- const open = [
2078
- ...expandedRef.current
2079
- ];
2080
- setError(null);
2081
- setDirs({});
2082
- for (const uri of open){
2083
- if (scope.current().key !== current.key) return;
2084
- await fetchPage(uri, 0);
2085
- }
2086
- }
2087
- };
2088
- }, [
2089
- client,
2090
- rootUri,
2091
- requestOptions,
2092
- scope
2093
- ]);
2094
- const rows = useMemo(()=>flattenTree(rootUri, 0, dirs, expanded), [
2095
- rootUri,
2096
- dirs,
2097
- expanded
2098
- ]);
2099
- const metadata = useTreeMetadata(rootUri, dirs);
2100
- return {
2101
- rows,
2102
- ...metadata,
2103
- isReady,
2104
- error,
2105
- ...state
2106
- };
2107
- }
2108
- function useFileBrowser({ rootUri, locale: localeProp, dashboardKinds, renderDashboard, dashboardLabels, controlled = false, summaryLabels, formatCharacterCount, defaultExpandedUri, currentUri, requestOptions, onUriChange }) {
2109
- const locale = useLocale(localeProp);
2110
- const client = useOvClient();
2111
- const [query, setQuery] = useState('');
2112
- const [pendingUri, setPendingUri] = useState(currentUri);
2113
- const [refreshing, setRefreshing] = useState(false);
2114
- const [refreshGeneration, setRefreshGeneration] = useState(0);
2115
- const tree = useFsTree({
2116
- client,
2117
- rootUri,
2118
- defaultExpandedUri,
2119
- requestOptions
2120
- });
2121
- const search = useFsSearch({
2122
- client,
2123
- query,
2124
- targetUri: rootUri,
2125
- generation: refreshGeneration,
2126
- requestOptions
2127
- });
2128
- const activeUri = controlled ? currentUri : pendingUri;
2129
- const resourceType = null === activeUri ? 'file' : tree.directoryUris.has(activeUri) ? 'directory' : tree.isKnownFile(activeUri) ? 'file' : 'unknown';
2130
- const openTree = tree.open;
2131
- const notifyUriChange = useRef(onUriChange);
2132
- notifyUriChange.current = onUriChange;
2133
- const openParent = useMemo(()=>async (uri)=>{
2134
- setPendingUri(uri);
2135
- notifyUriChange.current(uri);
2136
- await openTree(uri);
2137
- }, [
2138
- openTree
2139
- ]);
2140
- const preview = useFsPreview({
2141
- client,
2142
- uri: activeUri,
2143
- resourceType,
2144
- labels: summaryLabels ?? resolveSummaryLabels(locale),
2145
- formatCharacterCount: formatCharacterCount ?? resolveLabels(void 0, locale).formatCharacterCount,
2146
- openParent,
2147
- generation: refreshGeneration,
2148
- requestOptions
2149
- });
2150
- const rows = useMemo(()=>{
2151
- if (null === search.results) return tree.rows;
2152
- return search.results.map((entry, index)=>toEntryRow(entry, 0, false, index));
2153
- }, [
2154
- search.results,
2155
- tree.rows
2156
- ]);
2157
- const openPath = tree.openPath;
2158
- const openResource = useMemo(()=>async (uri)=>{
2159
- setPendingUri(uri);
2160
- notifyUriChange.current(uri);
2161
- const directory = tree.directoryUris.has(uri) ? uri : uri.slice(0, uri.lastIndexOf('/'));
2162
- await openPath(directory);
2163
- }, [
2164
- openPath,
2165
- tree.directoryUris
2166
- ]);
2167
- const boards = useBrowserDashboards({
2168
- rows,
2169
- metadataRows: tree.metadataRows,
2170
- uri: activeUri,
2171
- rootUri,
2172
- generation: refreshGeneration,
2173
- locale,
2174
- requestOptions,
2175
- onOpenUri: openResource,
2176
- dashboardKinds,
2177
- renderDashboard,
2178
- dashboardLabels
2179
- });
2180
- const selectedId = selectedRowId(activeUri, search.results);
2181
- const { open, toggleExpand, loadMore, retry, refresh } = tree;
2182
- const { open: openDashboard, close: closeDashboard } = boards;
2183
- const setActiveKey = preview.setActiveKey;
2184
- const actions = useMemo(()=>({
2185
- select: async (row)=>{
2186
- closeDashboard();
2187
- setPendingUri(row.uri);
2188
- notifyUriChange.current(row.uri);
2189
- if ('directory' === row.type) await open(row.uri);
2190
- },
2191
- toggleExpand,
2192
- loadMore: async (row)=>{
2193
- const parentId = 'parentId' in row ? row.parentId : void 0;
2194
- if (parentId) await loadMore(parentId);
2195
- },
2196
- retry: async (row)=>{
2197
- const parentId = 'parentId' in row ? row.parentId : void 0;
2198
- if (parentId) await retry(parentId);
2199
- },
2200
- refresh: async ()=>{
2201
- setRefreshing(true);
2202
- try {
2203
- setRefreshGeneration((generation)=>generation + 1);
2204
- await refresh();
2205
- } finally{
2206
- setRefreshing(false);
2207
- }
2208
- },
2209
- openDashboard: openDashboard,
2210
- setPreviewKey: (key)=>{
2211
- if (activeUri && key === dashboardKey(activeUri)) openDashboard(activeUri);
2212
- else {
2213
- closeDashboard();
2214
- setActiveKey(key);
2215
- }
2216
- },
2217
- setQuery
2218
- }), [
2219
- setActiveKey,
2220
- open,
2221
- toggleExpand,
2222
- loadMore,
2223
- retry,
2224
- refresh,
2225
- openDashboard,
2226
- closeDashboard,
2227
- activeUri
2228
- ]);
2229
- return {
2230
- rows,
2231
- selectedId,
2232
- currentUri: activeUri,
2233
- isReady: tree.isReady,
2234
- error: tree.error ?? search.error ?? preview.error,
2235
- treeError: tree.error,
2236
- previewError: preview.error,
2237
- searchError: search.error,
2238
- dashboards: boards.dashboards,
2239
- dashboardError: boards.error,
2240
- previewTabs: boards.tab ? [
2241
- ...preview.tabs ?? [],
2242
- boards.tab
2243
- ] : preview.tabs,
2244
- previewKey: boards.isOpen && activeUri ? dashboardKey(activeUri) : preview.activeKey,
2245
- previewFooter: preview.footer,
2246
- query,
2247
- searching: null !== search.results,
2248
- searchLoading: search.loading,
2249
- refreshing,
2250
- actions
2251
- };
2252
- }
2253
- function FileBrowser({ uri, defaultUri, rootUri = 'viking://', defaultExpandedUri, locale: localeProp, agentConnect, dashboardKinds, renderDashboard, onUriChange, onImportResources, renderImportResources, labels, requestOptions, className, style, ...rest }) {
2254
- const locale = useLocale(localeProp);
2255
- const [internalUri, setInternalUri] = useState(()=>defaultUri ?? null);
2256
- const [preferredTreeWidth, setPreferredTreeWidth] = useState(352);
2257
- const searchId = useId();
2258
- const isControlled = void 0 !== uri;
2259
- const currentUri = isControlled ? uri : internalUri;
2260
- const text = resolveLabels(labels, locale);
2261
- const { ref: layoutRef, width: layoutWidth } = useContainerWidth();
2262
- const treeMaxWidth = resolveTreeMaxWidth(layoutWidth);
2263
- const treeWidth = Math.min(preferredTreeWidth, treeMaxWidth);
2264
- const changeUri = useCallback((next)=>{
2265
- if (!isControlled) setInternalUri(next);
2266
- onUriChange?.(next);
2267
- }, [
2268
- isControlled,
2269
- onUriChange
2270
- ]);
2271
- const summaryLabels = useMemo(()=>({
2272
- l0: text.l0Summary,
2273
- l1: text.l1Overview,
2274
- failure: text.summaryFailed
2275
- }), [
2276
- text.l0Summary,
2277
- text.l1Overview,
2278
- text.summaryFailed
2279
- ]);
2280
- const previewLabels = useMemo(()=>resolvePreviewLabels(resolveLabels(labels, locale)), [
2281
- labels,
2282
- locale
2283
- ]);
2284
- const browser = useFileBrowser({
2285
- rootUri,
2286
- locale,
2287
- dashboardKinds,
2288
- renderDashboard,
2289
- dashboardLabels: labels?.dashboard,
2290
- controlled: isControlled,
2291
- summaryLabels,
2292
- formatCharacterCount: text.formatCharacterCount,
2293
- defaultExpandedUri,
2294
- currentUri,
2295
- requestOptions,
2296
- onUriChange: changeUri
2297
- });
2298
- return /*#__PURE__*/ jsx(LocaleProvider, {
2299
- locale: locale,
2300
- children: /*#__PURE__*/ jsxs("div", {
2301
- ...rest,
2302
- ref: layoutRef,
2303
- className: [
2304
- 'ov-file-browser',
2305
- className
2306
- ].filter(Boolean).join(' '),
2307
- style: {
2308
- ...style,
2309
- '--ov-file-browser-tree-width': `${treeWidth}px`
2310
- },
2311
- children: [
2312
- /*#__PURE__*/ jsx("div", {
2313
- className: "ov-file-browser__tree",
2314
- children: /*#__PURE__*/ jsx(FileBrowserTreePane, {
2315
- entries: {
2316
- agentConnect,
2317
- onImportResources,
2318
- renderImportResources,
2319
- labels: labels?.entries
2320
- },
2321
- searchId: searchId,
2322
- browser: browser,
2323
- treeLabels: text.tree,
2324
- locale: locale,
2325
- dashboardLabels: labels?.dashboard,
2326
- searchPlaceholder: text.searchPlaceholder,
2327
- refreshLabel: text.refresh,
2328
- searchLoading: text.searchLoading,
2329
- searchEmpty: text.searchEmpty,
2330
- searchErrorLabel: text.searchFailed,
2331
- retryLabel: text.retry
2332
- })
2333
- }),
2334
- /*#__PURE__*/ jsx(ResizableHandle, {
2335
- label: text.resizeTree,
2336
- min: 200,
2337
- max: treeMaxWidth,
2338
- value: treeWidth,
2339
- onResize: setPreferredTreeWidth,
2340
- className: "ov-file-browser__resizer"
2341
- }),
2342
- browser.previewTabs && browser.previewTabs.length > 0 ? /*#__PURE__*/ jsx(FileBrowserDetail, {
2343
- tabs: browser.previewTabs,
2344
- activeKey: browser.previewKey,
2345
- locale: locale,
2346
- labels: previewLabels,
2347
- footer: browser.previewFooter,
2348
- viewLabels: {
2349
- preview: text.previewMode,
2350
- source: text.sourceMode,
2351
- copyPath: text.copyPath,
2352
- copyContent: text.copyContent,
2353
- download: text.download,
2354
- viewSwitch: text.viewSwitch
2355
- },
2356
- onActiveKeyChange: browser.actions.setPreviewKey
2357
- }) : browser.currentUri && browser.previewError ? /*#__PURE__*/ jsx("div", {
2358
- className: "ov-file-browser__detail",
2359
- children: /*#__PURE__*/ jsx(FileBrowserFailure, {
2360
- message: text.error,
2361
- detail: browser.previewError.message,
2362
- retryLabel: text.retry,
2363
- onRetry: ()=>void browser.actions.refresh()
2364
- })
2365
- }) : /*#__PURE__*/ jsx("div", {
2366
- className: "ov-file-browser__detail",
2367
- children: /*#__PURE__*/ jsx(FileBrowserEmpty, {
2368
- label: text.empty
2369
- })
2370
- })
2371
- ]
2372
- })
2373
- });
2374
- }
2375
- export { FileBrowser };
55
+ export { EmailLoginForm };