@openviking/react 0.1.7 → 0.1.8-beta.11.1.gc6def608a25e

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 (127) hide show
  1. package/README.md +11 -1
  2. package/dist/1~0.js +57 -0
  3. package/dist/3~0.js +171 -5
  4. package/dist/5~0.js +181 -0
  5. package/dist/6~0.js +48 -0
  6. package/dist/ark-message-list-view~0.js +50 -8
  7. package/dist/components/agent-connect/style.css +4 -2
  8. package/dist/components/api-key-login-form/api-key-login-form.d.ts +2 -0
  9. package/dist/components/api-key-login-form/index.d.ts +3 -0
  10. package/dist/components/api-key-login-form/style.css +438 -0
  11. package/dist/components/api-key-login-form/style.js +0 -0
  12. package/dist/components/api-key-login-form/types.d.ts +7 -0
  13. package/dist/components/api-key-login-form.js +1 -0
  14. package/dist/components/directory-tour/directory-tour-intro.d.ts +3 -0
  15. package/dist/components/directory-tour/index.d.ts +2 -1
  16. package/dist/components/directory-tour/style.css +154 -26
  17. package/dist/components/directory-tour/tour-card.d.ts +14 -0
  18. package/dist/components/directory-tour/types.d.ts +24 -1
  19. package/dist/components/directory-tour/use-tour-anchor.d.ts +1 -0
  20. package/dist/components/directory-tour/use-tour-position.d.ts +4 -1
  21. package/dist/components/directory-tour/use-tour-theme.d.ts +2 -0
  22. package/dist/components/directory-tour.js +52 -1
  23. package/dist/components/email-login-form/email-login-form.d.ts +2 -0
  24. package/dist/components/email-login-form/index.d.ts +3 -0
  25. package/dist/components/email-login-form/style.css +438 -0
  26. package/dist/components/email-login-form/style.js +0 -0
  27. package/dist/components/email-login-form/types.d.ts +11 -0
  28. package/dist/components/email-login-form.js +1 -0
  29. package/dist/components/experience-dashboard/experience-impact.d.ts +3 -1
  30. package/dist/components/experience-dashboard/style.css +4 -2
  31. package/dist/components/file-browser-entries/style.css +12 -6
  32. package/dist/components/file-preview/file-preview-header.d.ts +4 -21
  33. package/dist/components/file-preview/file-preview-toolbar.d.ts +7 -0
  34. package/dist/components/file-preview/locales/en-US.d.ts +9 -0
  35. package/dist/components/file-preview/locales/zh-CN.d.ts +9 -0
  36. package/dist/components/file-preview/style.css +116 -2
  37. package/dist/components/file-preview/types.d.ts +14 -21
  38. package/dist/components/file-tree/style.css +4 -2
  39. package/dist/components/invitation-confirmation/index.d.ts +3 -0
  40. package/dist/components/invitation-confirmation/invitation-confirmation.d.ts +2 -0
  41. package/dist/components/invitation-confirmation/style.css +438 -0
  42. package/dist/components/invitation-confirmation/style.js +0 -0
  43. package/dist/components/invitation-confirmation/types.d.ts +20 -0
  44. package/dist/components/invitation-confirmation.js +1 -0
  45. package/dist/components/login-method-selector/index.d.ts +2 -0
  46. package/dist/components/login-method-selector/login-method-selector.d.ts +2 -0
  47. package/dist/components/login-method-selector/style.css +438 -0
  48. package/dist/components/login-method-selector/style.js +0 -0
  49. package/dist/components/login-method-selector/types.d.ts +14 -0
  50. package/dist/components/login-method-selector.js +1 -0
  51. package/dist/components/password-reset-request-form/index.d.ts +3 -0
  52. package/dist/components/password-reset-request-form/password-reset-request-form.d.ts +2 -0
  53. package/dist/components/password-reset-request-form/style.css +438 -0
  54. package/dist/components/password-reset-request-form/style.js +0 -0
  55. package/dist/components/password-reset-request-form/types.d.ts +13 -0
  56. package/dist/components/password-reset-request-form.js +1 -0
  57. package/dist/components/password-setup-form/index.d.ts +3 -0
  58. package/dist/components/password-setup-form/password-setup-form.d.ts +2 -0
  59. package/dist/components/password-setup-form/style.css +438 -0
  60. package/dist/components/password-setup-form/style.js +0 -0
  61. package/dist/components/password-setup-form/types.d.ts +10 -0
  62. package/dist/components/password-setup-form.js +1 -0
  63. package/dist/components/scope-switcher/style.css +4 -2
  64. package/dist/components/scope-switcher.js +1 -1
  65. package/dist/components/style.css +3120 -79
  66. package/dist/components/tui/style.css +8 -4
  67. package/dist/components/viking-bot/bot-popover.d.ts +2 -1
  68. package/dist/components/viking-bot/composer-reference-tags.d.ts +8 -0
  69. package/dist/components/viking-bot/composer-references.d.ts +0 -5
  70. package/dist/components/viking-bot/locales/en-US.d.ts +1 -0
  71. package/dist/components/viking-bot/locales/zh-CN.d.ts +1 -0
  72. package/dist/components/viking-bot/model.d.ts +1 -0
  73. package/dist/components/viking-bot/popover-tab-navigation.d.ts +3 -0
  74. package/dist/components/viking-bot/style.css +166 -27
  75. package/dist/components/viking-bot/types.d.ts +3 -1
  76. package/dist/components/viking-bot/user-message-group.d.ts +9 -0
  77. package/dist/components/wiki-dashboard/index.d.ts +1 -1
  78. package/dist/components/wiki-dashboard/style.css +16 -4
  79. package/dist/components/wiki-dashboard/types.d.ts +12 -16
  80. package/dist/components/wiki-dashboard/wiki-action-button.d.ts +2 -9
  81. package/dist/components/wiki-dashboard/wiki-conflict-card.d.ts +3 -10
  82. package/dist/c~0.js +77 -6
  83. package/dist/d~0.js +28 -0
  84. package/dist/ep~0.js +281 -133
  85. package/dist/fi~0.js +339 -0
  86. package/dist/fj~0.js +32 -67
  87. package/dist/fl~0.js +3 -2
  88. package/dist/f~0.js +63 -326
  89. package/dist/g~0.js +135 -0
  90. package/dist/icons/index.d.ts +2 -0
  91. package/dist/icons/viking-bot-icons.d.ts +1 -1
  92. package/dist/icons.js +1 -1
  93. package/dist/index.d.ts +12 -0
  94. package/dist/index.js +8 -2
  95. package/dist/k~0.js +44 -4
  96. package/dist/l5~0.js +3813 -0
  97. package/dist/lg~0.js +41 -1
  98. package/dist/lk~0.js +1 -1
  99. package/dist/l~0.js +54 -3811
  100. package/dist/modules/console/style.css +182 -35
  101. package/dist/modules/file-browser/file-browser-detail-icons.d.ts +0 -6
  102. package/dist/modules/file-browser/file-browser-detail.d.ts +2 -23
  103. package/dist/modules/file-browser/file-browser.d.ts +1 -1
  104. package/dist/modules/file-browser/fs-file-editing.d.ts +4 -0
  105. package/dist/modules/file-browser/fs-preview-images.d.ts +3 -0
  106. package/dist/modules/file-browser/fs-read-file.d.ts +1 -1
  107. package/dist/modules/file-browser/style.css +156 -70
  108. package/dist/modules/file-browser/types.d.ts +2 -0
  109. package/dist/modules/file-browser/use-file-browser-acl.d.ts +1 -0
  110. package/dist/modules/file-browser/wiki-dashboard-pane.d.ts +2 -4
  111. package/dist/modules/file-browser.js +1 -1
  112. package/dist/modules/scope-cascade/style.css +4 -2
  113. package/dist/modules/style.css +346 -109
  114. package/dist/n~0.js +1 -1
  115. package/dist/p0~0.js +27 -0
  116. package/dist/p~0.js +34 -25
  117. package/dist/shared/auth/agreements.d.ts +10 -0
  118. package/dist/shared/auth/fields.d.ts +15 -0
  119. package/dist/shared/auth/form-frame.d.ts +12 -0
  120. package/dist/shared/auth/locales/en-US.d.ts +24 -0
  121. package/dist/shared/auth/locales/zh-CN.d.ts +24 -0
  122. package/dist/shared/auth/types.d.ts +61 -0
  123. package/dist/shared/auth/use-auth-labels.d.ts +3 -0
  124. package/dist/shared/auth/use-form.d.ts +8 -0
  125. package/dist/style.css +3690 -410
  126. package/dist/viking-bot-composer~0.js +86 -29
  127. package/package.json +32 -2
package/dist/l~0.js CHANGED
@@ -1,3812 +1,55 @@
1
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { createElement, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
3
- import { createPortal } from "react-dom";
4
- import { CSSTransition } from "react-transition-group";
5
- import { FilePreview as file_preview_FilePreview } from "./3~0.js";
6
- import { button_Button } from "./e~0.js";
7
- import { FileTree as file_tree_FileTree, FileTreeToolbar } from "./n~0.js";
8
- import { getFileTypeColor, getFileTypeIcon, WikiBookIcon, ExperienceBoardIcon, WikiConflictBoardIcon, FolderIcon, WikiBoardIcon, resolveFileTypeIconKey } from "./k~0.js";
9
- import { FileBrowserEntries, es2015, lockBodyScroll } from "./2~0.js";
10
- import { removereact } from "./4~0.js";
11
- import { useLocale, LocaleProvider } from "./28~0.js";
12
- import { resolveLocale } from "./nx~0.js";
13
- import { usePortalTheme } from "./9~0.js";
14
- import { OV_PATHS, OV_PATH_BUILDERS } from "./ck~0.js";
15
- import { useOvSignal, useOvClient, isOvClientError, useOvIdentity } from "./ae~0.js";
16
- import { input_Input } from "./c7r~0.js";
17
- import { ExperienceDashboard } from "./fl~0.js";
18
- import { WikiDashboard } from "./fj~0.js";
19
- import { chevron_downreact } from "./s~0.js";
20
- import { checkreact } from "./0~0.js";
21
- function clampResizableWidth(width, min, max) {
22
- const rounded = Math.round(width);
23
- const lower = Math.max(min, rounded);
24
- return Math.min(Math.max(min, max), lower);
25
- }
26
- function ResizableHandle({ label, min, max, value, step = 16, direction = 1, onResize, className, ...rest }) {
27
- const dragRef = useRef(null);
28
- const [dragging, setDragging] = useState(false);
29
- const endDrag = (event)=>{
30
- if (!dragRef.current) return;
31
- dragRef.current = null;
32
- setDragging(false);
33
- if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
34
- };
35
- const handlePointerDown = (event)=>{
36
- if (!onResize) return;
37
- if (0 !== event.button) return;
38
- event.preventDefault();
39
- event.currentTarget.setPointerCapture(event.pointerId);
40
- dragRef.current = {
41
- pointerId: event.pointerId,
42
- x: event.clientX,
43
- width: value
44
- };
45
- setDragging(true);
46
- };
47
- const handlePointerMove = (event)=>{
48
- const drag = dragRef.current;
49
- if (!drag || !onResize || drag.pointerId !== event.pointerId) return;
50
- onResize(clampResizableWidth(drag.width + (event.clientX - drag.x) * direction, min, max));
51
- };
52
- const handleKeyDown = (event)=>{
53
- if (!onResize) return;
54
- if ('ArrowLeft' !== event.key && 'ArrowRight' !== event.key) return;
55
- event.preventDefault();
56
- const delta = ('ArrowRight' === event.key ? step : -step) * direction;
57
- onResize(clampResizableWidth(value + delta, min, max));
58
- };
59
- return /*#__PURE__*/ jsx("div", {
60
- ...rest,
61
- role: "separator",
62
- tabIndex: onResize ? 0 : void 0,
63
- "aria-label": label,
64
- "aria-orientation": "vertical",
65
- "aria-valuemin": min,
66
- "aria-valuemax": max,
67
- "aria-valuenow": Math.round(value),
68
- "data-dragging": dragging || void 0,
69
- className: [
70
- 'ov-resizable-handle',
71
- className
72
- ].filter(Boolean).join(' '),
73
- onPointerDown: handlePointerDown,
74
- onPointerMove: handlePointerMove,
75
- onPointerUp: endDrag,
76
- onPointerCancel: endDrag,
77
- onKeyDown: handleKeyDown,
78
- children: /*#__PURE__*/ jsx("span", {
79
- "aria-hidden": "true",
80
- className: "ov-resizable-handle__line"
81
- })
82
- });
83
- }
84
- const SIZE = 14;
85
- function iconProps(size = SIZE) {
86
- return {
87
- width: size,
88
- height: size,
89
- viewBox: '0 0 16 16',
90
- fill: 'none',
91
- stroke: 'currentColor',
92
- strokeWidth: 1.4,
93
- strokeLinecap: 'round',
94
- strokeLinejoin: 'round',
95
- 'aria-hidden': true,
96
- focusable: 'false'
97
- };
98
- }
99
- function CopyIcon({ size = 12 }) {
100
- return /*#__PURE__*/ jsxs("svg", {
101
- ...iconProps(size),
102
- children: [
103
- /*#__PURE__*/ jsx("rect", {
104
- x: "5.5",
105
- y: "5.5",
106
- width: "8",
107
- height: "8",
108
- rx: "1.5"
109
- }),
110
- /*#__PURE__*/ jsx("path", {
111
- 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"
112
- })
113
- ]
114
- });
115
- }
116
- function DownloadIcon() {
117
- return /*#__PURE__*/ jsxs("svg", {
118
- ...iconProps(),
119
- children: [
120
- /*#__PURE__*/ jsx("path", {
121
- d: "M8 2.5v8"
122
- }),
123
- /*#__PURE__*/ jsx("path", {
124
- d: "M5 7.5 8 10.5l3-3"
125
- }),
126
- /*#__PURE__*/ jsx("path", {
127
- d: "M2.5 12.5h11"
128
- })
129
- ]
130
- });
131
- }
132
- function FileBrowserDetail({ tabs, activeKey, locale, labels, footer, titleExtra, extraActions, viewLabels, onActiveKeyChange }) {
133
- return /*#__PURE__*/ jsx("div", {
134
- className: "ov-file-browser__detail",
135
- children: /*#__PURE__*/ jsx(file_preview_FilePreview, {
136
- tabs: decorateTabs(tabs, viewLabels, footer, titleExtra, extraActions),
137
- activeKey: activeKey ?? void 0,
138
- locale: locale,
139
- labels: labels,
140
- onActiveKeyChange: onActiveKeyChange
141
- })
142
- });
143
- }
144
- function decorateTabs(tabs, viewLabels, footer, titleExtra, extraActions) {
145
- return tabs.map((tab)=>{
146
- if ('content' === tab.kind) return tab;
147
- return {
148
- ...tab,
149
- slots: {
150
- ...tab.slots,
151
- footer,
152
- titleExtra: /*#__PURE__*/ jsxs(Fragment, {
153
- children: [
154
- tab.slots?.titleExtra,
155
- titleExtra
156
- ]
157
- }),
158
- actions: (actions)=>/*#__PURE__*/ jsxs("div", {
159
- className: "ov-file-browser__detail-actions",
160
- children: [
161
- extraActions,
162
- actions.canSwitchView ? /*#__PURE__*/ jsxs("div", {
163
- className: "ov-file-browser__segmented",
164
- role: "group",
165
- "aria-label": viewLabels.viewSwitch,
166
- children: [
167
- /*#__PURE__*/ jsx("button", {
168
- type: "button",
169
- className: "ov-file-browser__segment",
170
- "data-active": 'preview' === actions.viewMode || void 0,
171
- onClick: ()=>actions.setViewMode('preview'),
172
- children: viewLabels.preview
173
- }),
174
- /*#__PURE__*/ jsx("button", {
175
- type: "button",
176
- className: "ov-file-browser__segment",
177
- "data-active": 'source' === actions.viewMode || void 0,
178
- onClick: ()=>actions.setViewMode('source'),
179
- children: viewLabels.source
180
- })
181
- ]
182
- }) : null,
183
- actions.canCopyContent || actions.canDownload ? /*#__PURE__*/ jsx("span", {
184
- "aria-hidden": "true",
185
- className: "ov-file-browser__detail-sep"
186
- }) : null,
187
- actions.canCopyContent ? /*#__PURE__*/ jsx(button_Button, {
188
- size: "small",
189
- type: "text",
190
- iconOnly: true,
191
- htmlType: "button",
192
- className: "ov-file-browser__detail-icon",
193
- "aria-label": viewLabels.copyContent,
194
- title: viewLabels.copyContent,
195
- onClick: ()=>void actions.copyContent(),
196
- children: /*#__PURE__*/ jsx(CopyIcon, {})
197
- }) : null,
198
- actions.canDownload ? /*#__PURE__*/ jsx(button_Button, {
199
- size: "small",
200
- type: "text",
201
- iconOnly: true,
202
- htmlType: "button",
203
- className: "ov-file-browser__detail-icon",
204
- "aria-label": viewLabels.download,
205
- title: viewLabels.download,
206
- onClick: ()=>actions.download(),
207
- children: /*#__PURE__*/ jsx(DownloadIcon, {})
208
- }) : null
209
- ]
210
- })
211
- }
212
- };
213
- });
214
- }
215
- const empty_state_namespaceObject = "data:image/png;base64,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";
216
- function FileBrowserEmpty({ label }) {
217
- return /*#__PURE__*/ jsxs("div", {
218
- className: "ov-file-browser__empty",
219
- children: [
220
- /*#__PURE__*/ jsx("img", {
221
- className: "ov-file-browser__empty-art",
222
- src: empty_state_namespaceObject,
223
- alt: "",
224
- "aria-hidden": "true"
225
- }),
226
- /*#__PURE__*/ jsx("p", {
227
- className: "ov-file-browser__empty-label",
228
- children: label
229
- })
230
- ]
231
- });
232
- }
233
- function FileBrowserFailure({ message, detail, retryLabel, onRetry }) {
234
- return /*#__PURE__*/ jsxs("div", {
235
- className: "ov-file-browser__failure",
236
- role: "alert",
237
- children: [
238
- /*#__PURE__*/ jsx("p", {
239
- className: "ov-file-browser__failure-title",
240
- children: message
241
- }),
242
- detail ? /*#__PURE__*/ jsx("p", {
243
- className: "ov-file-browser__failure-detail",
244
- children: detail
245
- }) : null,
246
- /*#__PURE__*/ jsx(button_Button, {
247
- size: "small",
248
- type: "default",
249
- htmlType: "button",
250
- className: "ov-file-browser__failure-retry",
251
- onClick: onRetry,
252
- children: retryLabel
253
- })
254
- ]
255
- });
256
- }
257
- const TREE_MIN_WIDTH = 200;
258
- const DETAIL_MIN_WIDTH = 320;
259
- const RESIZE_FOOTPRINT = 24;
260
- const TREE_MAX_WIDTH = 520;
261
- function resolveTreeMaxWidth(containerWidth) {
262
- if (!containerWidth) return TREE_MAX_WIDTH;
263
- return Math.max(TREE_MIN_WIDTH, Math.min(TREE_MAX_WIDTH, containerWidth - DETAIL_MIN_WIDTH - RESIZE_FOOTPRINT));
264
- }
265
- const en = {
266
- experienceTitle: 'Experience dashboard',
267
- wikiTitle: 'Dashboard',
268
- openExperience: 'Open experience dashboard',
269
- openWiki: 'Open Wiki dashboard',
270
- wikiConflicts: 'View pending Wiki conflicts',
271
- failed: 'Could not load dashboard information'
272
- };
273
- const zh = {
274
- experienceTitle: '经验看板',
275
- wikiTitle: '看板',
276
- openExperience: '打开经验看板',
277
- openWiki: '打开 Wiki 看板',
278
- wikiConflicts: '查看 Wiki 待确认冲突',
279
- failed: '看板信息加载失败'
280
- };
281
- const dashboard_labels_dashboardLabels = (locale, labels)=>({
282
- ...'zh-CN' === locale ? zh : en,
283
- ...labels
284
- });
285
- function FileBrowserToolbar({ refreshing, canRefresh, placeholder, refreshLabel, onSearch, onRefresh }) {
286
- return /*#__PURE__*/ jsx(FileTreeToolbar, {
287
- className: "ov-file-browser__toolbar",
288
- search: true,
289
- refresh: {
290
- disabled: !canRefresh
291
- },
292
- refreshing: refreshing,
293
- text: {
294
- search: placeholder,
295
- refresh: refreshLabel
296
- },
297
- onSearch: onSearch,
298
- onRefresh: onRefresh
299
- });
300
- }
301
- function DashboardIndicator({ dashboard, locale, labels, onOpen }) {
302
- const text = dashboard_labels_dashboardLabels(locale, labels);
303
- const label = 'experience' === dashboard.kind ? text.openExperience : dashboard.pendingConflicts ? text.wikiConflicts : text.openWiki;
304
- const Icon = 'experience' === dashboard.kind ? ExperienceBoardIcon : dashboard.pendingConflicts ? WikiConflictBoardIcon : WikiBoardIcon;
305
- return /*#__PURE__*/ jsx("button", {
306
- type: "button",
307
- className: `ov-file-browser__dashboard${dashboard.pendingConflicts ? ' ov-file-browser__dashboard--pending' : ''}`,
308
- "aria-label": label,
309
- title: label,
310
- onClick: (event)=>{
311
- event.stopPropagation();
312
- onOpen(dashboard.uri);
313
- },
314
- children: /*#__PURE__*/ jsx(Icon, {
315
- width: 12,
316
- height: 12
317
- })
318
- });
319
- }
320
- function fileTypeIcon(name) {
321
- const Icon = getFileTypeIcon(name);
322
- const key = resolveFileTypeIconKey(name);
323
- return /*#__PURE__*/ jsx(Icon, {
324
- className: "ov-file-tree__file-type-icon",
325
- style: {
326
- '--ov-file-tree-icon-light': getFileTypeColor(key, 'light'),
327
- '--ov-file-tree-icon-dark': getFileTypeColor(key, 'dark')
328
- }
329
- });
330
- }
331
- function directoryIcon() {
332
- return /*#__PURE__*/ jsx(FolderIcon, {
333
- className: "ov-file-tree__file-type-icon"
334
- });
335
- }
336
- function FileBrowserTreePane({ entries, locale, dashboardLabels, onSearch, browser, treeLabels, searchPlaceholder, refreshLabel, retryLabel }) {
337
- return /*#__PURE__*/ jsxs(Fragment, {
338
- children: [
339
- /*#__PURE__*/ jsx(FileBrowserEntries, {
340
- ...entries,
341
- locale: locale,
342
- className: "ov-file-browser__entries"
343
- }),
344
- /*#__PURE__*/ jsx(FileBrowserToolbar, {
345
- onSearch: onSearch,
346
- refreshing: browser.refreshing,
347
- canRefresh: browser.isReady,
348
- placeholder: searchPlaceholder,
349
- refreshLabel: refreshLabel,
350
- onRefresh: ()=>void browser.actions.refresh()
351
- }),
352
- /*#__PURE__*/ jsxs("div", {
353
- className: "ov-file-browser__tree-scroll",
354
- children: [
355
- browser.dashboardError ? /*#__PURE__*/ jsxs("div", {
356
- className: "ov-file-browser__hint ov-file-browser__hint--error",
357
- "aria-live": "polite",
358
- children: [
359
- /*#__PURE__*/ jsxs("p", {
360
- children: [
361
- dashboard_labels_dashboardLabels(locale, dashboardLabels).failed,
362
- ":",
363
- ' ',
364
- browser.dashboardError.message
365
- ]
366
- }),
367
- /*#__PURE__*/ jsx(button_Button, {
368
- size: "small",
369
- type: "default",
370
- htmlType: "button",
371
- onClick: ()=>void browser.actions.refresh(),
372
- children: retryLabel
373
- })
374
- ]
375
- }) : null,
376
- /*#__PURE__*/ jsx(file_tree_FileTree, {
377
- search: false,
378
- refresh: false,
379
- locale: locale,
380
- rows: browser.rows,
381
- selectedId: browser.selectedId,
382
- isReady: browser.isReady,
383
- labels: treeLabels,
384
- renderRowIcon: (row)=>browser.dashboards.get(row.uri)?.isRoot ? /*#__PURE__*/ jsx(WikiBookIcon, {
385
- width: 14,
386
- height: 14
387
- }) : fileTypeIcon(row.name),
388
- renderDashboard: (row)=>{
389
- const dashboard = browser.dashboards.get(row.uri);
390
- return dashboard ? /*#__PURE__*/ jsx(DashboardIndicator, {
391
- dashboard: dashboard,
392
- locale: locale,
393
- labels: dashboardLabels,
394
- onOpen: browser.actions.openDashboard
395
- }) : null;
396
- },
397
- operations: {
398
- select: browser.actions.select,
399
- toggleExpand: browser.actions.toggleExpand,
400
- loadMore: browser.actions.loadMore,
401
- retry: browser.actions.retry
402
- }
403
- })
404
- ]
405
- })
406
- ]
407
- });
408
- }
409
- const en_US = {
410
- closeLabel: 'Close dialog'
411
- };
412
- const zh_CN = {
413
- closeLabel: '关闭弹窗'
414
- };
415
- const MOTION = {
416
- appear: 'ov-modal--enter',
417
- appearActive: 'ov-modal--enter-active',
418
- enter: 'ov-modal--enter',
419
- enterActive: 'ov-modal--enter-active',
420
- exitActive: 'ov-modal--exit'
421
- };
422
- function Modal({ open, title, triggerRef, id, className, locale: localeProp, onClose, children, closeLabel }) {
423
- const locale = useLocale(localeProp);
424
- const text = resolveLocale({
425
- 'en-US': en_US,
426
- 'zh-CN': zh_CN
427
- }, locale);
428
- const label = closeLabel ?? text.closeLabel;
429
- const generatedId = useId();
430
- const panelRef = useRef(null);
431
- const maskRef = useRef(null);
432
- const [present, setPresent] = useState(open);
433
- const [layer, setLayer] = useState(null);
434
- usePortalTheme(Boolean(layer), triggerRef, layer);
435
- useEffect(()=>{
436
- if (layer) return lockBodyScroll(layer.ownerDocument.body);
437
- }, [
438
- layer
439
- ]);
440
- if ("u" < typeof document || !open && !present) return null;
441
- return /*#__PURE__*/ createPortal(/*#__PURE__*/ jsxs("div", {
442
- ref: setLayer,
443
- role: "presentation",
444
- lang: locale,
445
- className: [
446
- 'ov-modal',
447
- className
448
- ].filter(Boolean).join(' '),
449
- onKeyDown: (event)=>{
450
- if ('Escape' !== event.key || event.defaultPrevented) return;
451
- if (!(event.target instanceof Node) || !event.currentTarget.contains(event.target)) return;
452
- event.preventDefault();
453
- event.stopPropagation();
454
- onClose?.();
455
- },
456
- children: [
457
- /*#__PURE__*/ jsx(CSSTransition, {
458
- nodeRef: maskRef,
459
- in: open,
460
- timeout: 300,
461
- classNames: MOTION,
462
- appear: true,
463
- mountOnEnter: true,
464
- unmountOnExit: true,
465
- children: /*#__PURE__*/ jsx("button", {
466
- ref: maskRef,
467
- type: "button",
468
- className: "ov-modal__mask",
469
- "aria-label": label,
470
- "aria-hidden": "true",
471
- tabIndex: -1,
472
- onClick: onClose
473
- })
474
- }),
475
- /*#__PURE__*/ jsx(CSSTransition, {
476
- nodeRef: panelRef,
477
- in: open,
478
- timeout: 300,
479
- classNames: MOTION,
480
- appear: true,
481
- mountOnEnter: true,
482
- unmountOnExit: true,
483
- onEnter: ()=>setPresent(true),
484
- onExited: ()=>setPresent(false),
485
- children: /*#__PURE__*/ jsx("div", {
486
- ref: panelRef,
487
- id: id ?? generatedId,
488
- role: "dialog",
489
- "aria-modal": "true",
490
- "aria-label": title,
491
- className: "ov-modal__panel",
492
- children: /*#__PURE__*/ jsxs(es2015, {
493
- className: "ov-modal__focus-lock",
494
- returnFocus: {
495
- preventScroll: true
496
- },
497
- crossFrame: false,
498
- children: [
499
- /*#__PURE__*/ jsx("button", {
500
- type: "button",
501
- className: "ov-modal__close",
502
- "aria-label": label,
503
- disabled: !onClose,
504
- onClick: onClose,
505
- children: /*#__PURE__*/ jsx(removereact, {
506
- width: 16,
507
- height: 16,
508
- "aria-hidden": "true"
509
- })
510
- }),
511
- /*#__PURE__*/ jsx("div", {
512
- className: "ov-modal__body",
513
- children: children
514
- })
515
- ]
516
- })
517
- })
518
- })
519
- ]
520
- }), document.body);
521
- }
522
- function mergeFindResult(result) {
523
- const seen = new Set();
524
- const entries = [];
525
- for (const group of [
526
- result?.memories,
527
- result?.resources,
528
- result?.skills
529
- ])for (const item of group ?? []){
530
- const uri = item?.uri;
531
- if (!(!uri || seen.has(uri))) {
532
- seen.add(uri);
533
- entries.push({
534
- uri,
535
- isDir: false,
536
- abstract: item.abstract?.trim() || void 0
537
- });
538
- }
539
- }
540
- return entries;
541
- }
542
- const emptyDir = ()=>({
543
- entries: [],
544
- hasMore: false,
545
- loading: false,
546
- error: null
547
- });
548
- function mergePage(current, page, offset) {
549
- const previous = current ?? emptyDir();
550
- return {
551
- entries: 0 === offset ? page.entries : [
552
- ...previous.entries,
553
- ...page.entries
554
- ],
555
- hasMore: page.hasMore,
556
- loading: false,
557
- error: null
558
- };
559
- }
560
- function nameFromUri(uri) {
561
- const trimmed = uri.replace(/\/+$/, '');
562
- const index = trimmed.lastIndexOf('/');
563
- const name = index < 0 ? trimmed : trimmed.slice(index + 1);
564
- return name || trimmed;
565
- }
566
- function toEntryRow(entry, depth, expanded, index, busy) {
567
- const isDir = true === entry.isDir;
568
- return {
569
- tags: entry.tags,
570
- kind: 'entry',
571
- id: void 0 === index ? entry.uri : `${entry.uri}#${index}`,
572
- depth,
573
- uri: entry.uri,
574
- name: nameFromUri(entry.uri),
575
- type: isDir ? 'directory' : 'file',
576
- expanded: isDir ? expanded : void 0,
577
- disabled: 'denied' === entry.access || void 0,
578
- selectable: 'container' === entry.access ? false : void 0,
579
- access: entry.access ?? ('read' === entry.permission ? 'read-only' : void 0),
580
- busy: busy || void 0
581
- };
582
- }
583
- function toFileTab(entry, content, maxLines, icon, openParent, truncated = content.split('\n').length >= maxLines) {
584
- const name = nameFromUri(entry.uri);
585
- return {
586
- kind: 'file',
587
- key: entry.uri,
588
- title: name,
589
- icon,
590
- operations: {
591
- openParent
592
- },
593
- source: {
594
- content,
595
- fileName: name,
596
- path: entry.uri,
597
- truncated
598
- }
599
- };
600
- }
601
- function toDirectoryTab(uri, summary, labels, openParent, icon) {
602
- const name = nameFromUri(uri);
603
- const levelBody = (body, failure)=>void 0 === failure ? body : `> ${failure || labels.failure}`;
604
- return {
605
- kind: 'directory',
606
- key: uri,
607
- title: name,
608
- icon,
609
- levels: [
610
- {
611
- key: 'l0',
612
- label: labels.l0,
613
- source: {
614
- content: levelBody(summary.abstract, summary.abstractError),
615
- fileName: `${name}.md`,
616
- path: uri,
617
- fileType: 'markdown'
618
- }
619
- },
620
- {
621
- key: 'l1',
622
- label: labels.l1,
623
- source: {
624
- content: levelBody(summary.overview, summary.overviewError),
625
- fileName: `${name}.md`,
626
- path: uri,
627
- fileType: 'markdown'
628
- }
629
- }
630
- ],
631
- operations: {
632
- openParent
633
- }
634
- };
635
- }
636
- function flattenTree(uri, depth, dirs, expanded) {
637
- const dir = dirs[uri];
638
- if (!dir) return [];
639
- const rows = [];
640
- for (const entry of dir.entries){
641
- const isOpen = expanded.has(entry.uri);
642
- const loadingChildren = isOpen && dirs[entry.uri]?.loading === true;
643
- rows.push(toEntryRow(entry, depth, isOpen, void 0, loadingChildren));
644
- if (isOpen) {
645
- const children = flattenTree(entry.uri, depth + 1, dirs, expanded);
646
- if (children.length > 0) rows.push(...children);
647
- else if (loadingChildren) rows.push({
648
- kind: 'loading',
649
- id: `${entry.uri}::loading`,
650
- depth: depth + 1,
651
- parentId: entry.uri
652
- });
653
- else rows.push({
654
- kind: 'empty',
655
- id: `${entry.uri}::empty`,
656
- depth: depth + 1,
657
- parentId: entry.uri
658
- });
659
- }
660
- }
661
- if (dir.error) rows.push({
662
- kind: 'error',
663
- id: `${uri}::error`,
664
- depth,
665
- parentId: uri
666
- });
667
- else if (dir.hasMore) rows.push({
668
- kind: 'load-more',
669
- id: `${uri}::more`,
670
- depth,
671
- parentId: uri,
672
- loading: dir.loading
673
- });
674
- return rows;
675
- }
676
- function isAbort(error) {
677
- return 'object' == typeof error && null !== error && 'AbortError' === error.name;
678
- }
679
- const toError = (cause)=>cause instanceof Error ? cause : new Error(String(cause));
680
- const LIMIT = 20;
681
- function useFsSearch({ client, query, targetUri, generation = 0, requestOptions }) {
682
- const [results, setResults] = useState(null);
683
- const [loading, setLoading] = useState(false);
684
- const [error, setError] = useState(null);
685
- useEffect(()=>{
686
- if (!client || !query) {
687
- setResults(null);
688
- setLoading(false);
689
- setError(null);
690
- return;
691
- }
692
- const controller = new AbortController();
693
- setLoading(true);
694
- setError(null);
695
- client.request({
696
- method: 'POST',
697
- path: OV_PATHS.searchFind,
698
- body: {
699
- query,
700
- target_uri: targetUri,
701
- limit: LIMIT
702
- },
703
- options: {
704
- ...requestOptions,
705
- signal: controller.signal
706
- }
707
- }).then((result)=>{
708
- if (controller.signal.aborted) return;
709
- setResults(mergeFindResult(result));
710
- setLoading(false);
711
- }, (cause)=>{
712
- if (isAbort(cause) || controller.signal.aborted) return;
713
- setResults([]);
714
- setError(toError(cause));
715
- setLoading(false);
716
- });
717
- return ()=>controller.abort();
718
- }, [
719
- client,
720
- query,
721
- targetUri,
722
- generation,
723
- requestOptions
724
- ]);
725
- return {
726
- results,
727
- loading,
728
- error
729
- };
730
- }
731
- function FileBrowserSearch({ open, rootUri, triggerRef, locale, text, requestOptions, onClose }) {
732
- const client = useOvClient();
733
- const [draft, setDraft] = useState('');
734
- const [request, setRequest] = useState({
735
- query: '',
736
- generation: 0
737
- });
738
- const search = useFsSearch({
739
- client,
740
- query: open ? request.query : '',
741
- targetUri: rootUri,
742
- generation: request.generation,
743
- requestOptions
744
- });
745
- const close = ()=>{
746
- setDraft('');
747
- setRequest({
748
- query: '',
749
- generation: 0
750
- });
751
- onClose();
752
- };
753
- return /*#__PURE__*/ jsxs(Modal, {
754
- open: open,
755
- title: text.searchTitle,
756
- locale: locale,
757
- triggerRef: triggerRef,
758
- className: "ov-file-browser-search",
759
- onClose: close,
760
- children: [
761
- /*#__PURE__*/ jsx("h2", {
762
- className: "ov-file-browser-search__title",
763
- children: text.searchTitle
764
- }),
765
- /*#__PURE__*/ jsx("search", {
766
- children: /*#__PURE__*/ jsxs("form", {
767
- className: "ov-file-browser-search__form",
768
- onSubmit: (event)=>{
769
- event.preventDefault();
770
- const query = draft.trim();
771
- if (!query || !client || search.loading) return;
772
- setRequest((current)=>({
773
- query,
774
- generation: current.generation + 1
775
- }));
776
- },
777
- children: [
778
- /*#__PURE__*/ jsx(input_Input, {
779
- "data-autofocus": true,
780
- required: true,
781
- type: "search",
782
- name: "query",
783
- "aria-label": text.searchTitle,
784
- placeholder: text.searchPlaceholder,
785
- value: draft,
786
- onChange: (event)=>setDraft(event.target.value)
787
- }),
788
- /*#__PURE__*/ jsx(button_Button, {
789
- type: "primary",
790
- htmlType: "submit",
791
- loading: search.loading,
792
- disabled: !client,
793
- children: text.searchAction
794
- })
795
- ]
796
- })
797
- }),
798
- /*#__PURE__*/ jsx("div", {
799
- className: "ov-file-browser-search__results",
800
- "aria-busy": search.loading,
801
- children: search.loading ? /*#__PURE__*/ jsx("p", {
802
- role: "status",
803
- children: text.searchLoading
804
- }) : search.error ? /*#__PURE__*/ jsxs("div", {
805
- role: "alert",
806
- className: "ov-file-browser-search__error",
807
- children: [
808
- /*#__PURE__*/ jsx("p", {
809
- children: text.searchFailed
810
- }),
811
- /*#__PURE__*/ jsx("p", {
812
- children: search.error.message
813
- })
814
- ]
815
- }) : null === search.results ? /*#__PURE__*/ jsx("p", {
816
- role: "status",
817
- children: text.searchHint
818
- }) : 0 === search.results.length ? /*#__PURE__*/ jsx("p", {
819
- role: "status",
820
- children: text.searchEmpty
821
- }) : /*#__PURE__*/ jsx("ul", {
822
- className: "ov-file-browser-search__list",
823
- children: search.results.map((entry)=>/*#__PURE__*/ jsxs("li", {
824
- className: "ov-file-browser-search__result",
825
- children: [
826
- /*#__PURE__*/ jsx("span", {
827
- className: "ov-file-browser-search__uri",
828
- children: entry.uri
829
- }),
830
- entry.abstract ? /*#__PURE__*/ jsx("p", {
831
- className: "ov-file-browser-search__summary",
832
- children: entry.abstract
833
- }) : null
834
- ]
835
- }, entry.uri))
836
- })
837
- })
838
- ]
839
- });
840
- }
841
- const messages = {
842
- formatCharacterCount: (count)=>`${count.toLocaleString('en-US')} ${1 === count ? 'character' : 'characters'}`,
843
- accessDenied: 'You do not have permission to view this node.',
844
- traverseOnly: 'This directory can only be expanded to reach accessible children.',
845
- empty: 'Select a file to preview',
846
- error: 'Failed to load the directory',
847
- retry: 'Retry',
848
- refresh: 'Refresh',
849
- searchPlaceholder: 'Search files ⌘+K...',
850
- searchTitle: 'Search files',
851
- searchAction: 'Search',
852
- searchHint: 'Enter a query to search.',
853
- searchEmpty: 'No matching resources',
854
- searchFailed: 'Failed to run the search',
855
- loading: 'Loading…',
856
- searchLoading: 'Searching…',
857
- previewMode: 'Preview',
858
- sourceMode: 'Source',
859
- copyPath: 'Copy path',
860
- copyContent: 'Copy content',
861
- download: 'Download',
862
- history: 'Version history',
863
- viewSwitch: 'Switch view',
864
- resizeTree: 'Resize the directory tree',
865
- l0Summary: 'L0 Summary',
866
- l1Overview: 'L1 Overview',
867
- summaryEmpty: 'No summary generated yet',
868
- summaryFailed: 'The summary could not be loaded.'
869
- };
870
- const locales_en_US = messages;
871
- const zh_CN_messages = {
872
- formatCharacterCount: (count)=>`${count.toLocaleString('zh-CN')} 个字符`,
873
- accessDenied: '无权查看此节点。',
874
- traverseOnly: '此目录仅可展开以访问有权限的子节点。',
875
- empty: '选择一个文件查看内容',
876
- error: '目录加载失败',
877
- retry: '重试',
878
- refresh: '刷新',
879
- searchPlaceholder: '搜索文件 ⌘+K...',
880
- searchTitle: '搜索文件',
881
- searchAction: '搜索',
882
- searchHint: '输入关键词后搜索。',
883
- searchEmpty: '没有匹配的资源',
884
- searchFailed: '搜索失败',
885
- loading: '加载中…',
886
- searchLoading: '搜索中…',
887
- previewMode: '预览',
888
- sourceMode: '源码',
889
- copyPath: '复制路径',
890
- copyContent: '复制正文',
891
- download: '下载',
892
- history: '版本历史',
893
- viewSwitch: '切换视图',
894
- resizeTree: '调整目录树宽度',
895
- l0Summary: 'L0 摘要',
896
- l1Overview: 'L1 总览',
897
- summaryEmpty: '暂无生成内容',
898
- summaryFailed: '摘要加载失败。'
899
- };
900
- const locales_zh_CN = zh_CN_messages;
901
- const LOCALES = {
902
- 'en-US': locales_en_US,
903
- 'zh-CN': locales_zh_CN
904
- };
905
- function resolveLabels(labels, locale) {
906
- return {
907
- ...resolveLocale(LOCALES, locale, labels),
908
- tree: labels?.tree,
909
- previewLabels: labels?.preview
910
- };
911
- }
912
- function resolvePreviewLabels(text) {
913
- return {
914
- loading: text.loading,
915
- copyPath: text.copyPath,
916
- download: text.download,
917
- ...text.previewLabels
918
- };
919
- }
920
- function resolveSummaryLabels(locale, labels) {
921
- const text = resolveLabels(labels, locale);
922
- return {
923
- l0: text.l0Summary,
924
- l1: text.l1Overview,
925
- failure: text.summaryFailed
926
- };
927
- }
928
- function useContainerWidth() {
929
- const ref = useRef(null);
930
- const [width, setWidth] = useState(0);
931
- useEffect(()=>{
932
- const element = ref.current;
933
- if (!element) return;
934
- const update = (next)=>setWidth((current)=>current === next ? current : next);
935
- update(Math.round(element.getBoundingClientRect().width));
936
- const observer = new ResizeObserver(([entry])=>{
937
- if (entry) update(Math.round(entry.contentRect.width));
938
- });
939
- observer.observe(element);
940
- return ()=>observer.disconnect();
941
- }, []);
942
- return {
943
- ref,
944
- width
945
- };
946
- }
947
- async function readDirectory(client, uri, options) {
948
- const read = (path)=>client.request({
949
- method: 'GET',
950
- path,
951
- query: {
952
- uri
953
- },
954
- options
955
- }).then((value)=>({
956
- ok: true,
957
- text: 'string' == typeof value ? value : ''
958
- })).catch((cause)=>({
959
- ok: false,
960
- cause
961
- }));
962
- const [abstractResult, overviewResult] = await Promise.all([
963
- read(OV_PATHS.contentAbstract),
964
- read(OV_PATHS.contentOverview)
965
- ]);
966
- const aborted = [
967
- abstractResult,
968
- overviewResult
969
- ].find((result)=>!result.ok && isAbort(result.cause));
970
- if (aborted && !aborted.ok) throw aborted.cause;
971
- if (!abstractResult.ok && !overviewResult.ok) throw abstractResult.cause;
972
- const reason = (result)=>result.ok ? void 0 : result.cause instanceof Error ? result.cause.message : String(result.cause);
973
- return {
974
- abstract: abstractResult.ok ? abstractResult.text : '',
975
- overview: overviewResult.ok ? overviewResult.text : '',
976
- abstractError: reason(abstractResult),
977
- overviewError: reason(overviewResult)
978
- };
979
- }
980
- const BINARY_EXTENSIONS = new Set([
981
- 'png',
982
- 'jpg',
983
- 'jpeg',
984
- 'gif',
985
- 'webp',
986
- 'avif',
987
- 'bmp',
988
- 'ico',
989
- 'svg',
990
- 'pdf',
991
- 'doc',
992
- 'docx',
993
- 'ppt',
994
- 'pptx',
995
- 'xls',
996
- 'xlsx',
997
- 'mp4',
998
- 'webm',
999
- 'mov',
1000
- 'mp3',
1001
- 'wav',
1002
- 'ogg',
1003
- 'm4a',
1004
- 'zip',
1005
- 'gz',
1006
- 'tar',
1007
- 'ovpack'
1008
- ]);
1009
- function isBinaryFile(name) {
1010
- const dot = name.lastIndexOf('.');
1011
- if (dot < 0 || dot === name.length - 1) return false;
1012
- return BINARY_EXTENSIONS.has(name.slice(dot + 1).toLowerCase());
1013
- }
1014
- const MIME_BY_EXTENSION = {
1015
- png: 'image/png',
1016
- jpg: 'image/jpeg',
1017
- jpeg: 'image/jpeg',
1018
- gif: 'image/gif',
1019
- webp: 'image/webp',
1020
- avif: 'image/avif',
1021
- bmp: 'image/bmp',
1022
- ico: 'image/x-icon',
1023
- svg: 'image/svg+xml',
1024
- pdf: 'application/pdf',
1025
- doc: 'application/msword',
1026
- docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
1027
- ppt: 'application/vnd.ms-powerpoint',
1028
- pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
1029
- xls: 'application/vnd.ms-excel',
1030
- xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
1031
- mp4: 'video/mp4',
1032
- webm: 'video/webm',
1033
- mov: 'video/quicktime',
1034
- mp3: 'audio/mpeg',
1035
- wav: 'audio/wav',
1036
- ogg: 'audio/ogg',
1037
- m4a: 'audio/mp4',
1038
- zip: 'application/zip',
1039
- gz: 'application/gzip',
1040
- tar: 'application/x-tar'
1041
- };
1042
- function mimeTypeOf(name) {
1043
- const dot = name.lastIndexOf('.');
1044
- if (dot < 0) return 'application/octet-stream';
1045
- return MIME_BY_EXTENSION[name.slice(dot + 1).toLowerCase()] ?? 'application/octet-stream';
1046
- }
1047
- function toBinaryTab(uri, name, file, icon, openParent) {
1048
- return {
1049
- kind: 'file',
1050
- key: uri,
1051
- title: name,
1052
- icon,
1053
- operations: {
1054
- openParent
1055
- },
1056
- source: {
1057
- file,
1058
- fileName: name,
1059
- path: uri
1060
- }
1061
- };
1062
- }
1063
- const LINE_BREAK_CODES = new Set([
1064
- 0x0a,
1065
- 0x0b,
1066
- 0x0c,
1067
- 0x0d,
1068
- 0x1c,
1069
- 0x1d,
1070
- 0x1e,
1071
- 0x85,
1072
- 0x2028,
1073
- 0x2029
1074
- ]);
1075
- function splitLines(text) {
1076
- if (!text) return [];
1077
- const lines = [];
1078
- let start = 0;
1079
- for(let index = 0; index < text.length; index++){
1080
- if (!LINE_BREAK_CODES.has(text.charCodeAt(index))) continue;
1081
- const paired = 0x0d === text.charCodeAt(index) && 0x0a === text.charCodeAt(index + 1);
1082
- const end = index + (paired ? 2 : 1);
1083
- lines.push(text.slice(start, end));
1084
- start = end;
1085
- index = end - 1;
1086
- }
1087
- if (start < text.length) lines.push(text.slice(start));
1088
- return lines;
1089
- }
1090
- function joinLines(lines) {
1091
- return lines.join('');
1092
- }
1093
- const PY_WHITESPACE_CODES = [
1094
- 0x09,
1095
- 0x0a,
1096
- 0x0b,
1097
- 0x0c,
1098
- 0x0d,
1099
- 0x1c,
1100
- 0x1d,
1101
- 0x1e,
1102
- 0x1f,
1103
- 0x20,
1104
- 0x85,
1105
- 0xa0,
1106
- 0x1680,
1107
- 0x2000,
1108
- 0x2001,
1109
- 0x2002,
1110
- 0x2003,
1111
- 0x2004,
1112
- 0x2005,
1113
- 0x2006,
1114
- 0x2007,
1115
- 0x2008,
1116
- 0x2009,
1117
- 0x200a,
1118
- 0x2028,
1119
- 0x2029,
1120
- 0x202f,
1121
- 0x205f,
1122
- 0x3000
1123
- ];
1124
- const PY_WHITESPACE = String.fromCharCode(...PY_WHITESPACE_CODES);
1125
- const PY_WORD = '\\p{L}\\p{N}_';
1126
- const MEMORY_FIELDS_COMMENT = new RegExp(`<!--[${PY_WHITESPACE}]*MEMORY_FIELDS(?![${PY_WORD}])[\\s\\S]*?[${PY_WHITESPACE}]*-->`, 'gu');
1127
- function isPythonBlank(text) {
1128
- for (const char of text)if (!PY_WHITESPACE.includes(char)) return false;
1129
- return true;
1130
- }
1131
- function trimPythonEnd(text) {
1132
- let end = text.length;
1133
- while(end > 0 && PY_WHITESPACE.includes(text[end - 1] ?? ''))end--;
1134
- return text.slice(0, end);
1135
- }
1136
- function uriParts(uri) {
1137
- const [beforeQuery = ''] = uri.split('?');
1138
- const path = beforeQuery.replace(/\/+$/, '');
1139
- if (!path.startsWith('viking://')) return [];
1140
- return path.slice(9).split('/').filter(Boolean);
1141
- }
1142
- function isMemoryUri(uri) {
1143
- const parts = uriParts(uri);
1144
- if (parts.length < 3) return false;
1145
- if ('user' !== parts[0] && '~' !== parts[0]) return false;
1146
- const scoped = '~' === parts[0] ? [
1147
- 'user',
1148
- '~',
1149
- ...parts.slice(1)
1150
- ] : parts;
1151
- if ('memories' === scoped[2]) return true;
1152
- return scoped.length >= 5 && 'peers' === scoped[2] && 'memories' === scoped[4];
1153
- }
1154
- function stripMemoryFieldsTrailer(text) {
1155
- let visible = text;
1156
- for(;;){
1157
- let start = -1;
1158
- MEMORY_FIELDS_COMMENT.lastIndex = 0;
1159
- let match;
1160
- while(null !== (match = MEMORY_FIELDS_COMMENT.exec(visible))){
1161
- const after = visible.slice(match.index + match[0].length);
1162
- if (isPythonBlank(after)) start = match.index;
1163
- }
1164
- if (start < 0) return visible;
1165
- visible = trimPythonEnd(visible.slice(0, start));
1166
- }
1167
- }
1168
- const MAX_LINES = 2000;
1169
- async function readFile(client, uri, options, openParent) {
1170
- const name = nameFromUri(uri);
1171
- const icon = fileTypeIcon(name);
1172
- if (isBinaryFile(name)) {
1173
- const blob = await client.request({
1174
- method: 'GET',
1175
- path: OV_PATHS.contentDownload,
1176
- query: {
1177
- uri
1178
- },
1179
- responseType: 'blob',
1180
- options
1181
- });
1182
- const typed = new Blob([
1183
- blob
1184
- ], {
1185
- type: mimeTypeOf(name)
1186
- });
1187
- return toBinaryTab(uri, name, typed, icon, openParent);
1188
- }
1189
- const read = (limit)=>client.request({
1190
- method: 'GET',
1191
- path: OV_PATHS.contentRead,
1192
- query: {
1193
- uri,
1194
- limit
1195
- },
1196
- options
1197
- }).then((value)=>'string' == typeof value ? value : '');
1198
- const first = await read(MAX_LINES);
1199
- if (!isMemoryUri(uri)) return toFileTab({
1200
- uri
1201
- }, first, MAX_LINES, icon, openParent, splitLines(first).length >= MAX_LINES);
1202
- const full = splitLines(first).length < MAX_LINES ? first : await read(-1);
1203
- const lines = splitLines(stripMemoryFieldsTrailer(full));
1204
- const truncated = lines.length > MAX_LINES;
1205
- const visible = joinLines(truncated ? lines.slice(0, MAX_LINES) : lines);
1206
- return toFileTab({
1207
- uri
1208
- }, visible, MAX_LINES, icon, openParent, truncated);
1209
- }
1210
- async function resolveIsDirectory(client, uri, options) {
1211
- try {
1212
- const result = await client.request({
1213
- method: 'GET',
1214
- path: OV_PATHS.fsStat,
1215
- query: {
1216
- uri
1217
- },
1218
- options
1219
- });
1220
- return result?.isDir === true || result?.is_dir === true;
1221
- } catch {
1222
- return false;
1223
- }
1224
- }
1225
- function abortError() {
1226
- const error = new Error('Aborted');
1227
- error.name = 'AbortError';
1228
- return error;
1229
- }
1230
- function useFsPreview({ client, uri, resourceType = 'file', labels = resolveSummaryLabels('en-US'), formatCharacterCount = resolveLabels(void 0, 'en-US').formatCharacterCount, openParent, generation = 0, requestOptions }) {
1231
- const [directory, setDirectory] = useState(null);
1232
- const [tabs, setTabs] = useState(null);
1233
- const [activeKey, setActiveKey] = useState(null);
1234
- const [error, setError] = useState(null);
1235
- const [characterCount, setCharacterCount] = useState();
1236
- useEffect(()=>{
1237
- setDirectory(null);
1238
- if (!client || !uri) {
1239
- setTabs(null);
1240
- setActiveKey(null);
1241
- setError(null);
1242
- setCharacterCount(void 0);
1243
- return;
1244
- }
1245
- const controller = new AbortController();
1246
- setTabs([
1247
- loadingTab(uri, 'file' !== resourceType)
1248
- ]);
1249
- setActiveKey(uri);
1250
- setActiveKey(null);
1251
- setError(null);
1252
- setCharacterCount(void 0);
1253
- const options = {
1254
- ...requestOptions,
1255
- signal: controller.signal
1256
- };
1257
- const read = (async ()=>{
1258
- const isDir = 'unknown' === resourceType ? await resolveIsDirectory(client, uri, options) : 'directory' === resourceType;
1259
- if (controller.signal.aborted) throw abortError();
1260
- return isDir ? {
1261
- summary: await readDirectory(client, uri, options)
1262
- } : {
1263
- tab: await readFile(client, uri, options, openParent)
1264
- };
1265
- })();
1266
- read.then((result)=>{
1267
- if (controller.signal.aborted) return;
1268
- if (result.summary) {
1269
- setDirectory({
1270
- uri,
1271
- summary: result.summary
1272
- });
1273
- setActiveKey(uri);
1274
- return;
1275
- }
1276
- const tab = result.tab;
1277
- setTabs([
1278
- tab
1279
- ]);
1280
- setActiveKey(tab.key);
1281
- const body = tab.source.content ?? '';
1282
- setCharacterCount(body.length);
1283
- }, (cause)=>{
1284
- if (isAbort(cause) || controller.signal.aborted) return;
1285
- setTabs([]);
1286
- setError(cause instanceof Error ? cause : new Error(String(cause)));
1287
- });
1288
- return ()=>controller.abort();
1289
- }, [
1290
- client,
1291
- uri,
1292
- resourceType,
1293
- openParent,
1294
- generation,
1295
- requestOptions
1296
- ]);
1297
- const directoryTab = directory?.uri === uri ? toDirectoryTab(directory.uri, directory.summary, labels, openParent, directoryIcon()) : void 0;
1298
- const count = directoryTab ? (directoryTab.levels[0].source.content ?? '').length : characterCount;
1299
- return {
1300
- tabs: directoryTab ? [
1301
- directoryTab
1302
- ] : tabs,
1303
- activeKey,
1304
- error,
1305
- footer: void 0 === count ? void 0 : formatCharacterCount(count),
1306
- setActiveKey
1307
- };
1308
- }
1309
- function loadingTab(uri, isDirectory) {
1310
- if (isDirectory) return {
1311
- kind: 'directory',
1312
- key: uri,
1313
- loading: true,
1314
- levels: [
1315
- {
1316
- key: 'l0',
1317
- label: '',
1318
- source: {
1319
- fileName: `${nameFromUri(uri)}.md`,
1320
- path: uri,
1321
- fileType: 'markdown',
1322
- content: ''
1323
- }
1324
- },
1325
- {
1326
- key: 'l1',
1327
- label: '',
1328
- source: {
1329
- fileName: `${nameFromUri(uri)}.md`,
1330
- path: uri,
1331
- fileType: 'markdown',
1332
- content: ''
1333
- }
1334
- }
1335
- ]
1336
- };
1337
- return {
1338
- kind: 'file',
1339
- key: uri,
1340
- loading: true,
1341
- source: {
1342
- fileName: nameFromUri(uri),
1343
- path: uri,
1344
- content: ''
1345
- }
1346
- };
1347
- }
1348
- const isHomeUri = (uri)=>'viking://~' === uri || uri.startsWith('viking://~/');
1349
- async function readDashboardStat(client, uri, options) {
1350
- const stat = await client.request({
1351
- method: 'GET',
1352
- path: OV_PATHS.fsStat,
1353
- query: {
1354
- uri
1355
- },
1356
- options
1357
- });
1358
- const canonical = stat?.uri ?? uri;
1359
- if ('boolean' != typeof stat?.isDir || 'string' != typeof canonical || !canonical || isHomeUri(canonical)) throw new TypeError('Invalid canonical resource stat');
1360
- return {
1361
- uri: canonical,
1362
- isDir: stat.isDir
1363
- };
1364
- }
1365
- async function resolveDashboardUri(client, uri, options) {
1366
- return isHomeUri(uri) ? (await readDashboardStat(client, uri, options)).uri : uri;
1367
- }
1368
- async function readDashboardHint(client, uri, options) {
1369
- const result = await client.request({
1370
- method: 'GET',
1371
- path: OV_PATHS.fsAttrs,
1372
- query: {
1373
- uri
1374
- },
1375
- options
1376
- });
1377
- return {
1378
- uri: await resolveDashboardUri(client, result?.uri ?? uri, options),
1379
- tags: result?.attrs?.tags ?? []
1380
- };
1381
- }
1382
- const EXPERIENCE_PAGE_SIZE = 20;
1383
- const isExperienceDirectory = (uri)=>/^viking:\/\/(?:user\/[^/]+|~)\/memories\/experiences\/?$/.test(uri);
1384
- const isExperienceFile = (uri)=>/^viking:\/\/(?:user\/[^/]+|~)\/memories\/experiences\/[^/]+\.md$/i.test(uri);
1385
- function experienceDateRange(days, now = new Date()) {
1386
- if (!days) return {};
1387
- const start = new Date(now);
1388
- start.setUTCDate(start.getUTCDate() - days + 1);
1389
- return {
1390
- start_date: start.toISOString().slice(0, 10),
1391
- end_date: now.toISOString().slice(0, 10)
1392
- };
1393
- }
1394
- async function readExperiences(client, uri, page, options) {
1395
- uri = await resolveDashboardUri(client, uri, options);
1396
- const result = await client.requestEnvelope({
1397
- method: 'GET',
1398
- path: OV_PATHS.fsLs,
1399
- query: {
1400
- uri,
1401
- output: 'original',
1402
- limit: EXPERIENCE_PAGE_SIZE,
1403
- offset: page * EXPERIENCE_PAGE_SIZE,
1404
- sort_by: 'mtime',
1405
- sort_order: 'desc'
1406
- },
1407
- options
1408
- });
1409
- if (!Array.isArray(result.result)) throw new TypeError('Invalid Experience listing');
1410
- const prefix = `${uri.replace(/\/+$/, '')}/`;
1411
- return {
1412
- items: result.result.filter((item)=>!item.isDir && item.uri.startsWith(prefix) && isExperienceFile(item.uri)),
1413
- hasMore: result.hasMore
1414
- };
1415
- }
1416
- async function readExperienceSources(client, uri, options) {
1417
- uri = await resolveDashboardUri(client, uri, options);
1418
- const result = await client.request({
1419
- method: 'GET',
1420
- path: OV_PATHS.fsAttrs,
1421
- query: {
1422
- uri
1423
- },
1424
- options
1425
- });
1426
- const links = result?.attrs?.memory?.links;
1427
- if (void 0 !== links && !Array.isArray(links)) throw new TypeError('Invalid Experience links');
1428
- const prefix = uri.slice(0, uri.indexOf('/memories/experiences/')) + '/memories/trajectories/';
1429
- const seen = new Set();
1430
- return (links ?? []).flatMap((link)=>{
1431
- if ('derived_from' !== link.link_type || 'string' != typeof link.to_uri || !link.to_uri.startsWith(prefix) || seen.has(link.to_uri)) return [];
1432
- seen.add(link.to_uri);
1433
- return [
1434
- {
1435
- uri: link.to_uri,
1436
- name: link.to_uri.split('/').pop() ?? link.to_uri,
1437
- description: link.description ?? link.match_text
1438
- }
1439
- ];
1440
- });
1441
- }
1442
- const dashboardKey = (uri)=>`dashboard:${uri}`;
1443
- const within = (uri, root)=>uri === root || uri.startsWith(`${root.replace(/\/+$/, '')}/`);
1444
- function resolveDashboard(uri, rows, targets) {
1445
- if (isExperienceDirectory(uri) || isExperienceFile(uri)) return {
1446
- kind: 'experience',
1447
- uri
1448
- };
1449
- const entries = rows.filter((row)=>'entry' === row.kind);
1450
- const row = entries.find((item)=>item.uri === uri);
1451
- const hasWiki = entries.some((item)=>item.tags?.includes('compile_target=true') && within(uri, item.uri));
1452
- const owner = targets.filter((item)=>within(uri, item.to)).sort((a, b)=>b.to.length - a.to.length)[0];
1453
- if (!hasWiki && !owner) return;
1454
- const tagged = row?.tags?.find((tag)=>tag.startsWith('has_conflict='));
1455
- return {
1456
- kind: 'wiki',
1457
- uri,
1458
- isRoot: Boolean(row?.tags?.includes('compile_target=true') || owner?.to === uri),
1459
- pendingConflicts: tagged ? 'has_conflict=true' === tagged : owner?.to === uri && void 0 !== owner.conflicts_num ? owner.conflicts_num > 0 : void 0
1460
- };
1461
- }
1462
- function mergeDashboardTab(tabs, dashboard, blocked) {
1463
- return blocked ? null : dashboard ? [
1464
- ...tabs ?? [],
1465
- dashboard
1466
- ] : tabs;
1467
- }
1468
- async function readCompileTargets(client, rootUri, options) {
1469
- rootUri = await resolveDashboardUri(client, rootUri, options);
1470
- const targets = [];
1471
- let cursor;
1472
- const seen = new Set();
1473
- do {
1474
- const result = await client.request({
1475
- method: 'GET',
1476
- path: OV_PATHS.compileConfigs,
1477
- query: {
1478
- limit: 100,
1479
- cursor
1480
- },
1481
- options
1482
- });
1483
- if (!Array.isArray(result?.targets)) throw new TypeError('Invalid Compile target registry');
1484
- 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))));
1485
- cursor = result.next_cursor ?? void 0;
1486
- if (cursor && seen.has(cursor)) throw new TypeError('Compile target cursor did not advance');
1487
- if (cursor) seen.add(cursor);
1488
- }while (cursor)
1489
- return targets;
1490
- }
1491
- function useDashboardQuery(load, requestOptions, enabled = true, refreshGeneration = 0) {
1492
- const client = useOvClient();
1493
- const inheritedSignal = useOvSignal();
1494
- const { baseURL, apiKey, accountId, userId, resourceId, signal } = requestOptions ?? {};
1495
- const [generation, setGeneration] = useState(0);
1496
- const [state, setState] = useState({
1497
- owner: [],
1498
- error: null
1499
- });
1500
- const owner = useMemo(()=>[
1501
- client,
1502
- load,
1503
- baseURL,
1504
- apiKey,
1505
- accountId,
1506
- userId,
1507
- resourceId,
1508
- signal,
1509
- inheritedSignal,
1510
- generation,
1511
- enabled,
1512
- refreshGeneration
1513
- ], [
1514
- client,
1515
- load,
1516
- baseURL,
1517
- apiKey,
1518
- accountId,
1519
- userId,
1520
- resourceId,
1521
- signal,
1522
- inheritedSignal,
1523
- generation,
1524
- enabled,
1525
- refreshGeneration
1526
- ]);
1527
- const current = owner.every((value, i)=>value === state.owner[i]);
1528
- useEffect(()=>{
1529
- if (!enabled) return;
1530
- if (!client) return void setState({
1531
- owner,
1532
- error: new Error('OpenVikingProvider is required')
1533
- });
1534
- const controller = new AbortController();
1535
- const signals = [
1536
- controller.signal,
1537
- signal,
1538
- inheritedSignal
1539
- ].filter((value)=>Boolean(value));
1540
- const options = {
1541
- baseURL,
1542
- apiKey,
1543
- accountId,
1544
- userId,
1545
- resourceId,
1546
- signal: AbortSignal.any(signals)
1547
- };
1548
- load(client, options).then((data)=>{
1549
- if (!options.signal.aborted) setState({
1550
- owner,
1551
- data,
1552
- error: null
1553
- });
1554
- }, (cause)=>{
1555
- if (!options.signal.aborted) setState({
1556
- owner,
1557
- error: cause instanceof Error ? cause : new Error(String(cause))
1558
- });
1559
- });
1560
- return ()=>controller.abort();
1561
- }, [
1562
- client,
1563
- load,
1564
- baseURL,
1565
- apiKey,
1566
- accountId,
1567
- userId,
1568
- resourceId,
1569
- signal,
1570
- inheritedSignal,
1571
- generation,
1572
- enabled,
1573
- owner
1574
- ]);
1575
- return {
1576
- data: current ? state.data : void 0,
1577
- loading: enabled && !current,
1578
- error: current ? state.error : null,
1579
- retry: ()=>setGeneration((value)=>value + 1)
1580
- };
1581
- }
1582
- function useExperienceDashboard({ uri, requestOptions, enabled = true, refreshGeneration = 0 }) {
1583
- const client = useOvClient();
1584
- const signal = useOvSignal();
1585
- const owner = useMemo(()=>[
1586
- uri,
1587
- client,
1588
- signal,
1589
- requestOptions?.baseURL,
1590
- requestOptions?.apiKey,
1591
- requestOptions?.accountId,
1592
- requestOptions?.userId,
1593
- requestOptions?.resourceId
1594
- ], [
1595
- uri,
1596
- client,
1597
- signal,
1598
- requestOptions?.baseURL,
1599
- requestOptions?.apiKey,
1600
- requestOptions?.accountId,
1601
- requestOptions?.userId,
1602
- requestOptions?.resourceId
1603
- ]);
1604
- const [state, setState] = useState({
1605
- owner,
1606
- page: 0,
1607
- days: 7,
1608
- tab: 'impact'
1609
- });
1610
- const current = state.owner === owner ? state : {
1611
- owner,
1612
- page: 0,
1613
- days: 7,
1614
- tab: 'impact'
1615
- };
1616
- const { page, days, tab } = current;
1617
- const setPage = (value)=>setState({
1618
- ...current,
1619
- page: Math.max(0, value)
1620
- });
1621
- const setDays = (value)=>setState({
1622
- ...current,
1623
- days: value,
1624
- page: 0
1625
- });
1626
- const setTab = (value)=>setState({
1627
- ...current,
1628
- tab: value,
1629
- page: 0
1630
- });
1631
- const directory = isExperienceDirectory(uri);
1632
- const loadList = useCallback((client, options)=>readExperiences(client, uri, page, options), [
1633
- uri,
1634
- page
1635
- ]);
1636
- const loadSources = useCallback((client, options)=>readExperienceSources(client, uri, options), [
1637
- uri
1638
- ]);
1639
- const loadTrajectories = useCallback(async (client, options)=>{
1640
- const result = await client.request({
1641
- method: 'GET',
1642
- path: OV_PATHS.experienceTrajectories,
1643
- query: {
1644
- experience_uri: uri,
1645
- offset: 20 * page,
1646
- limit: 20,
1647
- ...experienceDateRange(days)
1648
- },
1649
- options
1650
- });
1651
- 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');
1652
- return result;
1653
- }, [
1654
- uri,
1655
- page,
1656
- days
1657
- ]);
1658
- const loadOutcomes = useCallback(async (client, options)=>{
1659
- const result = await client.request({
1660
- method: 'GET',
1661
- path: OV_PATHS.experienceOutcomes,
1662
- query: {
1663
- experience_uri: uri,
1664
- ...experienceDateRange(days)
1665
- },
1666
- options
1667
- });
1668
- if (!Array.isArray(result?.outcome_distribution) || result.outcome_distribution.some((entry)=>![
1669
- 'success',
1670
- 'partial',
1671
- 'unfinished',
1672
- 'failure',
1673
- 'unknown'
1674
- ].includes(entry?.outcome) || !Number.isSafeInteger(entry.count) || entry.count < 0)) throw new TypeError('Invalid Experience outcomes');
1675
- return result.outcome_distribution;
1676
- }, [
1677
- uri,
1678
- days
1679
- ]);
1680
- const list = useDashboardQuery(loadList, requestOptions, enabled && directory, refreshGeneration);
1681
- const sources = useDashboardQuery(loadSources, requestOptions, enabled && !directory && 'source' === tab, refreshGeneration);
1682
- const trajectories = useDashboardQuery(loadTrajectories, requestOptions, enabled && !directory && 'impact' === tab, refreshGeneration);
1683
- const outcomes = useDashboardQuery(loadOutcomes, requestOptions, enabled && !directory && 'impact' === tab, refreshGeneration);
1684
- return {
1685
- list,
1686
- sources,
1687
- trajectories,
1688
- outcomes,
1689
- page,
1690
- setPage,
1691
- days,
1692
- setDays,
1693
- tab,
1694
- setTab
1695
- };
1696
- }
1697
- function ExperienceDashboardPane({ uri, locale, requestOptions, refreshGeneration, onOpenUri }) {
1698
- const browser = useExperienceDashboard({
1699
- uri,
1700
- requestOptions,
1701
- refreshGeneration
1702
- });
1703
- const directory = isExperienceDirectory(uri);
1704
- const status = (query)=>({
1705
- loading: query.loading,
1706
- error: query.error,
1707
- onRetry: query.retry
1708
- });
1709
- return /*#__PURE__*/ jsx(ExperienceDashboard, {
1710
- uri: uri,
1711
- kind: directory ? 'directory' : 'file',
1712
- locale: locale,
1713
- onOpenUri: onOpenUri,
1714
- data: {
1715
- experiences: browser.list.data?.items,
1716
- outcomes: browser.outcomes.data,
1717
- trajectories: browser.trajectories.data?.items,
1718
- trajectoryTotal: browser.trajectories.data?.total,
1719
- sources: browser.sources.data
1720
- },
1721
- tab: browser.tab,
1722
- days: browser.days,
1723
- page: browser.page,
1724
- startIndex: 20 * browser.page,
1725
- hasMore: Boolean(directory ? browser.list.data?.hasMore : 'impact' === browser.tab && browser.trajectories.data?.has_more),
1726
- states: {
1727
- list: status(browser.list),
1728
- sources: status(browser.sources),
1729
- outcomes: status(browser.outcomes),
1730
- trajectories: status(browser.trajectories)
1731
- },
1732
- onTabChange: browser.setTab,
1733
- onDaysChange: browser.setDays,
1734
- onPageChange: browser.setPage
1735
- });
1736
- }
1737
- const wiki_conflicts_prefix = '<!-- CONFLICTS_CONTENT';
1738
- const manualResolutionBasis = '\u4eba\u5de5\u4fee\u590d';
1739
- const timestamp = (value)=>'number' == typeof value && Number.isSafeInteger(value) && value >= 0 && Number.isFinite(new Date(1000 * value).getTime());
1740
- const locateWikiConflict = (document1, matchText)=>{
1741
- const mask = (value)=>value.replace(/[^\r\n]/g, ' ');
1742
- const body = document1.replace(/^(?:\uFEFF)?---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/, mask).replace(/<!--[\s\S]*?(?:-->|$)/g, mask);
1743
- const start = matchText ? body.indexOf(matchText) : -1;
1744
- if (start < 0) return {
1745
- status: 'missing'
1746
- };
1747
- if (body.indexOf(matchText, start + 1) >= 0) return {
1748
- status: 'ambiguous'
1749
- };
1750
- return {
1751
- status: 'unique',
1752
- start,
1753
- end: start + matchText.length,
1754
- line: document1.slice(0, start).split('\n').length
1755
- };
1756
- };
1757
- const parseWikiFileConflicts = (content)=>{
1758
- const start = content.lastIndexOf(wiki_conflicts_prefix);
1759
- if (start < 0) return {
1760
- status: 'missing'
1761
- };
1762
- const footer = content.slice(start).trimEnd();
1763
- if (!footer.endsWith('-->')) return {
1764
- status: 'invalid'
1765
- };
1766
- const document1 = content.slice(0, start);
1767
- const source = footer.slice(wiki_conflicts_prefix.length, -3).trim();
1768
- let parsed;
1769
- try {
1770
- parsed = source ? JSON.parse(`[${source}]`) : [];
1771
- } catch {
1772
- return {
1773
- status: 'invalid'
1774
- };
1775
- }
1776
- if (!Array.isArray(parsed)) return {
1777
- status: 'invalid'
1778
- };
1779
- const records = [];
1780
- for (const [index, raw] of parsed.entries()){
1781
- if (!raw || 'object' != typeof raw || Array.isArray(raw)) return {
1782
- status: 'invalid'
1783
- };
1784
- const value = raw;
1785
- if ('string' != typeof value.match_text || !value.match_text || 'string' != typeof value.problem_description || 'string' != typeof value.reason || ![
1786
- 'high',
1787
- 'medium',
1788
- 'low'
1789
- ].includes(value.severity) || ![
1790
- 'unfixed',
1791
- 'fixed'
1792
- ].includes(value.state) || !timestamp(value.begin_time) || 'string' != typeof value.fix_plan || 'string' != typeof value.resolution_basis) return {
1793
- status: 'invalid'
1794
- };
1795
- if ('fixed' === value.state ? !timestamp(value.fix_time) || value.fix_time < value.begin_time : null !== value.fix_time) return {
1796
- status: 'invalid'
1797
- };
1798
- const matchText = value.match_text;
1799
- const location = locateWikiConflict(document1, matchText);
1800
- records.push({
1801
- id: JSON.stringify([
1802
- index,
1803
- value.begin_time,
1804
- matchText
1805
- ]),
1806
- matchText,
1807
- description: value.problem_description,
1808
- reason: value.reason,
1809
- severity: value.severity,
1810
- state: value.state,
1811
- beginTime: value.begin_time,
1812
- fixTime: value.fix_time,
1813
- fixPlan: value.fix_plan,
1814
- resolutionBasis: value.resolution_basis,
1815
- resolutionSource: 'fixed' === value.state && value.resolution_basis.trim() ? value.resolution_basis.trim() === manualResolutionBasis ? 'manual' : 'automatic' : void 0,
1816
- location
1817
- });
1818
- }
1819
- return {
1820
- status: 'available',
1821
- document: document1,
1822
- records
1823
- };
1824
- };
1825
- async function readWikiDashboard(client, uri, options) {
1826
- const stat = await readDashboardStat(client, uri, options);
1827
- uri = stat.uri;
1828
- if (!stat.isDir) {
1829
- const result = await client.request({
1830
- method: 'GET',
1831
- path: OV_PATHS.contentRead,
1832
- query: {
1833
- uri,
1834
- limit: -1
1835
- },
1836
- options
1837
- });
1838
- if ('string' != typeof result) throw new TypeError('Invalid Wiki content response');
1839
- const parsed = parseWikiFileConflicts(result);
1840
- if ('invalid' === parsed.status) throw new TypeError('Invalid CONFLICTS_CONTENT metadata');
1841
- return {
1842
- kind: 'file',
1843
- data: {
1844
- path: uri,
1845
- conflicts: 'available' === parsed.status ? parsed.records : []
1846
- }
1847
- };
1848
- }
1849
- const page = await client.requestEnvelope({
1850
- method: 'GET',
1851
- path: OV_PATHS.fsLs,
1852
- query: {
1853
- uri,
1854
- recursive: true,
1855
- output: 'agent',
1856
- tags: [
1857
- 'has_conflict=true'
1858
- ],
1859
- limit: 100,
1860
- sort_by: 'mtime',
1861
- sort_order: 'desc'
1862
- },
1863
- options
1864
- });
1865
- if (!Array.isArray(page.result)) throw new TypeError('Invalid Wiki conflict listing');
1866
- const prefix = `${uri.replace(/\/+$/, '')}/`;
1867
- const files = page.result.filter((entry)=>!entry.isDir && entry.uri.startsWith(prefix)).map((entry)=>entry.uri);
1868
- return {
1869
- kind: 'directory',
1870
- data: {
1871
- files,
1872
- conflictFileCount: files.length,
1873
- limited: page.hasMore || files.length >= 100
1874
- }
1875
- };
1876
- }
1877
- function useWikiDashboard({ uri, requestOptions, enabled = true, refreshGeneration = 0 }) {
1878
- const load = useCallback((client, options)=>readWikiDashboard(client, uri, options), [
1879
- uri
1880
- ]);
1881
- return useDashboardQuery(load, requestOptions, enabled, refreshGeneration);
1882
- }
1883
- function WikiDashboardPane({ uri, kind, requestOptions, refreshGeneration, onOpenUri, onOpenDashboard, onEdit, onDiscuss, ...props }) {
1884
- const query = useWikiDashboard({
1885
- uri,
1886
- requestOptions,
1887
- refreshGeneration
1888
- });
1889
- const common = {
1890
- ...props,
1891
- loading: query.loading,
1892
- error: query.error,
1893
- onRetry: query.retry
1894
- };
1895
- if ((query.data?.kind ?? kind) === 'file') return /*#__PURE__*/ createElement(WikiDashboard, {
1896
- ...common,
1897
- key: uri,
1898
- kind: "file",
1899
- data: query.data?.kind === 'file' ? query.data.data : void 0,
1900
- onOpenUri: onOpenUri && (()=>onOpenUri(uri)),
1901
- onEdit: onEdit && ((conflict)=>onEdit(uri, conflict)),
1902
- onDiscuss: onDiscuss && ((conflict)=>onDiscuss(uri, conflict))
1903
- });
1904
- return /*#__PURE__*/ createElement(WikiDashboard, {
1905
- ...common,
1906
- key: uri,
1907
- kind: "directory",
1908
- data: query.data?.kind === 'directory' ? query.data.data : void 0,
1909
- onOpenUri: onOpenUri,
1910
- onOpenDashboard: onOpenDashboard,
1911
- onEdit: onEdit
1912
- });
1913
- }
1914
- function useBrowserDashboards({ rows, metadataRows, uri, rootUri, generation, locale, requestOptions, onOpenUri, dashboardKinds, renderDashboard, dashboardLabels }) {
1915
- const [opened, setOpened] = useState(null);
1916
- const load = useCallback((client, options)=>readCompileTargets(client, rootUri, options), [
1917
- rootUri
1918
- ]);
1919
- const wikiEnabled = void 0 === dashboardKinds || dashboardKinds.includes('wiki');
1920
- const catalog = useDashboardQuery(load, requestOptions, wikiEnabled, generation);
1921
- const loadHint = useCallback(async (client, options)=>uri ? readDashboardHint(client, uri, options) : void 0, [
1922
- uri
1923
- ]);
1924
- const hint = useDashboardQuery(loadHint, requestOptions, wikiEnabled && Boolean(uri), generation);
1925
- const canonicalUri = hint.data?.uri ?? uri;
1926
- const knownRows = canonicalUri && hint.data?.tags.includes('compile_target=true') ? [
1927
- ...metadataRows,
1928
- {
1929
- kind: 'entry',
1930
- uri: canonicalUri,
1931
- id: canonicalUri,
1932
- name: canonicalUri,
1933
- depth: 0,
1934
- type: 'directory',
1935
- tags: hint.data.tags
1936
- }
1937
- ] : metadataRows;
1938
- const unsupported = isOvClientError(catalog.error) && 404 === catalog.error.statusCode;
1939
- const targets = catalog.data ?? [];
1940
- const resolve = (target)=>{
1941
- const match = resolveDashboard(target === uri ? canonicalUri ?? target : target, knownRows, targets);
1942
- return match ? {
1943
- ...match,
1944
- uri: target
1945
- } : void 0;
1946
- };
1947
- const dashboards = new Map(rows.filter((row)=>'entry' === row.kind).filter((row)=>!row.disabled && false !== row.selectable).flatMap((row)=>{
1948
- const dashboard = resolve(row.uri);
1949
- return dashboard && (void 0 === dashboardKinds || dashboardKinds.includes(dashboard.kind)) ? [
1950
- [
1951
- row.uri,
1952
- dashboard
1953
- ]
1954
- ] : [];
1955
- }));
1956
- const resolved = uri ? resolve(uri) : void 0;
1957
- const current = resolved && (void 0 === dashboardKinds || dashboardKinds.includes(resolved.kind)) ? resolved : void 0;
1958
- const open = useCallback((target)=>{
1959
- setOpened(target);
1960
- onOpenUri(target);
1961
- }, [
1962
- onOpenUri
1963
- ]);
1964
- const close = useCallback(()=>setOpened(null), []);
1965
- const text = dashboard_labels_dashboardLabels(locale, dashboardLabels);
1966
- const title = current?.kind === 'experience' ? text.experienceTitle : text.wikiTitle;
1967
- const tab = current && uri ? {
1968
- key: dashboardKey(uri),
1969
- title,
1970
- icon: createElement('experience' === current.kind ? ExperienceBoardIcon : WikiBoardIcon, {
1971
- width: 14,
1972
- height: 14
1973
- }),
1974
- kind: 'content',
1975
- content: renderDashboard?.(current) ?? ('experience' === current.kind ? createElement(ExperienceDashboardPane, {
1976
- uri,
1977
- locale,
1978
- requestOptions,
1979
- refreshGeneration: generation,
1980
- onOpenUri: (target)=>{
1981
- setOpened(null);
1982
- onOpenUri(target);
1983
- }
1984
- }) : createElement(WikiDashboardPane, {
1985
- uri,
1986
- kind: knownRows.some((row)=>'entry' === row.kind && row.uri === canonicalUri && 'file' === row.type) ? 'file' : 'directory',
1987
- locale,
1988
- requestOptions,
1989
- refreshGeneration: generation,
1990
- onOpenUri: (target)=>{
1991
- setOpened(null);
1992
- onOpenUri(target);
1993
- },
1994
- onOpenDashboard: open
1995
- }))
1996
- } : void 0;
1997
- return {
1998
- dashboards,
1999
- tab,
2000
- isOpen: null !== uri && opened === uri && Boolean(current),
2001
- open,
2002
- close,
2003
- error: unsupported ? null : catalog.error,
2004
- retry: catalog.retry
2005
- };
2006
- }
2007
- function knownDirectories(rootUri, dirs) {
2008
- const known = new Set([
2009
- rootUri
2010
- ]);
2011
- for (const [parent, level] of Object.entries(dirs)){
2012
- known.add(parent);
2013
- for (const entry of level.entries)if (true === entry.isDir) known.add(entry.uri);
2014
- }
2015
- return known;
2016
- }
2017
- function knownFiles(dirs) {
2018
- const known = new Set();
2019
- for (const level of Object.values(dirs))for (const entry of level.entries)if (true !== entry.isDir) known.add(entry.uri);
2020
- return known;
2021
- }
2022
- function useKnownFile(dirs) {
2023
- const files = useMemo(()=>knownFiles(dirs), [
2024
- dirs
2025
- ]);
2026
- return useCallback((uri)=>files.has(uri), [
2027
- files
2028
- ]);
2029
- }
2030
- function useTreeMetadata(rootUri, dirs) {
2031
- const directoryUris = useMemo(()=>knownDirectories(rootUri, dirs), [
2032
- rootUri,
2033
- dirs
2034
- ]);
2035
- const isKnownFile = useKnownFile(dirs);
2036
- const metadataRows = useMemo(()=>Object.values(dirs).flatMap((dir)=>dir.entries.map((entry)=>toEntryRow(entry, 0, false))), [
2037
- dirs
2038
- ]);
2039
- const accessOf = useCallback((uri)=>{
2040
- const row = metadataRows.find((entry)=>entry.uri === uri);
2041
- return row?.access === 'denied' || row?.access === 'container' ? row.access : void 0;
2042
- }, [
2043
- metadataRows
2044
- ]);
2045
- return {
2046
- directoryUris,
2047
- isKnownFile,
2048
- metadataRows,
2049
- accessOf
2050
- };
2051
- }
2052
- const ids = new WeakMap();
2053
- let nextId = 1;
2054
- function idOf(value) {
2055
- if (!value) return 0;
2056
- const existing = ids.get(value);
2057
- if (void 0 !== existing) return existing;
2058
- const assigned = nextId++;
2059
- ids.set(value, assigned);
2060
- return assigned;
2061
- }
2062
- function fieldKey(value) {
2063
- if (void 0 === value) return 'inherit';
2064
- if ('function' == typeof value) return `fn#${idOf(value)}`;
2065
- return `value:${value}`;
2066
- }
2067
- function scopeKeyOf(client, options, rootUri) {
2068
- return JSON.stringify([
2069
- idOf(client),
2070
- void 0 === rootUri ? 'inherit-root' : `root:${rootUri}`,
2071
- options?.baseURL === void 0 ? 'inherit-base' : `base:${options.baseURL}`,
2072
- fieldKey(options?.apiKey),
2073
- fieldKey(options?.accountId),
2074
- fieldKey(options?.userId),
2075
- fieldKey(options?.resourceId)
2076
- ]);
2077
- }
2078
- function useRequestScope(client, requestOptions, rootUri) {
2079
- const scopeKey = scopeKeyOf(client, requestOptions, rootUri);
2080
- const scopeRef = useRef({
2081
- key: scopeKey,
2082
- controller: new AbortController()
2083
- });
2084
- const handleRef = useRef({
2085
- current: ()=>scopeRef.current
2086
- });
2087
- useEffect(()=>{
2088
- const current = scopeRef.current;
2089
- if (current.key === scopeKey) return;
2090
- current.controller.abort();
2091
- scopeRef.current = {
2092
- key: scopeKey,
2093
- controller: new AbortController()
2094
- };
2095
- }, [
2096
- scopeKey
2097
- ]);
2098
- useEffect(()=>()=>{
2099
- scopeRef.current.controller.abort();
2100
- scopeRef.current = {
2101
- key: scopeRef.current.key,
2102
- controller: new AbortController()
2103
- };
2104
- }, []);
2105
- return handleRef.current;
2106
- }
2107
- function expandChain(rootUri, targetUri) {
2108
- if (!targetUri) return [];
2109
- const base = rootUri.endsWith('/') ? rootUri : `${rootUri}/`;
2110
- if (!targetUri.startsWith(base)) return [];
2111
- const rest = targetUri.slice(base.length).split('/').filter(Boolean);
2112
- return rest.map((_, index)=>`${base}${rest.slice(0, index + 1).join('/')}`);
2113
- }
2114
- const PAGE_SIZE = 200;
2115
- async function loadPage(client, uri, offset, signal, requestOptions) {
2116
- const envelope = await client.requestEnvelope({
2117
- method: 'GET',
2118
- path: OV_PATHS.fsLs,
2119
- query: {
2120
- uri,
2121
- output: 'agent',
2122
- include_tags: true,
2123
- node_limit: PAGE_SIZE,
2124
- offset
2125
- },
2126
- options: {
2127
- ...requestOptions,
2128
- signal
2129
- }
2130
- });
2131
- return {
2132
- entries: envelope.result ?? [],
2133
- hasMore: envelope.hasMore
2134
- };
2135
- }
2136
- function useFsTree({ client, rootUri, defaultExpandedUri, requestOptions }) {
2137
- const [dirs, setDirs] = useState({});
2138
- const [expanded, setExpanded] = useState(()=>new Set([
2139
- rootUri
2140
- ]));
2141
- const [isReady, setReady] = useState(false);
2142
- const [error, setError] = useState(null);
2143
- const dirsRef = useRef(dirs);
2144
- dirsRef.current = dirs;
2145
- const expandedRef = useRef(expanded);
2146
- expandedRef.current = expanded;
2147
- useEffect(()=>{
2148
- if (!client) return;
2149
- const controller = new AbortController();
2150
- setReady(false);
2151
- setError(null);
2152
- setExpanded(new Set([
2153
- rootUri
2154
- ]));
2155
- setDirs({
2156
- [rootUri]: {
2157
- ...emptyDir(),
2158
- loading: true
2159
- }
2160
- });
2161
- const run = async ()=>{
2162
- const root = await loadPage(client, rootUri, 0, controller.signal, requestOptions);
2163
- if (controller.signal.aborted) return;
2164
- setDirs({
2165
- [rootUri]: mergePage(void 0, root, 0)
2166
- });
2167
- const chain = expandChain(rootUri, defaultExpandedUri);
2168
- for (const uri of chain){
2169
- let page;
2170
- try {
2171
- page = await loadPage(client, uri, 0, controller.signal, requestOptions);
2172
- } catch (cause) {
2173
- if (isAbort(cause) || controller.signal.aborted) return;
2174
- break;
2175
- }
2176
- if (controller.signal.aborted) return;
2177
- setExpanded((prev)=>new Set(prev).add(uri));
2178
- setDirs((prev)=>({
2179
- ...prev,
2180
- [uri]: mergePage(prev[uri], page, 0)
2181
- }));
2182
- }
2183
- if (controller.signal.aborted) return;
2184
- setReady(true);
2185
- };
2186
- run().catch((cause)=>{
2187
- if (isAbort(cause) || controller.signal.aborted) return;
2188
- const failure = toError(cause);
2189
- setError(failure);
2190
- setDirs({
2191
- [rootUri]: {
2192
- ...emptyDir(),
2193
- loading: false,
2194
- error: failure
2195
- }
2196
- });
2197
- setReady(true);
2198
- });
2199
- return ()=>controller.abort();
2200
- }, [
2201
- client,
2202
- rootUri,
2203
- defaultExpandedUri,
2204
- requestOptions
2205
- ]);
2206
- const scope = useRequestScope(client, requestOptions, rootUri);
2207
- const state = useMemo(()=>{
2208
- const fetchPage = async (uri, offset)=>{
2209
- if (!client) return;
2210
- const current = scope.current();
2211
- const { signal } = current.controller;
2212
- if (signal.aborted) return;
2213
- if (uri === rootUri) setError(null);
2214
- setDirs((prev)=>({
2215
- ...prev,
2216
- [uri]: {
2217
- ...prev[uri] ?? emptyDir(),
2218
- loading: true,
2219
- error: null
2220
- }
2221
- }));
2222
- try {
2223
- const page = await loadPage(client, uri, offset, signal, requestOptions);
2224
- if (signal.aborted || scope.current().key !== current.key) return;
2225
- setDirs((prev)=>({
2226
- ...prev,
2227
- [uri]: mergePage(prev[uri], page, offset)
2228
- }));
2229
- } catch (cause) {
2230
- if (isAbort(cause) || signal.aborted) return;
2231
- const failure = toError(cause);
2232
- if (uri === rootUri) setError(failure);
2233
- setDirs((prev)=>({
2234
- ...prev,
2235
- [uri]: {
2236
- ...prev[uri] ?? emptyDir(),
2237
- loading: false,
2238
- error: failure
2239
- }
2240
- }));
2241
- }
2242
- };
2243
- return {
2244
- open: async (uri)=>{
2245
- setExpanded((prev)=>new Set(prev).add(uri));
2246
- if (!dirsRef.current[uri]) await fetchPage(uri, 0);
2247
- },
2248
- openPath: async (uri)=>{
2249
- const current = scope.current();
2250
- for (const parent of expandChain(rootUri, uri)){
2251
- if (current.controller.signal.aborted || scope.current().key !== current.key) return;
2252
- setExpanded((prev)=>new Set(prev).add(parent));
2253
- if (!dirsRef.current[parent]) await fetchPage(parent, 0);
2254
- }
2255
- },
2256
- toggleExpand: async (row)=>{
2257
- if (row.disabled) return;
2258
- const isOpen = expandedRef.current.has(row.uri);
2259
- setExpanded((prev)=>{
2260
- const next = new Set(prev);
2261
- if (isOpen) next.delete(row.uri);
2262
- else next.add(row.uri);
2263
- return next;
2264
- });
2265
- if (!isOpen && !dirsRef.current[row.uri]) await fetchPage(row.uri, 0);
2266
- },
2267
- loadMore: (parentId)=>fetchPage(parentId, dirsRef.current[parentId]?.entries.length ?? 0),
2268
- retry: (parentId)=>fetchPage(parentId, 0),
2269
- refresh: async ()=>{
2270
- if (!client) return;
2271
- const current = scope.current();
2272
- const open = [
2273
- ...expandedRef.current
2274
- ];
2275
- setError(null);
2276
- setDirs({});
2277
- for (const uri of open){
2278
- if (scope.current().key !== current.key) return;
2279
- await fetchPage(uri, 0);
2280
- }
2281
- }
2282
- };
2283
- }, [
2284
- client,
2285
- rootUri,
2286
- requestOptions,
2287
- scope
2288
- ]);
2289
- const rows = useMemo(()=>flattenTree(rootUri, 0, dirs, expanded), [
2290
- rootUri,
2291
- dirs,
2292
- expanded
2293
- ]);
2294
- return {
2295
- rows,
2296
- ...useTreeMetadata(rootUri, dirs),
2297
- isReady,
2298
- error,
2299
- ...state
2300
- };
2301
- }
2302
- function useFileBrowser({ rootUri, locale: localeProp, dashboardKinds, renderDashboard, dashboardLabels, controlled = false, summaryLabels, accessLabels, formatCharacterCount, defaultExpandedUri, currentUri, requestOptions, onUriChange }) {
2303
- const locale = useLocale(localeProp);
2304
- const text = resolveLabels(accessLabels, locale);
2305
- const client = useOvClient();
2306
- const [pendingUri, setPendingUri] = useState(currentUri);
2307
- const [refreshing, setRefreshing] = useState(false);
2308
- const [refreshGeneration, setRefreshGeneration] = useState(0);
2309
- const tree = useFsTree({
2310
- client,
2311
- rootUri,
2312
- defaultExpandedUri,
2313
- requestOptions
2314
- });
2315
- const activeUri = controlled ? currentUri : pendingUri;
2316
- const blocked = tree.accessOf(activeUri);
2317
- const resourceType = null === activeUri ? 'file' : tree.directoryUris.has(activeUri) ? 'directory' : tree.isKnownFile(activeUri) ? 'file' : 'unknown';
2318
- const openTree = tree.open;
2319
- const notifyUriChange = useRef(onUriChange);
2320
- notifyUriChange.current = onUriChange;
2321
- const openParent = useMemo(()=>async (uri)=>{
2322
- setPendingUri(uri);
2323
- notifyUriChange.current(uri);
2324
- await openTree(uri);
2325
- }, [
2326
- openTree
2327
- ]);
2328
- const preview = useFsPreview({
2329
- client,
2330
- uri: blocked ? null : activeUri,
2331
- resourceType,
2332
- labels: summaryLabels ?? resolveSummaryLabels(locale),
2333
- formatCharacterCount: formatCharacterCount ?? text.formatCharacterCount,
2334
- openParent,
2335
- generation: refreshGeneration,
2336
- requestOptions
2337
- });
2338
- const rows = tree.rows;
2339
- const openPath = tree.openPath;
2340
- const openResource = useMemo(()=>async (uri)=>{
2341
- setPendingUri(uri);
2342
- notifyUriChange.current(uri);
2343
- const directory = tree.directoryUris.has(uri) ? uri : uri.slice(0, uri.lastIndexOf('/'));
2344
- await openPath(directory);
2345
- }, [
2346
- openPath,
2347
- tree.directoryUris
2348
- ]);
2349
- const boards = useBrowserDashboards({
2350
- rows,
2351
- metadataRows: tree.metadataRows,
2352
- uri: blocked ? null : activeUri,
2353
- rootUri,
2354
- generation: refreshGeneration,
2355
- locale,
2356
- requestOptions,
2357
- onOpenUri: openResource,
2358
- dashboardKinds,
2359
- renderDashboard,
2360
- dashboardLabels
2361
- });
2362
- const selectedId = activeUri;
2363
- const { open, toggleExpand, loadMore, retry, refresh } = tree;
2364
- const { open: openDashboard, close: closeDashboard } = boards;
2365
- const setActiveKey = preview.setActiveKey;
2366
- const actions = useMemo(()=>({
2367
- select: async (row)=>{
2368
- if (row.disabled || false === row.selectable) return;
2369
- closeDashboard();
2370
- setPendingUri(row.uri);
2371
- notifyUriChange.current(row.uri);
2372
- if ('directory' === row.type) await open(row.uri);
2373
- },
2374
- toggleExpand,
2375
- loadMore: async (row)=>{
2376
- const parentId = 'parentId' in row ? row.parentId : void 0;
2377
- if (parentId) await loadMore(parentId);
2378
- },
2379
- retry: async (row)=>{
2380
- const parentId = 'parentId' in row ? row.parentId : void 0;
2381
- if (parentId) await retry(parentId);
2382
- },
2383
- refresh: async ()=>{
2384
- setRefreshing(true);
2385
- try {
2386
- setRefreshGeneration((generation)=>generation + 1);
2387
- await refresh();
2388
- } finally{
2389
- setRefreshing(false);
2390
- }
2391
- },
2392
- openDashboard: openDashboard,
2393
- setPreviewKey: (key)=>{
2394
- if (activeUri && key === dashboardKey(activeUri)) openDashboard(activeUri);
2395
- else {
2396
- closeDashboard();
2397
- setActiveKey(key);
2398
- }
2399
- }
2400
- }), [
2401
- setActiveKey,
2402
- open,
2403
- toggleExpand,
2404
- loadMore,
2405
- retry,
2406
- refresh,
2407
- openDashboard,
2408
- closeDashboard,
2409
- activeUri
2410
- ]);
2411
- const previewError = blocked ? new Error(text['denied' === blocked ? 'accessDenied' : 'traverseOnly']) : preview.error;
2412
- return {
2413
- rows,
2414
- selectedId,
2415
- currentUri: activeUri,
2416
- isReady: tree.isReady,
2417
- error: tree.error ?? previewError,
2418
- treeError: tree.error,
2419
- previewError,
2420
- dashboards: boards.dashboards,
2421
- dashboardError: boards.error,
2422
- previewTabs: mergeDashboardTab(preview.tabs, boards.tab, Boolean(blocked)),
2423
- previewKey: boards.isOpen && activeUri ? dashboardKey(activeUri) : preview.activeKey,
2424
- previewFooter: preview.footer,
2425
- refreshing,
2426
- actions
2427
- };
2428
- }
2429
- function AclPrincipalTabs({ type, text, onChange }) {
2430
- return /*#__PURE__*/ jsx("div", {
2431
- className: "ov-file-browser-acl__types",
2432
- role: "group",
2433
- "aria-label": text.addPrincipal,
2434
- children: [
2435
- 'user',
2436
- 'group'
2437
- ].map((value)=>/*#__PURE__*/ jsx(button_Button, {
2438
- size: "small",
2439
- type: type === value ? 'primary' : 'secondary',
2440
- "aria-pressed": type === value,
2441
- onClick: ()=>onChange(value),
2442
- children: 'user' === value ? text.users : text.groups
2443
- }, value))
2444
- });
2445
- }
2446
- const file_browser_icons_SIZE = 16;
2447
- const strokeProps = {
2448
- width: file_browser_icons_SIZE,
2449
- height: file_browser_icons_SIZE,
2450
- viewBox: '0 0 48 48',
2451
- fill: 'none',
2452
- stroke: 'currentColor',
2453
- strokeWidth: 4,
2454
- 'aria-hidden': true,
2455
- focusable: 'false'
2456
- };
2457
- function SearchIcon() {
2458
- return /*#__PURE__*/ jsx("svg", {
2459
- ...strokeProps,
2460
- children: /*#__PURE__*/ jsx("path", {
2461
- 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"
2462
- })
2463
- });
2464
- }
2465
- const LEVELS = [
2466
- 'read',
2467
- 'write',
2468
- 'manage'
2469
- ];
2470
- const RANK = {
2471
- read: 1,
2472
- write: 2,
2473
- manage: 3
2474
- };
2475
- const isLevel = (value)=>LEVELS.includes(value);
2476
- function isAclTarget(uri) {
2477
- if (!uri?.startsWith('viking://resources/')) return false;
2478
- const segments = uri.slice(19).split('/');
2479
- return segments.every((part)=>part && '.' !== part && '..' !== part);
2480
- }
2481
- function normalizeEntries(entries) {
2482
- const byPrincipal = new Map();
2483
- for (const entry of entries){
2484
- const principal = entry.principal.trim();
2485
- if (!/^(user|group):[^\s:]+$/.test(principal) || 'group:*' === principal || !isLevel(entry.level)) throw new TypeError('Invalid ACL entry');
2486
- const previous = byPrincipal.get(principal);
2487
- if (!previous || RANK[entry.level] > RANK[previous.level]) byPrincipal.set(principal, {
2488
- principal,
2489
- level: entry.level
2490
- });
2491
- }
2492
- return [
2493
- ...byPrincipal.values()
2494
- ].sort((a, b)=>a.principal.localeCompare(b.principal));
2495
- }
2496
- function parseReport(value, uri) {
2497
- const report = value;
2498
- if (!report || report.uri !== uri || ![
2499
- 'none',
2500
- 'inherit',
2501
- 'restricted'
2502
- ].includes(report.acl_mode)) throw new TypeError('Invalid ACL report');
2503
- for (const key of [
2504
- 'direct_entries',
2505
- 'inherited_entries',
2506
- 'effective_entries'
2507
- ])if (!Array.isArray(report[key])) throw new TypeError('Invalid ACL entries');
2508
- return {
2509
- uri,
2510
- acl_mode: report.acl_mode,
2511
- direct_entries: normalizeEntries(report.direct_entries),
2512
- inherited_entries: normalizeEntries(report.inherited_entries),
2513
- effective_entries: normalizeEntries(report.effective_entries)
2514
- };
2515
- }
2516
- function planChange(report, next) {
2517
- const parent = new Map(report.inherited_entries.map((entry)=>[
2518
- entry.principal,
2519
- entry
2520
- ]));
2521
- const target = new Map(next.map((entry)=>[
2522
- entry.principal,
2523
- entry
2524
- ]));
2525
- const retained = [
2526
- ...report.inherited_entries,
2527
- ...report.effective_entries
2528
- ].every((entry)=>{
2529
- const value = target.get(entry.principal);
2530
- return value && RANK[value.level] >= RANK[entry.level];
2531
- });
2532
- const entries = normalizeEntries(next);
2533
- if ('restricted' === report.acl_mode) return {
2534
- entries,
2535
- mode: 'restricted',
2536
- confirmation: false
2537
- };
2538
- if (!retained) return {
2539
- entries,
2540
- mode: 'restricted',
2541
- confirmation: true
2542
- };
2543
- return {
2544
- entries: entries.filter((entry)=>{
2545
- const inherited = parent.get(entry.principal);
2546
- return !inherited || RANK[entry.level] > RANK[inherited.level];
2547
- }),
2548
- mode: 'inherit',
2549
- confirmation: false
2550
- };
2551
- }
2552
- function restoreDiff(report) {
2553
- const inherited = new Map(report.inherited_entries.map((entry)=>[
2554
- entry.principal,
2555
- RANK[entry.level]
2556
- ]));
2557
- return report.direct_entries.filter((entry)=>Math.max(inherited.get(entry.principal) ?? 0, entry.principal.startsWith('user:') ? inherited.get('user:*') ?? 0 : 0) < RANK[entry.level]);
2558
- }
2559
- const acl_locales_en_US = {
2560
- title: 'Manage node permissions',
2561
- manage: 'Manage permissions',
2562
- read: 'Can read',
2563
- write: 'Can edit',
2564
- manageLevel: 'Can manage',
2565
- readDescription: 'Can view content, but cannot edit or manage permissions.',
2566
- writeDescription: 'Can view and edit content, but cannot manage permissions.',
2567
- manageDescription: 'Can manage the permissions of this node.',
2568
- effectivePermission: 'Current user’s effective permission',
2569
- addPrincipal: 'Add a User or Group',
2570
- search: 'Search users or groups',
2571
- users: 'User',
2572
- groups: 'Group',
2573
- allUsers: 'All users',
2574
- administrator: 'Account administrators',
2575
- administratorDescription: 'Administrators retain implicit management access.',
2576
- direct: 'Direct grant',
2577
- inherited: 'Inherited from parent',
2578
- remove: 'Remove permission',
2579
- add: 'Add',
2580
- cancel: 'Cancel',
2581
- confirm: 'Confirm',
2582
- close: 'Close permissions',
2583
- retry: 'Retry',
2584
- loadMore: 'Load more',
2585
- loading: 'Loading permissions…',
2586
- saving: 'Saving…',
2587
- saved: 'Permissions saved',
2588
- loadFailed: 'Could not load permissions',
2589
- saveFailed: 'Could not save permissions',
2590
- principalsFailed: 'Could not load users or groups',
2591
- empty: 'No principals available to add',
2592
- noMatches: 'No matching principals',
2593
- restricted: 'This node does not inherit its parent’s permissions.',
2594
- restore: 'Restore inheritance',
2595
- stopTitle: 'Stop inheriting parent permissions?',
2596
- stopDescription: 'This node will stop inheriting parent permissions and use the grants shown here.',
2597
- restoreTitle: 'Restore parent permission inheritance?',
2598
- restoreDescription: 'Direct grants on this node will be cleared and parent permissions inherited again.',
2599
- restoreRemoved: 'These direct grants will no longer apply:',
2600
- readOnly: 'Permission changes are disabled by the host.'
2601
- };
2602
- const acl_locales_zh_CN = {
2603
- title: '管理节点权限',
2604
- manage: '管理权限',
2605
- read: '可阅读',
2606
- write: '可编辑',
2607
- manageLevel: '可管理',
2608
- readDescription: '可查看节点内容,不能编辑或管理节点权限。',
2609
- writeDescription: '可查看并编辑内容,不能管理节点权限。',
2610
- manageDescription: '可管理该节点的权限配置。',
2611
- effectivePermission: '当前 User 有效权限',
2612
- addPrincipal: '添加 User 或 Group',
2613
- search: '搜索用户或用户组',
2614
- users: 'User',
2615
- groups: 'Group',
2616
- allUsers: '全部 User',
2617
- administrator: '数据空间管理员',
2618
- administratorDescription: '管理员始终保留隐式管理权限。',
2619
- direct: '直接授权',
2620
- inherited: '从父级目录继承权限',
2621
- remove: '移除权限',
2622
- add: '添加',
2623
- cancel: '取消',
2624
- confirm: '确定',
2625
- close: '关闭权限管理',
2626
- retry: '重试',
2627
- loadMore: '加载更多',
2628
- loading: '正在加载权限…',
2629
- saving: '正在保存…',
2630
- saved: '权限已保存',
2631
- loadFailed: '权限加载失败',
2632
- saveFailed: '权限保存失败',
2633
- principalsFailed: '用户或用户组加载失败',
2634
- empty: '暂无可添加成员',
2635
- noMatches: '暂无匹配结果',
2636
- restricted: '当前节点不继承父目录的权限。',
2637
- restore: '恢复继承',
2638
- stopTitle: '停止继承上级权限?',
2639
- stopDescription: '确定后,此节点将不再继承父级目录的权限,并按当前设置的访问权限生效。',
2640
- restoreTitle: '恢复继承上级权限?',
2641
- restoreDescription: '将清空本节点的直接授权,重新跟随上级权限。',
2642
- restoreRemoved: '以下直接授权将不再生效:',
2643
- readOnly: '宿主已禁止修改权限。'
2644
- };
2645
- const aclLabels = (locale, labels)=>resolveLocale({
2646
- 'en-US': acl_locales_en_US,
2647
- 'zh-CN': acl_locales_zh_CN
2648
- }, locale, labels);
2649
- const levelLabel = (level, text)=>'manage' === level ? text.manageLevel : text[level];
2650
- function AclMenu({ level, text, name, disabled, onChange, onRemove }) {
2651
- const [open, setOpen] = useState(false);
2652
- const root = useRef(null);
2653
- const trigger = useRef(null);
2654
- const menu = useRef(null);
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 }) {
2655
6
  const id = useId();
2656
- const close = ()=>{
2657
- setOpen(false);
2658
- trigger.current?.focus();
2659
- };
2660
- useEffect(()=>{
2661
- if (!open) return;
2662
- menu.current?.querySelector('button')?.focus();
2663
- const outside = (event)=>{
2664
- if (event.target instanceof Node && !root.current?.contains(event.target)) setOpen(false);
2665
- };
2666
- document.addEventListener('pointerdown', outside);
2667
- return ()=>document.removeEventListener('pointerdown', outside);
2668
- }, [
2669
- open
2670
- ]);
2671
- return /*#__PURE__*/ jsxs("div", {
2672
- className: "ov-file-browser-acl__menu-anchor",
2673
- ref: root,
2674
- onBlur: (event)=>{
2675
- if (!event.currentTarget.contains(event.relatedTarget)) setOpen(false);
2676
- },
2677
- children: [
2678
- /*#__PURE__*/ jsxs("button", {
2679
- ref: trigger,
2680
- type: "button",
2681
- className: "ov-file-browser-acl__level",
2682
- "aria-label": `${name}: ${levelLabel(level, text)}`,
2683
- "aria-haspopup": "menu",
2684
- "aria-expanded": open,
2685
- "aria-controls": open ? id : void 0,
2686
- disabled: disabled,
2687
- onClick: ()=>setOpen(!open),
2688
- children: [
2689
- levelLabel(level, text),
2690
- /*#__PURE__*/ jsx(chevron_downreact, {
2691
- "aria-hidden": "true",
2692
- width: 12,
2693
- height: 12
2694
- })
2695
- ]
2696
- }),
2697
- open && !disabled ? /*#__PURE__*/ jsxs("div", {
2698
- id: id,
2699
- role: "menu",
2700
- tabIndex: -1,
2701
- "aria-label": name,
2702
- ref: menu,
2703
- className: "ov-file-browser-acl__menu",
2704
- onKeyDown: (event)=>{
2705
- if ('Escape' === event.key) {
2706
- event.preventDefault();
2707
- event.stopPropagation();
2708
- close();
2709
- }
2710
- const buttons = [
2711
- ...event.currentTarget.querySelectorAll('button')
2712
- ];
2713
- const index = buttons.indexOf(document.activeElement);
2714
- const last = buttons.length - 1;
2715
- const next = 'ArrowDown' === event.key ? (index + 1) % buttons.length : 'ArrowUp' === event.key ? (index + last) % buttons.length : 'Home' === event.key ? 0 : 'End' === event.key ? last : -1;
2716
- if (next >= 0) {
2717
- event.preventDefault();
2718
- buttons[next]?.focus();
2719
- }
2720
- },
2721
- children: [
2722
- LEVELS.map((value)=>/*#__PURE__*/ jsxs("button", {
2723
- type: "button",
2724
- role: "menuitemradio",
2725
- "aria-checked": level === value,
2726
- onClick: ()=>{
2727
- close();
2728
- if (value !== level) onChange(value);
2729
- },
2730
- children: [
2731
- /*#__PURE__*/ jsx("span", {
2732
- className: "ov-file-browser-acl__check",
2733
- children: level === value ? /*#__PURE__*/ jsx(checkreact, {
2734
- width: 12,
2735
- height: 12,
2736
- "aria-hidden": "true"
2737
- }) : null
2738
- }),
2739
- levelLabel(value, text)
2740
- ]
2741
- }, value)),
2742
- onRemove ? /*#__PURE__*/ jsx("button", {
2743
- type: "button",
2744
- role: "menuitem",
2745
- className: "ov-file-browser-acl__remove",
2746
- onClick: ()=>{
2747
- close();
2748
- onRemove();
2749
- },
2750
- children: text.remove
2751
- }) : null
2752
- ]
2753
- }) : null
2754
- ]
2755
- });
2756
- }
2757
- function AclAvatar({ principal }) {
2758
- const [type, id] = principal.split(':');
2759
- return /*#__PURE__*/ jsx("span", {
2760
- "aria-hidden": "true",
2761
- className: "ov-file-browser-acl__avatar",
2762
- "data-group": 'group' === type || void 0,
2763
- children: 'group' === type ? 'G' : id?.charAt(0).toUpperCase()
2764
- });
2765
- }
2766
- function AclEntry({ entry, source, text, disabled, onChange, onRemove }) {
2767
- const name = 'user:*' === entry.principal ? text.allUsers : entry.principal.slice(entry.principal.indexOf(':') + 1);
2768
- return /*#__PURE__*/ jsxs("li", {
2769
- className: "ov-file-browser-acl__entry",
2770
- children: [
2771
- /*#__PURE__*/ jsx(AclAvatar, {
2772
- principal: entry.principal
2773
- }),
2774
- /*#__PURE__*/ jsxs("div", {
2775
- className: "ov-file-browser-acl__identity",
2776
- children: [
2777
- /*#__PURE__*/ jsx("span", {
2778
- className: "ov-file-browser-acl__name",
2779
- children: name
2780
- }),
2781
- /*#__PURE__*/ jsx("span", {
2782
- className: "ov-file-browser-acl__source",
2783
- children: source
2784
- })
2785
- ]
2786
- }),
2787
- /*#__PURE__*/ jsx(AclMenu, {
2788
- level: entry.level,
2789
- text: text,
2790
- name: entry.principal,
2791
- disabled: disabled,
2792
- onChange: onChange,
2793
- onRemove: onRemove
2794
- })
2795
- ]
2796
- });
2797
- }
2798
- function AclCandidate({ principal, level, text, onChange }) {
2799
- const name = 'user:*' === principal ? text.allUsers : principal.slice(principal.indexOf(':') + 1);
2800
- return /*#__PURE__*/ jsxs("div", {
2801
- className: "ov-file-browser-acl__candidate",
2802
- children: [
2803
- /*#__PURE__*/ jsxs("label", {
2804
- children: [
2805
- /*#__PURE__*/ jsx("input", {
2806
- type: "checkbox",
2807
- checked: void 0 !== level,
2808
- onChange: (event)=>onChange(event.target.checked ? 'read' : void 0)
2809
- }),
2810
- /*#__PURE__*/ jsx(AclAvatar, {
2811
- principal: principal
2812
- }),
2813
- /*#__PURE__*/ jsx("span", {
2814
- children: name
2815
- })
2816
- ]
2817
- }),
2818
- /*#__PURE__*/ jsx(AclMenu, {
2819
- text: text,
2820
- name: principal,
2821
- level: level ?? 'read',
2822
- onChange: onChange
2823
- })
2824
- ]
2825
- });
2826
- }
2827
- const readAcl = async (client, uri, options)=>parseReport(await client.request({
2828
- method: 'GET',
2829
- path: OV_PATHS.acl,
2830
- query: {
2831
- uri
2832
- },
2833
- options
2834
- }), uri);
2835
- async function readPermission(client, uri, options) {
2836
- const stat = await client.request({
2837
- method: 'GET',
2838
- path: OV_PATHS.fsStat,
2839
- query: {
2840
- uri
2841
- },
2842
- options
2843
- });
2844
- if (void 0 !== stat.permission) {
2845
- if (!isLevel(stat.permission)) throw new TypeError('Unknown resource permission');
2846
- return stat.permission;
2847
- }
2848
- try {
2849
- await readAcl(client, uri, options);
2850
- return 'manage';
2851
- } catch (error) {
2852
- if (isOvClientError(error) && 403 === error.statusCode) return;
2853
- throw error;
2854
- }
2855
- }
2856
- async function writeAcl(client, uri, options, change) {
2857
- const value = await client.request({
2858
- method: change ? 'PUT' : 'DELETE',
2859
- path: OV_PATHS.acl,
2860
- ...change ? {
2861
- body: {
2862
- uri,
2863
- acl_mode: change.mode,
2864
- entries: change.direct_entries
2865
- }
2866
- } : {
2867
- query: {
2868
- uri
2869
- }
2870
- },
2871
- options
2872
- });
2873
- return parseReport(value, uri);
2874
- }
2875
- async function identityValue(value) {
2876
- return ('function' == typeof value ? await value() : value)?.trim() ?? '';
2877
- }
2878
- async function listPrincipals(query, context, accountId) {
2879
- const account = await identityValue(accountId);
2880
- if (!account) throw new TypeError('Principal listing requires an account ID');
2881
- if ('group' === query.type) {
2882
- const groups = await context.client.request({
2883
- method: 'GET',
2884
- path: OV_PATH_BUILDERS.accountGroups(account),
2885
- options: context.requestOptions
2886
- });
2887
- return {
2888
- principals: groups.map((group)=>`group:${group.group_id}`),
2889
- hasMore: false
2890
- };
2891
- }
2892
- const result = await context.client.request({
2893
- method: 'GET',
2894
- path: OV_PATH_BUILDERS.accountUsers(account),
2895
- query: {
2896
- query: query.keyword,
2897
- page: query.page,
2898
- limit: 20,
2899
- include_summary: true,
2900
- include_credentials: false
2901
- },
2902
- options: context.requestOptions
2903
- });
2904
- return {
2905
- principals: result.users.map((user)=>`user:${user.user_id}`),
2906
- hasMore: 20 * query.page < result.total
2907
- };
2908
- }
2909
- function useAclPrincipals({ open, type, keyword, context, accountId, options }) {
2910
- const key = JSON.stringify([
2911
- type,
2912
- keyword,
2913
- open
2914
- ]);
2915
- const [paging, setPaging] = useState({
2916
- key,
2917
- page: 1
2918
- });
2919
- const page = paging.key === key ? paging.page : 1;
2920
- if (paging.key !== key) setPaging({
2921
- key,
2922
- page: 1
2923
- });
2924
- const [generation, setGeneration] = useState(0);
2925
- const [state, setState] = useState({
2926
- key: '',
2927
- items: [],
2928
- hasMore: false
2929
- });
2930
- const [loading, setLoading] = useState(false);
2931
- const [error, setError] = useState();
2932
- const load = options?.listPrincipals;
2933
- useEffect(()=>{
2934
- if (!open) return;
2935
- const controller = new AbortController();
2936
- setLoading(true);
2937
- setError(void 0);
2938
- const timer = setTimeout(()=>{
2939
- const inherited = context.requestOptions.signal;
2940
- const signal = inherited ? AbortSignal.any([
2941
- controller.signal,
2942
- inherited
2943
- ]) : controller.signal;
2944
- const request = {
2945
- ...context,
2946
- requestOptions: {
2947
- ...context.requestOptions,
2948
- signal
2949
- }
2950
- };
2951
- const query = {
2952
- type,
2953
- keyword,
2954
- page
2955
- };
2956
- (load ? load(query, request) : listPrincipals(query, request, accountId)).then((result)=>{
2957
- if (signal.aborted) return;
2958
- setState((previous)=>({
2959
- key,
2960
- hasMore: result.hasMore,
2961
- items: [
2962
- ...new Set([
2963
- ...page > 1 && previous.key === key ? previous.items : [],
2964
- ...result.principals
2965
- ])
2966
- ]
2967
- }));
2968
- setLoading(false);
2969
- }, (cause)=>{
2970
- if (!signal.aborted) {
2971
- setError(toError(cause));
2972
- setLoading(false);
2973
- }
2974
- });
2975
- }, 200);
2976
- return ()=>{
2977
- clearTimeout(timer);
2978
- controller.abort();
2979
- };
2980
- }, [
2981
- open,
2982
- type,
2983
- keyword,
2984
- key,
2985
- page,
2986
- generation,
2987
- context,
2988
- accountId,
2989
- load
2990
- ]);
2991
- return {
2992
- items: state.key === key ? state.items : [],
2993
- loading,
2994
- error,
2995
- hasMore: state.key === key && state.hasMore,
2996
- more: ()=>{
2997
- if (!loading) setPaging({
2998
- key,
2999
- page: page + 1
3000
- });
3001
- },
3002
- retry: ()=>setGeneration((value)=>value + 1)
3003
- };
3004
- }
3005
- function AclAddPrincipal({ entries, text, disabled, context, accountId, options, onAdd }) {
3006
- const [open, setOpen] = useState(false);
3007
- const [keyword, setKeyword] = useState('');
3008
- const [type, setType] = useState('user');
3009
- const [pending, setPending] = useState({});
3010
- const id = useId();
3011
- const directory = useAclPrincipals({
3012
- open: open && !disabled,
3013
- type,
3014
- keyword,
3015
- context,
3016
- accountId,
3017
- options
3018
- });
3019
- const existing = new Set(entries.map((entry)=>entry.principal));
3020
- const candidates = [
3021
- ...new Set([
3022
- ...'user' === type ? [
3023
- 'user:*'
3024
- ] : [],
3025
- ...directory.items
3026
- ])
3027
- ].filter((principal)=>!existing.has(principal) && principal.startsWith(`${type}:`)).filter((principal)=>('user:*' === principal ? text.allUsers : principal.slice(principal.indexOf(':') + 1)).toLocaleLowerCase().includes(keyword.trim().toLocaleLowerCase()));
3028
- const reset = ()=>{
3029
- setOpen(false);
3030
- setKeyword('');
3031
- setPending({});
3032
- };
3033
- const selected = Object.entries(pending).filter(([principal])=>!existing.has(principal));
3034
- return /*#__PURE__*/ jsxs("div", {
3035
- className: "ov-file-browser-acl__add",
3036
- children: [
3037
- /*#__PURE__*/ jsx("label", {
3038
- htmlFor: id,
3039
- children: text.addPrincipal
3040
- }),
3041
- /*#__PURE__*/ jsx(input_Input, {
3042
- prefix: /*#__PURE__*/ jsx(SearchIcon, {}),
3043
- id: id,
3044
- type: "search",
3045
- role: "combobox",
3046
- "aria-haspopup": "dialog",
3047
- value: keyword,
3048
- placeholder: text.search,
3049
- disabled: disabled,
3050
- "aria-expanded": open && !disabled,
3051
- "aria-controls": open ? `${id}-options` : void 0,
3052
- onFocus: ()=>setOpen(true),
3053
- onChange: (event)=>{
3054
- setKeyword(event.target.value);
3055
- setOpen(true);
3056
- }
3057
- }),
3058
- open && !disabled ? /*#__PURE__*/ jsxs("div", {
3059
- id: `${id}-options`,
3060
- className: "ov-file-browser-acl__picker",
3061
- role: "dialog",
3062
- "aria-label": text.addPrincipal,
3063
- children: [
3064
- /*#__PURE__*/ jsx(AclPrincipalTabs, {
3065
- type: type,
3066
- text: text,
3067
- onChange: setType
3068
- }),
3069
- /*#__PURE__*/ jsxs("div", {
3070
- className: "ov-file-browser-acl__candidates",
3071
- "aria-busy": directory.loading,
3072
- children: [
3073
- candidates.map((principal)=>/*#__PURE__*/ jsx(AclCandidate, {
3074
- principal: principal,
3075
- level: pending[principal],
3076
- text: text,
3077
- onChange: (level)=>setPending((previous)=>{
3078
- const next = {
3079
- ...previous
3080
- };
3081
- if (level) next[principal] = level;
3082
- else delete next[principal];
3083
- return next;
3084
- })
3085
- }, principal)),
3086
- directory.loading || candidates.length || directory.error ? null : /*#__PURE__*/ jsx("p", {
3087
- className: "ov-file-browser-acl__hint",
3088
- children: keyword.trim() ? text.noMatches : text.empty
3089
- })
3090
- ]
3091
- }),
3092
- directory.error ? /*#__PURE__*/ jsxs("div", {
3093
- className: "ov-file-browser-acl__failure",
3094
- role: "alert",
3095
- children: [
3096
- /*#__PURE__*/ jsx("p", {
3097
- children: text.principalsFailed
3098
- }),
3099
- /*#__PURE__*/ jsx("p", {
3100
- children: directory.error.message
3101
- }),
3102
- /*#__PURE__*/ jsx(button_Button, {
3103
- size: "small",
3104
- type: "default",
3105
- htmlType: "button",
3106
- onClick: directory.retry,
3107
- children: text.retry
3108
- })
3109
- ]
3110
- }) : null,
3111
- directory.loading ? /*#__PURE__*/ jsx("p", {
3112
- className: "ov-file-browser-acl__hint",
3113
- children: text.loading
3114
- }) : null,
3115
- directory.hasMore ? /*#__PURE__*/ jsx(button_Button, {
3116
- size: "small",
3117
- type: "default",
3118
- htmlType: "button",
3119
- className: "ov-file-browser-acl__more",
3120
- long: true,
3121
- disabled: directory.loading,
3122
- onClick: directory.more,
3123
- children: text.loadMore
3124
- }) : null,
3125
- /*#__PURE__*/ jsxs("div", {
3126
- className: "ov-file-browser-acl__buttons",
3127
- children: [
3128
- /*#__PURE__*/ jsx(button_Button, {
3129
- size: "small",
3130
- type: "default",
3131
- htmlType: "button",
3132
- onClick: reset,
3133
- children: text.cancel
3134
- }),
3135
- /*#__PURE__*/ jsx(button_Button, {
3136
- size: "small",
3137
- type: "primary",
3138
- htmlType: "button",
3139
- className: "ov-file-browser-acl__primary",
3140
- disabled: !selected.length,
3141
- onClick: ()=>{
3142
- onAdd(selected.map(([principal, level])=>({
3143
- principal,
3144
- level
3145
- })));
3146
- reset();
3147
- },
3148
- children: text.add
3149
- })
3150
- ]
3151
- })
3152
- ]
3153
- }) : null
3154
- ]
3155
- });
3156
- }
3157
- function AclConfirmation({ model, text }) {
3158
- const cancel = useRef(null);
3159
- const titleId = useId();
3160
- const descriptionId = useId();
3161
- const restore = model.confirmation?.kind === 'restore';
3162
- const removed = restore && model.report ? restoreDiff(model.report) : [];
3163
- useEffect(()=>{
3164
- cancel.current?.focus();
3165
- }, []);
3166
- return /*#__PURE__*/ jsxs("section", {
3167
- className: "ov-file-browser-acl__confirmation",
3168
- "aria-labelledby": titleId,
3169
- "aria-describedby": descriptionId,
3170
- children: [
3171
- /*#__PURE__*/ jsx("h3", {
3172
- id: titleId,
3173
- children: restore ? text.restoreTitle : text.stopTitle
3174
- }),
3175
- /*#__PURE__*/ jsx("p", {
3176
- id: descriptionId,
3177
- children: restore ? text.restoreDescription : text.stopDescription
3178
- }),
3179
- removed.length ? /*#__PURE__*/ jsxs(Fragment, {
3180
- children: [
3181
- /*#__PURE__*/ jsx("p", {
3182
- children: text.restoreRemoved
3183
- }),
3184
- /*#__PURE__*/ jsx("ul", {
3185
- children: removed.map((entry)=>/*#__PURE__*/ jsx("li", {
3186
- children: entry.principal
3187
- }, entry.principal))
3188
- })
3189
- ]
3190
- }) : null,
3191
- /*#__PURE__*/ jsxs("div", {
3192
- className: "ov-file-browser-acl__buttons",
3193
- children: [
3194
- /*#__PURE__*/ jsx(button_Button, {
3195
- size: "small",
3196
- type: "default",
3197
- ref: cancel,
3198
- htmlType: "button",
3199
- disabled: 'saving' === model.phase,
3200
- onClick: model.cancel,
3201
- children: text.cancel
3202
- }),
3203
- /*#__PURE__*/ jsx(button_Button, {
3204
- size: "small",
3205
- type: "primary",
3206
- htmlType: "button",
3207
- className: "ov-file-browser-acl__primary",
3208
- disabled: 'saving' === model.phase,
3209
- onClick: model.confirm,
3210
- children: 'saving' === model.phase ? text.saving : text.confirm
3211
- })
3212
- ]
3213
- })
3214
- ]
3215
- });
3216
- }
3217
- function useAclReport({ uri, context, open, readOnly, onUpdated }) {
3218
- const [report, setReport] = useState();
3219
- const [confirmation, setConfirmation] = useState();
3220
- const [error, setError] = useState();
3221
- const [phase, setPhase] = useState('loading');
3222
- const [saved, setSaved] = useState(false);
3223
- const [generation, setGeneration] = useState(0);
3224
- const pending = useRef(false);
3225
- const lifetime = useRef(null);
3226
- useEffect(()=>{
3227
- if (!open) return;
3228
- const controller = new AbortController();
3229
- lifetime.current = controller;
3230
- pending.current = false;
3231
- setPhase('loading');
3232
- setReport(void 0);
3233
- setError(void 0);
3234
- setConfirmation(void 0);
3235
- setSaved(false);
3236
- const { client, requestOptions } = context;
3237
- const signal = requestOptions.signal ? AbortSignal.any([
3238
- controller.signal,
3239
- requestOptions.signal
3240
- ]) : controller.signal;
3241
- readAcl(client, uri, {
3242
- ...requestOptions,
3243
- signal
3244
- }).then((value)=>{
3245
- if (!signal.aborted) {
3246
- setReport(value);
3247
- setPhase('ready');
3248
- }
3249
- }, (cause)=>{
3250
- if (!signal.aborted) {
3251
- setError(toError(cause));
3252
- setPhase('ready');
3253
- }
3254
- });
3255
- return ()=>controller.abort();
3256
- }, [
3257
- uri,
3258
- open,
3259
- generation,
3260
- context
3261
- ]);
3262
- async function save(change) {
3263
- const controller = lifetime.current;
3264
- if (pending.current || readOnly || !report || !controller || controller.signal.aborted) return;
3265
- pending.current = true;
3266
- setPhase('saving');
3267
- setError(void 0);
3268
- setSaved(false);
3269
- const { client, requestOptions } = context;
3270
- const signal = requestOptions.signal ? AbortSignal.any([
3271
- controller.signal,
3272
- requestOptions.signal
3273
- ]) : controller.signal;
3274
- try {
3275
- const value = await writeAcl(client, uri, {
3276
- ...requestOptions,
3277
- signal
3278
- }, change && {
3279
- direct_entries: change.entries,
3280
- mode: change.mode
3281
- });
3282
- if (signal.aborted) return;
3283
- setReport(value);
3284
- setConfirmation(void 0);
3285
- setSaved(true);
3286
- onUpdated(value);
3287
- } catch (cause) {
3288
- if (!signal.aborted) setError(toError(cause));
3289
- } finally{
3290
- if (!controller.signal.aborted && lifetime.current === controller) {
3291
- pending.current = false;
3292
- setPhase('ready');
3293
- }
3294
- }
3295
- }
3296
- function change(entries) {
3297
- if (!report || pending.current || readOnly) return;
3298
- const plan = planChange(report, normalizeEntries(entries));
3299
- setSaved(false);
3300
- setError(void 0);
3301
- if (plan.confirmation) setConfirmation({
3302
- kind: 'restrict',
3303
- entries: plan.entries
3304
- });
3305
- else save(plan);
3306
- }
3307
- return {
3308
- report,
3309
- confirmation,
3310
- error,
3311
- phase,
3312
- saved,
3313
- retry: ()=>setGeneration((value)=>value + 1),
3314
- change,
3315
- restore: ()=>{
3316
- if (!pending.current && !readOnly) setConfirmation({
3317
- kind: 'restore'
3318
- });
3319
- },
3320
- cancel: ()=>{
3321
- if (!pending.current) {
3322
- setConfirmation(void 0);
3323
- setError(void 0);
3324
- }
3325
- },
3326
- confirm: ()=>{
3327
- if (confirmation?.kind === 'restore') save();
3328
- else if (confirmation) save({
3329
- entries: confirmation.entries,
3330
- mode: 'restricted'
3331
- });
3332
- }
3333
- };
3334
- }
3335
- function AclModal({ uri, open, text, locale, context, triggerRef, accountId, options, onClose, onUpdated }) {
3336
- const id = useId();
3337
- const heading = useRef(null);
3338
- const model = useAclReport({
3339
- uri,
3340
- context,
3341
- open,
3342
- readOnly: Boolean(options?.readOnly),
3343
- onUpdated
3344
- });
3345
- const disabled = Boolean(options?.readOnly) || 'ready' !== model.phase;
3346
- const entries = model.report?.effective_entries ?? [];
3347
- const direct = new Map(model.report?.direct_entries.map((entry)=>[
3348
- entry.principal,
3349
- entry.level
3350
- ]));
3351
- const wasConfirming = useRef(false);
3352
- useEffect(()=>{
3353
- if (wasConfirming.current && !model.confirmation) heading.current?.focus();
3354
- wasConfirming.current = Boolean(model.confirmation);
3355
- }, [
3356
- model.confirmation
3357
- ]);
3358
- return /*#__PURE__*/ jsxs(Modal, {
3359
- id: id,
3360
- open: open,
3361
- title: text.title,
3362
- closeLabel: text.close,
3363
- triggerRef: triggerRef,
3364
- className: "ov-file-browser-acl",
3365
- locale: locale,
3366
- onClose: ()=>{
3367
- if ('saving' === model.phase) return;
3368
- if (model.confirmation) model.cancel();
3369
- else onClose();
3370
- },
3371
- children: [
3372
- /*#__PURE__*/ jsx("h2", {
3373
- ref: heading,
3374
- tabIndex: -1,
3375
- className: "ov-file-browser-acl__title",
3376
- children: text.title
3377
- }),
3378
- /*#__PURE__*/ jsx("p", {
3379
- className: "ov-file-browser-acl__uri",
3380
- children: uri
3381
- }),
3382
- model.error ? /*#__PURE__*/ jsxs("div", {
3383
- className: "ov-file-browser-acl__failure",
3384
- role: "alert",
3385
- children: [
3386
- /*#__PURE__*/ jsx("p", {
3387
- children: model.report ? text.saveFailed : text.loadFailed
3388
- }),
3389
- /*#__PURE__*/ jsx("p", {
3390
- children: model.error.message
3391
- }),
3392
- model.report ? null : /*#__PURE__*/ jsx(button_Button, {
3393
- size: "small",
3394
- type: "default",
3395
- htmlType: "button",
3396
- onClick: model.retry,
3397
- children: text.retry
3398
- })
3399
- ]
3400
- }) : null,
3401
- /*#__PURE__*/ jsx("div", {
3402
- role: "status",
3403
- className: "ov-file-browser-acl__status",
3404
- children: 'saving' === model.phase ? text.saving : 'loading' === model.phase ? text.loading : model.saved ? text.saved : ''
3405
- }),
3406
- model.confirmation ? /*#__PURE__*/ jsx(AclConfirmation, {
3407
- model: model,
3408
- text: text
3409
- }) : model.report ? /*#__PURE__*/ jsxs(Fragment, {
3410
- children: [
3411
- 'restricted' === model.report.acl_mode ? /*#__PURE__*/ jsxs("div", {
3412
- className: "ov-file-browser-acl__restricted",
3413
- children: [
3414
- /*#__PURE__*/ jsx("p", {
3415
- children: text.restricted
3416
- }),
3417
- /*#__PURE__*/ jsx(button_Button, {
3418
- size: "small",
3419
- type: "default",
3420
- htmlType: "button",
3421
- disabled: disabled,
3422
- onClick: model.restore,
3423
- children: text.restore
3424
- })
3425
- ]
3426
- }) : null,
3427
- options?.readOnly ? /*#__PURE__*/ jsx("p", {
3428
- className: "ov-file-browser-acl__hint",
3429
- children: text.readOnly
3430
- }) : null,
3431
- /*#__PURE__*/ jsx(AclAddPrincipal, {
3432
- entries: entries,
3433
- text: text,
3434
- disabled: disabled,
3435
- context: context,
3436
- accountId: accountId,
3437
- options: options,
3438
- onAdd: (added)=>model.change([
3439
- ...entries,
3440
- ...added
3441
- ])
3442
- }),
3443
- /*#__PURE__*/ jsxs("ul", {
3444
- className: "ov-file-browser-acl__entries",
3445
- "aria-busy": 'saving' === model.phase,
3446
- children: [
3447
- /*#__PURE__*/ jsxs("li", {
3448
- className: "ov-file-browser-acl__entry",
3449
- children: [
3450
- /*#__PURE__*/ jsx("span", {
3451
- className: "ov-file-browser-acl__avatar",
3452
- "aria-hidden": "true",
3453
- children: "A"
3454
- }),
3455
- /*#__PURE__*/ jsxs("div", {
3456
- className: "ov-file-browser-acl__identity",
3457
- children: [
3458
- /*#__PURE__*/ jsx("span", {
3459
- className: "ov-file-browser-acl__name",
3460
- children: text.administrator
3461
- }),
3462
- /*#__PURE__*/ jsx("span", {
3463
- className: "ov-file-browser-acl__source",
3464
- children: text.administratorDescription
3465
- })
3466
- ]
3467
- }),
3468
- /*#__PURE__*/ jsx("span", {
3469
- className: "ov-file-browser-acl__fixed",
3470
- children: levelLabel('manage', text)
3471
- })
3472
- ]
3473
- }),
3474
- entries.map((entry)=>/*#__PURE__*/ jsx(AclEntry, {
3475
- entry: entry,
3476
- text: text,
3477
- disabled: disabled,
3478
- source: direct.get(entry.principal) === entry.level ? text.direct : text.inherited,
3479
- onChange: (level)=>model.change(entries.map((item)=>item.principal === entry.principal ? {
3480
- ...item,
3481
- level
3482
- } : item)),
3483
- onRemove: ()=>model.change(entries.filter((item)=>item.principal !== entry.principal))
3484
- }, entry.principal))
3485
- ]
3486
- })
3487
- ]
3488
- }) : null
3489
- ]
3490
- });
3491
- }
3492
- function AclTag({ level, text, onManage }) {
3493
- const [open, setOpen] = useState(false);
3494
- const id = useId();
3495
- const description = 'read' === level ? text.readDescription : 'write' === level ? text.writeDescription : text.manageDescription;
3496
- return /*#__PURE__*/ jsxs("div", {
3497
- className: "ov-file-browser-acl__tag-anchor",
3498
- onBlur: (event)=>{
3499
- if (!event.currentTarget.contains(event.relatedTarget)) setOpen(false);
3500
- },
3501
- children: [
3502
- /*#__PURE__*/ jsx("button", {
3503
- onKeyDown: (event)=>{
3504
- if ('Escape' === event.key) {
3505
- event.preventDefault();
3506
- setOpen(false);
3507
- }
3508
- },
3509
- type: "button",
3510
- className: "ov-file-browser-acl__tag",
3511
- "aria-expanded": open,
3512
- "aria-controls": open ? id : void 0,
3513
- onClick: ()=>setOpen(!open),
3514
- children: levelLabel(level, text)
3515
- }),
3516
- open ? /*#__PURE__*/ jsxs("div", {
3517
- id: id,
3518
- className: "ov-file-browser-acl__tag-detail",
3519
- children: [
3520
- /*#__PURE__*/ jsx("p", {
3521
- children: description
3522
- }),
3523
- /*#__PURE__*/ jsxs("p", {
3524
- className: "ov-file-browser-acl__source",
3525
- children: [
3526
- text.effectivePermission,
3527
- ": ",
3528
- levelLabel(level, text)
3529
- ]
3530
- }),
3531
- 'manage' === level ? /*#__PURE__*/ jsx(button_Button, {
3532
- size: "small",
3533
- type: "default",
3534
- htmlType: "button",
3535
- onClick: ()=>{
3536
- setOpen(false);
3537
- onManage();
3538
- },
3539
- children: text.manage
3540
- }) : null
3541
- ]
3542
- }) : null
3543
- ]
3544
- });
3545
- }
3546
- function useFileBrowserAcl({ uri, acl, locale, labels, requestOptions, refresh }) {
3547
- const client = useOvClient();
3548
- const identity = useOvIdentity(requestOptions);
3549
- const inheritedSignal = useOvSignal();
3550
- const signal = requestOptions?.signal ?? inheritedSignal;
3551
- const options = 'object' == typeof acl ? acl : void 0;
3552
- const key = scopeKeyOf(client, requestOptions, uri ?? void 0);
3553
- const [permission, setPermission] = useState();
3554
- const [opened, setOpened] = useState();
3555
- const [generation, setGeneration] = useState(0);
3556
- const triggerRef = useRef(null);
3557
- const { baseURL, apiKey, accountId, userId, resourceId } = requestOptions ?? {};
3558
- const context = useMemo(()=>client ? {
3559
- client,
3560
- requestOptions: {
3561
- baseURL,
3562
- apiKey,
3563
- accountId,
3564
- userId,
3565
- resourceId,
3566
- signal
3567
- }
3568
- } : void 0, [
3569
- client,
3570
- baseURL,
3571
- apiKey,
3572
- accountId,
3573
- userId,
3574
- resourceId,
3575
- signal
3576
- ]);
3577
- const enabled = Boolean(acl) && Boolean(client) && isAclTarget(uri);
3578
- const resolver = options?.resolvePermission;
3579
- useEffect(()=>{
3580
- if (!enabled || !uri || !context) return;
3581
- const controller = new AbortController();
3582
- const composed = signal ? AbortSignal.any([
3583
- controller.signal,
3584
- signal
3585
- ]) : controller.signal;
3586
- const request = {
3587
- ...context,
3588
- requestOptions: {
3589
- ...context.requestOptions,
3590
- signal: composed
3591
- }
3592
- };
3593
- const load = resolver ? resolver(uri, request) : readPermission(request.client, uri, request.requestOptions);
3594
- load.then((level)=>{
3595
- if (!composed.aborted) setPermission({
3596
- key,
3597
- level
3598
- });
3599
- }, ()=>{
3600
- if (!composed.aborted) setPermission({
3601
- key,
3602
- error: true
3603
- });
3604
- });
3605
- return ()=>controller.abort();
3606
- }, [
3607
- enabled,
3608
- key,
3609
- uri,
3610
- resolver,
3611
- signal,
3612
- generation,
3613
- context
3614
- ]);
3615
- const level = enabled && permission?.key === key ? permission.level : void 0;
3616
- const text = aclLabels(locale, labels);
3617
- return {
3618
- titleExtra: enabled && permission?.key === key && permission.error ? /*#__PURE__*/ jsxs("span", {
3619
- className: "ov-file-browser-acl__lookup-error",
3620
- role: "status",
3621
- children: [
3622
- text.loadFailed,
3623
- /*#__PURE__*/ jsx(button_Button, {
3624
- size: "small",
3625
- type: "default",
3626
- htmlType: "button",
3627
- onClick: ()=>setGeneration((value)=>value + 1),
3628
- children: text.retry
3629
- })
3630
- ]
3631
- }) : level ? /*#__PURE__*/ jsx(AclTag, {
3632
- level: level,
3633
- text: text,
3634
- onManage: ()=>setOpened(key)
3635
- }) : null,
3636
- actions: 'manage' === level ? /*#__PURE__*/ jsx(button_Button, {
3637
- size: "small",
3638
- type: "default",
3639
- ref: triggerRef,
3640
- htmlType: "button",
3641
- className: "ov-file-browser-acl__manage",
3642
- onClick: ()=>setOpened(key),
3643
- children: text.manage
3644
- }) : null,
3645
- drawer: enabled && uri && context && 'manage' === level ? /*#__PURE__*/ jsx(AclModal, {
3646
- uri: uri,
3647
- open: opened === key,
3648
- text: text,
3649
- locale: locale,
3650
- triggerRef: triggerRef,
3651
- context: context,
3652
- accountId: identity.accountId,
3653
- options: options,
3654
- onClose: ()=>setOpened(void 0),
3655
- onUpdated: (report)=>{
3656
- setGeneration((value)=>value + 1);
3657
- refresh();
3658
- try {
3659
- options?.onChange?.(report);
3660
- } catch {
3661
- return;
3662
- }
3663
- }
3664
- }, key) : null
3665
- };
3666
- }
3667
- function FileBrowser({ uri, defaultUri, rootUri = 'viking://', defaultExpandedUri, locale: localeProp, agentConnect, dashboardKinds, renderDashboard, acl, onUriChange, onImportResources, renderImportResources, labels, requestOptions, className, style, ...rest }) {
3668
- const locale = useLocale(localeProp);
3669
- const [searchOpen, setSearchOpen] = useState(false);
3670
- const [internalUri, setInternalUri] = useState(()=>defaultUri ?? null);
3671
- const [preferredTreeWidth, setPreferredTreeWidth] = useState(352);
3672
- const isControlled = void 0 !== uri;
3673
- const currentUri = isControlled ? uri : internalUri;
3674
- const text = resolveLabels(labels, locale);
3675
- const { ref: layoutRef, width: layoutWidth } = useContainerWidth();
3676
- const treeMaxWidth = resolveTreeMaxWidth(layoutWidth);
3677
- const treeWidth = Math.min(preferredTreeWidth, treeMaxWidth);
3678
- const changeUri = useCallback((next)=>{
3679
- if (!isControlled) setInternalUri(next);
3680
- onUriChange?.(next);
3681
- }, [
3682
- isControlled,
3683
- onUriChange
3684
- ]);
3685
- const summaryLabels = useMemo(()=>({
3686
- l0: text.l0Summary,
3687
- l1: text.l1Overview,
3688
- failure: text.summaryFailed
3689
- }), [
3690
- text.l0Summary,
3691
- text.l1Overview,
3692
- text.summaryFailed
3693
- ]);
3694
- const previewLabels = useMemo(()=>resolvePreviewLabels(resolveLabels(labels, locale)), [
3695
- labels,
3696
- locale
3697
- ]);
3698
- const browser = useFileBrowser({
3699
- rootUri,
3700
- locale,
3701
- dashboardKinds,
3702
- renderDashboard,
3703
- dashboardLabels: labels?.dashboard,
3704
- controlled: isControlled,
3705
- summaryLabels,
3706
- formatCharacterCount: text.formatCharacterCount,
3707
- accessLabels: {
3708
- accessDenied: text.accessDenied,
3709
- traverseOnly: text.traverseOnly
3710
- },
3711
- defaultExpandedUri,
3712
- currentUri,
3713
- requestOptions,
3714
- onUriChange: changeUri
3715
- });
3716
- const permissions = useFileBrowserAcl({
3717
- uri: browser.currentUri,
3718
- acl,
3719
- locale,
3720
- labels: labels?.acl,
3721
- requestOptions,
3722
- refresh: browser.actions.refresh
3723
- });
3724
- return /*#__PURE__*/ jsxs(LocaleProvider, {
3725
- locale: locale,
3726
- children: [
3727
- /*#__PURE__*/ jsxs("div", {
3728
- ...rest,
3729
- ref: layoutRef,
3730
- className: [
3731
- 'ov-file-browser',
3732
- className
3733
- ].filter(Boolean).join(' '),
3734
- style: {
3735
- ...style,
3736
- '--ov-file-browser-tree-width': `${treeWidth}px`
3737
- },
3738
- children: [
3739
- /*#__PURE__*/ jsx("div", {
3740
- className: "ov-file-browser__tree",
3741
- children: /*#__PURE__*/ jsx(FileBrowserTreePane, {
3742
- entries: {
3743
- agentConnect,
3744
- onImportResources,
3745
- renderImportResources,
3746
- labels: labels?.entries
3747
- },
3748
- onSearch: ()=>setSearchOpen(true),
3749
- browser: browser,
3750
- treeLabels: text.tree,
3751
- locale: locale,
3752
- dashboardLabels: labels?.dashboard,
3753
- searchPlaceholder: text.searchPlaceholder,
3754
- refreshLabel: text.refresh,
3755
- retryLabel: text.retry
3756
- })
3757
- }),
3758
- /*#__PURE__*/ jsx(ResizableHandle, {
3759
- label: text.resizeTree,
3760
- min: 200,
3761
- max: treeMaxWidth,
3762
- value: treeWidth,
3763
- onResize: setPreferredTreeWidth,
3764
- className: "ov-file-browser__resizer"
3765
- }),
3766
- browser.previewTabs && browser.previewTabs.length > 0 ? /*#__PURE__*/ jsx(FileBrowserDetail, {
3767
- tabs: browser.previewTabs,
3768
- activeKey: browser.previewKey,
3769
- locale: locale,
3770
- labels: previewLabels,
3771
- footer: browser.previewFooter,
3772
- titleExtra: permissions.titleExtra,
3773
- extraActions: permissions.actions,
3774
- viewLabels: {
3775
- preview: text.previewMode,
3776
- source: text.sourceMode,
3777
- copyPath: text.copyPath,
3778
- copyContent: text.copyContent,
3779
- download: text.download,
3780
- viewSwitch: text.viewSwitch
3781
- },
3782
- onActiveKeyChange: browser.actions.setPreviewKey
3783
- }) : browser.currentUri && browser.previewError ? /*#__PURE__*/ jsx("div", {
3784
- className: "ov-file-browser__detail",
3785
- children: /*#__PURE__*/ jsx(FileBrowserFailure, {
3786
- message: text.error,
3787
- detail: browser.previewError.message,
3788
- retryLabel: text.retry,
3789
- onRetry: ()=>void browser.actions.refresh()
3790
- })
3791
- }) : /*#__PURE__*/ jsx("div", {
3792
- className: "ov-file-browser__detail",
3793
- children: /*#__PURE__*/ jsx(FileBrowserEmpty, {
3794
- label: text.empty
3795
- })
3796
- })
3797
- ]
3798
- }),
3799
- permissions.drawer,
3800
- /*#__PURE__*/ jsx(FileBrowserSearch, {
3801
- open: searchOpen,
3802
- locale: locale,
3803
- rootUri: rootUri,
3804
- triggerRef: layoutRef,
3805
- text: text,
3806
- requestOptions: requestOptions,
3807
- onClose: ()=>setSearchOpen(false)
3808
- })
3809
- ]
3810
- });
3811
- }
3812
- export { FileBrowser };
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()
28
+ }),
29
+ children: [
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)
51
+ })
52
+ ]
53
+ });
54
+ }
55
+ export { EmailLoginForm };