@openviking/react 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -11
- package/dist/28~0.js +15 -0
- package/dist/2~0.js +6 -3
- package/dist/37~0.js +27 -0
- package/dist/3c~0.js +17 -9
- package/dist/3~0.js +4 -2
- package/dist/ae~0.js +6 -2
- package/dist/a~0.js +79 -72
- package/dist/ck~0.js +4 -0
- package/dist/client/paths.d.ts +4 -0
- package/dist/client/provider.d.ts +10 -6
- package/dist/components/agent-connect/agent-connect-code-block.d.ts +14 -0
- package/dist/components/agent-connect/agent-connect-copy.d.ts +3 -0
- package/dist/components/agent-connect/agent-connect-design.d.ts +1 -1
- package/dist/components/agent-connect/agent-connect-installer.d.ts +1 -0
- package/dist/components/agent-connect/agent-connect-instructions-view.d.ts +4 -6
- package/dist/components/agent-connect/agent-connect-instructions.d.ts +13 -0
- package/dist/components/agent-connect/agent-connect-markdown.d.ts +8 -2
- package/dist/components/agent-connect/agent-connect-mask.d.ts +10 -0
- package/dist/components/agent-connect/agent-connect.d.ts +1 -1
- package/dist/components/agent-connect/locales/en-US.d.ts +3 -0
- package/dist/components/agent-connect/style.css +163 -5
- package/dist/components/agent-connect/types.d.ts +5 -3
- package/dist/components/agent-connect/use-agent-connect-copy.d.ts +6 -0
- package/dist/components/directory-tour/style.css +46 -2
- package/dist/components/directory-tour/types.d.ts +2 -1
- package/dist/components/experience-dashboard/dashboard-tabs.d.ts +11 -0
- package/dist/components/experience-dashboard/experience-dashboard.d.ts +2 -0
- package/dist/components/experience-dashboard/experience-impact.d.ts +11 -0
- package/dist/components/experience-dashboard/experience-list.d.ts +9 -0
- package/dist/components/experience-dashboard/experience-pagination.d.ts +8 -0
- package/dist/components/experience-dashboard/experience-tests.d.ts +6 -0
- package/dist/components/experience-dashboard/experience-trajectories.d.ts +6 -0
- package/dist/components/experience-dashboard/index.d.ts +2 -0
- package/dist/components/experience-dashboard/labels.d.ts +2 -0
- package/dist/components/experience-dashboard/style.css +699 -0
- package/dist/components/experience-dashboard/style.js +0 -0
- package/dist/components/experience-dashboard/types.d.ts +106 -0
- package/dist/components/experience-dashboard.js +1 -0
- package/dist/components/file-browser-entries/file-browser-entries.d.ts +1 -1
- package/dist/components/file-browser-entries/style.css +259 -13
- package/dist/components/file-browser-entries/types.d.ts +2 -2
- package/dist/components/file-preview/style.css +48 -4
- package/dist/components/file-preview/types.d.ts +2 -2
- package/dist/components/file-tree/style.css +63 -4
- package/dist/components/file-tree/types.d.ts +2 -2
- package/dist/components/scope-switcher/scope-switcher.d.ts +2 -2
- package/dist/components/scope-switcher/style.css +48 -4
- package/dist/components/scope-switcher/types.d.ts +5 -5
- package/dist/components/scope-switcher.js +1 -1
- package/dist/components/style.css +2451 -139
- package/dist/components/tui/style.css +122 -36
- package/dist/components/tui/tui.d.ts +1 -1
- package/dist/components/tui/types.d.ts +2 -2
- package/dist/components/viking-bot/ark-message-list-view.d.ts +4 -1
- package/dist/components/viking-bot/interaction/types.d.ts +2 -2
- package/dist/components/viking-bot/interaction/viking-bot-interaction.d.ts +1 -1
- package/dist/components/viking-bot/session-actions.d.ts +2 -2
- package/dist/components/viking-bot/style.css +159 -12
- package/dist/components/viking-bot/types.d.ts +7 -7
- package/dist/components/viking-bot/viking-bot.d.ts +1 -1
- package/dist/components/wiki-dashboard/index.d.ts +2 -0
- package/dist/components/wiki-dashboard/labels.d.ts +2 -0
- package/dist/components/wiki-dashboard/style.css +741 -0
- package/dist/components/wiki-dashboard/style.js +0 -0
- package/dist/components/wiki-dashboard/types.d.ts +92 -0
- package/dist/components/wiki-dashboard/wiki-action-button.d.ts +9 -0
- package/dist/components/wiki-dashboard/wiki-conflict-card.d.ts +15 -0
- package/dist/components/wiki-dashboard/wiki-dashboard.d.ts +2 -0
- package/dist/components/wiki-dashboard/wiki-file-icon.d.ts +3 -0
- package/dist/components/wiki-dashboard/wiki-severity-filter.d.ts +8 -0
- package/dist/components/wiki-dashboard.js +1 -0
- package/dist/c~0.js +169 -155
- package/dist/e~0.js +3 -1
- package/dist/fi~0.js +354 -0
- package/dist/fj~0.js +503 -0
- package/dist/f~0.js +661 -309
- package/dist/icons/index.d.ts +28 -0
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -1
- package/dist/k~0.js +277 -1
- package/dist/lk~0.js +55 -13
- package/dist/l~0.js +1096 -187
- package/dist/modules/console/console.d.ts +1 -1
- package/dist/modules/console/index.d.ts +1 -2
- package/dist/modules/console/style.css +377 -56
- package/dist/modules/console/types.d.ts +2 -2
- package/dist/modules/console/use-console.d.ts +1 -1
- package/dist/modules/console.js +1 -1
- package/dist/modules/file-browser/dashboard-data.d.ts +9 -0
- package/dist/modules/file-browser/dashboard-indicator.d.ts +8 -0
- package/dist/modules/file-browser/dashboard-labels.d.ts +9 -0
- package/dist/modules/file-browser/dashboard-model.d.ts +14 -0
- package/dist/modules/file-browser/dashboard-resource.d.ts +12 -0
- package/dist/modules/file-browser/experience-dashboard-pane.d.ts +8 -0
- package/dist/modules/file-browser/experience-data.d.ts +31 -0
- package/dist/modules/file-browser/file-browser-labels.d.ts +1 -1
- package/dist/modules/file-browser/file-browser-tree-pane.d.ts +3 -2
- package/dist/modules/file-browser/file-browser.d.ts +1 -1
- package/dist/modules/file-browser/fs-directories.d.ts +8 -0
- package/dist/modules/file-browser/fs-lines.d.ts +36 -0
- package/dist/modules/file-browser/fs-memory-fields.d.ts +65 -0
- package/dist/modules/file-browser/fs-model.d.ts +12 -2
- package/dist/modules/file-browser/fs-read-file.d.ts +14 -0
- package/dist/modules/file-browser/fs-selection.d.ts +4 -0
- package/dist/modules/file-browser/index.d.ts +2 -2
- package/dist/modules/file-browser/style.css +1883 -25
- package/dist/modules/file-browser/types.d.ts +64 -2
- package/dist/modules/file-browser/use-browser-dashboards.d.ts +31 -0
- package/dist/modules/file-browser/use-dashboard-query.d.ts +9 -0
- package/dist/modules/file-browser/use-experience-dashboard.d.ts +27 -0
- package/dist/modules/file-browser/use-file-browser.d.ts +2 -45
- package/dist/modules/file-browser/use-fs-tree.d.ts +2 -0
- package/dist/modules/file-browser/use-wiki-dashboard.d.ts +17 -0
- package/dist/modules/file-browser/wiki-conflicts.d.ts +12 -0
- package/dist/modules/file-browser/wiki-dashboard-pane.d.ts +14 -0
- package/dist/modules/file-browser.js +1 -1
- package/dist/modules/scope-cascade/controller.d.ts +2 -2
- package/dist/modules/scope-cascade/index.d.ts +1 -2
- package/dist/modules/scope-cascade/scope-cascade.d.ts +2 -2
- package/dist/modules/scope-cascade/style.css +48 -4
- package/dist/modules/scope-cascade/types.d.ts +9 -4
- package/dist/modules/scope-cascade/use-scope-cascade.d.ts +2 -2
- package/dist/modules/scope-cascade.js +1 -1
- package/dist/modules/style.css +2459 -192
- package/dist/n~0.js +16 -130
- package/dist/rt~0.js +152 -0
- package/dist/r~0.js +17 -38
- package/dist/shared/components/popover/popover.d.ts +1 -1
- package/dist/shared/components/popover/types.d.ts +7 -1
- package/dist/shared/dashboard/dashboard-state.d.ts +12 -0
- package/dist/shared/locale-context.d.ts +8 -0
- package/dist/static/image/dashboard-background.png +0 -0
- package/dist/style.css +9445 -4822
- package/dist/u~0.js +324 -96
- package/dist/viking-bot-composer~0.js +4 -2
- package/dist/viking-bot-interaction~0.js +3 -1
- package/package.json +14 -2
package/dist/l~0.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { createElement, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { FilePreview as file_preview_FilePreview } from "./3~0.js";
|
|
4
|
-
import { Tooltip } from "./
|
|
5
|
-
import { getFileTypeColor,
|
|
4
|
+
import { Tooltip } from "./rt~0.js";
|
|
5
|
+
import { getFileTypeColor, getFileTypeIcon, WikiBookIcon, ExperienceBoardIcon, WikiConflictBoardIcon, FolderIcon, WikiBoardIcon, resolveFileTypeIconKey } from "./k~0.js";
|
|
6
6
|
import { FileBrowserEntries } from "./2~0.js";
|
|
7
7
|
import { FileTree as file_tree_FileTree } from "./n~0.js";
|
|
8
8
|
import { resolveLocale } from "./nx~0.js";
|
|
9
9
|
import { OV_PATHS } from "./ck~0.js";
|
|
10
|
-
import { useOvClient } from "./ae~0.js";
|
|
10
|
+
import { isOvClientError, useOvSignal, useOvClient } from "./ae~0.js";
|
|
11
|
+
import { ExperienceDashboard } from "./f~0.js";
|
|
12
|
+
import { WikiDashboard } from "./fj~0.js";
|
|
13
|
+
import { useLocale, LocaleProvider } from "./28~0.js";
|
|
11
14
|
function clampResizableWidth(width, min, max) {
|
|
12
15
|
const rounded = Math.round(width);
|
|
13
16
|
const lower = Math.max(min, rounded);
|
|
@@ -237,6 +240,26 @@ function resolveTreeMaxWidth(containerWidth) {
|
|
|
237
240
|
if (!containerWidth) return TREE_MAX_WIDTH;
|
|
238
241
|
return Math.max(TREE_MIN_WIDTH, Math.min(TREE_MAX_WIDTH, containerWidth - DETAIL_MIN_WIDTH - RESIZE_FOOTPRINT));
|
|
239
242
|
}
|
|
243
|
+
const en = {
|
|
244
|
+
experienceTitle: 'Experience dashboard',
|
|
245
|
+
wikiTitle: 'Dashboard',
|
|
246
|
+
openExperience: 'Open experience dashboard',
|
|
247
|
+
openWiki: 'Open Wiki dashboard',
|
|
248
|
+
wikiConflicts: 'View pending Wiki conflicts',
|
|
249
|
+
failed: 'Could not load dashboard information'
|
|
250
|
+
};
|
|
251
|
+
const zh = {
|
|
252
|
+
experienceTitle: '经验看板',
|
|
253
|
+
wikiTitle: '看板',
|
|
254
|
+
openExperience: '打开经验看板',
|
|
255
|
+
openWiki: '打开 Wiki 看板',
|
|
256
|
+
wikiConflicts: '查看 Wiki 待确认冲突',
|
|
257
|
+
failed: '看板信息加载失败'
|
|
258
|
+
};
|
|
259
|
+
const dashboard_labels_dashboardLabels = (locale, labels)=>({
|
|
260
|
+
...'zh-CN' === locale ? zh : en,
|
|
261
|
+
...labels
|
|
262
|
+
});
|
|
240
263
|
const file_browser_icons_SIZE = 16;
|
|
241
264
|
const strokeProps = {
|
|
242
265
|
width: file_browser_icons_SIZE,
|
|
@@ -303,6 +326,25 @@ function FileBrowserToolbar({ searchId, query, refreshing, canRefresh, placehold
|
|
|
303
326
|
]
|
|
304
327
|
});
|
|
305
328
|
}
|
|
329
|
+
function DashboardIndicator({ dashboard, locale, labels, onOpen }) {
|
|
330
|
+
const text = dashboard_labels_dashboardLabels(locale, labels);
|
|
331
|
+
const label = 'experience' === dashboard.kind ? text.openExperience : dashboard.pendingConflicts ? text.wikiConflicts : text.openWiki;
|
|
332
|
+
const Icon = 'experience' === dashboard.kind ? ExperienceBoardIcon : dashboard.pendingConflicts ? WikiConflictBoardIcon : WikiBoardIcon;
|
|
333
|
+
return /*#__PURE__*/ jsx("button", {
|
|
334
|
+
type: "button",
|
|
335
|
+
className: `ov-file-browser__dashboard${dashboard.pendingConflicts ? ' ov-file-browser__dashboard--pending' : ''}`,
|
|
336
|
+
"aria-label": label,
|
|
337
|
+
title: label,
|
|
338
|
+
onClick: (event)=>{
|
|
339
|
+
event.stopPropagation();
|
|
340
|
+
onOpen(dashboard.uri);
|
|
341
|
+
},
|
|
342
|
+
children: /*#__PURE__*/ jsx(Icon, {
|
|
343
|
+
width: 12,
|
|
344
|
+
height: 12
|
|
345
|
+
})
|
|
346
|
+
});
|
|
347
|
+
}
|
|
306
348
|
function fileTypeIcon(name) {
|
|
307
349
|
const Icon = getFileTypeIcon(name);
|
|
308
350
|
const key = resolveFileTypeIconKey(name);
|
|
@@ -319,7 +361,7 @@ function directoryIcon() {
|
|
|
319
361
|
className: "ov-file-tree__file-type-icon"
|
|
320
362
|
});
|
|
321
363
|
}
|
|
322
|
-
function FileBrowserTreePane({ entries, locale, searchId, browser, treeLabels, searchPlaceholder, refreshLabel, searchLoading, searchEmpty, searchErrorLabel, retryLabel }) {
|
|
364
|
+
function FileBrowserTreePane({ entries, locale, dashboardLabels, searchId, browser, treeLabels, searchPlaceholder, refreshLabel, searchLoading, searchEmpty, searchErrorLabel, retryLabel }) {
|
|
323
365
|
return /*#__PURE__*/ jsxs(Fragment, {
|
|
324
366
|
children: [
|
|
325
367
|
/*#__PURE__*/ jsx(FileBrowserEntries, {
|
|
@@ -337,44 +379,77 @@ function FileBrowserTreePane({ entries, locale, searchId, browser, treeLabels, s
|
|
|
337
379
|
onQueryChange: browser.actions.setQuery,
|
|
338
380
|
onRefresh: ()=>void browser.actions.refresh()
|
|
339
381
|
}),
|
|
340
|
-
/*#__PURE__*/
|
|
382
|
+
/*#__PURE__*/ jsxs("div", {
|
|
341
383
|
className: "ov-file-browser__tree-scroll",
|
|
342
|
-
children:
|
|
343
|
-
|
|
344
|
-
rows: browser.rows,
|
|
345
|
-
selectedId: browser.selectedId,
|
|
346
|
-
isReady: browser.isReady,
|
|
347
|
-
labels: treeLabels,
|
|
348
|
-
emptyFallback: browser.searching ? browser.searchError ? /*#__PURE__*/ jsxs("div", {
|
|
384
|
+
children: [
|
|
385
|
+
browser.dashboardError ? /*#__PURE__*/ jsxs("div", {
|
|
349
386
|
className: "ov-file-browser__hint ov-file-browser__hint--error",
|
|
387
|
+
"aria-live": "polite",
|
|
350
388
|
children: [
|
|
351
|
-
/*#__PURE__*/
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
389
|
+
/*#__PURE__*/ jsxs("p", {
|
|
390
|
+
children: [
|
|
391
|
+
dashboard_labels_dashboardLabels(locale, dashboardLabels).failed,
|
|
392
|
+
":",
|
|
393
|
+
' ',
|
|
394
|
+
browser.dashboardError.message
|
|
395
|
+
]
|
|
358
396
|
}),
|
|
359
397
|
/*#__PURE__*/ jsx("button", {
|
|
360
398
|
type: "button",
|
|
361
|
-
className: "ov-file-browser__retry",
|
|
362
399
|
onClick: ()=>void browser.actions.refresh(),
|
|
363
400
|
children: retryLabel
|
|
364
401
|
})
|
|
365
402
|
]
|
|
366
|
-
}) :
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
403
|
+
}) : null,
|
|
404
|
+
/*#__PURE__*/ jsx(file_tree_FileTree, {
|
|
405
|
+
locale: locale,
|
|
406
|
+
rows: browser.rows,
|
|
407
|
+
selectedId: browser.selectedId,
|
|
408
|
+
isReady: browser.isReady,
|
|
409
|
+
labels: treeLabels,
|
|
410
|
+
emptyFallback: browser.searching ? browser.searchError ? /*#__PURE__*/ jsxs("div", {
|
|
411
|
+
className: "ov-file-browser__hint ov-file-browser__hint--error",
|
|
412
|
+
children: [
|
|
413
|
+
/*#__PURE__*/ jsx("p", {
|
|
414
|
+
className: "ov-file-browser__failure-title",
|
|
415
|
+
children: searchErrorLabel
|
|
416
|
+
}),
|
|
417
|
+
/*#__PURE__*/ jsx("p", {
|
|
418
|
+
className: "ov-file-browser__failure-detail",
|
|
419
|
+
children: browser.searchError.message
|
|
420
|
+
}),
|
|
421
|
+
/*#__PURE__*/ jsx("button", {
|
|
422
|
+
type: "button",
|
|
423
|
+
className: "ov-file-browser__retry",
|
|
424
|
+
onClick: ()=>void browser.actions.refresh(),
|
|
425
|
+
children: retryLabel
|
|
426
|
+
})
|
|
427
|
+
]
|
|
428
|
+
}) : /*#__PURE__*/ jsx("p", {
|
|
429
|
+
className: "ov-file-browser__hint",
|
|
430
|
+
children: browser.searchLoading ? searchLoading : searchEmpty
|
|
431
|
+
}) : void 0,
|
|
432
|
+
renderRowIcon: (row)=>browser.dashboards.get(row.uri)?.isRoot ? /*#__PURE__*/ jsx(WikiBookIcon, {
|
|
433
|
+
width: 14,
|
|
434
|
+
height: 14
|
|
435
|
+
}) : fileTypeIcon(row.name),
|
|
436
|
+
renderDashboard: (row)=>{
|
|
437
|
+
const dashboard = browser.dashboards.get(row.uri);
|
|
438
|
+
return dashboard ? /*#__PURE__*/ jsx(DashboardIndicator, {
|
|
439
|
+
dashboard: dashboard,
|
|
440
|
+
locale: locale,
|
|
441
|
+
labels: dashboardLabels,
|
|
442
|
+
onOpen: browser.actions.openDashboard
|
|
443
|
+
}) : null;
|
|
444
|
+
},
|
|
445
|
+
operations: {
|
|
446
|
+
select: browser.actions.select,
|
|
447
|
+
toggleExpand: browser.actions.toggleExpand,
|
|
448
|
+
loadMore: browser.actions.loadMore,
|
|
449
|
+
retry: browser.actions.retry
|
|
450
|
+
}
|
|
451
|
+
})
|
|
452
|
+
]
|
|
378
453
|
})
|
|
379
454
|
]
|
|
380
455
|
});
|
|
@@ -475,6 +550,11 @@ function useContainerWidth() {
|
|
|
475
550
|
width
|
|
476
551
|
};
|
|
477
552
|
}
|
|
553
|
+
function selectedRowId(uri, results) {
|
|
554
|
+
if (!uri || null === results) return uri;
|
|
555
|
+
const index = results.findIndex((entry)=>entry.uri === uri);
|
|
556
|
+
return index < 0 ? uri : `${uri}#${index}`;
|
|
557
|
+
}
|
|
478
558
|
const emptyDir = ()=>({
|
|
479
559
|
entries: [],
|
|
480
560
|
hasMore: false,
|
|
@@ -502,6 +582,7 @@ function nameFromUri(uri) {
|
|
|
502
582
|
function toEntryRow(entry, depth, expanded, index, busy) {
|
|
503
583
|
const isDir = true === entry.isDir;
|
|
504
584
|
return {
|
|
585
|
+
tags: entry.tags,
|
|
505
586
|
kind: 'entry',
|
|
506
587
|
id: void 0 === index ? entry.uri : `${entry.uri}#${index}`,
|
|
507
588
|
depth,
|
|
@@ -512,7 +593,7 @@ function toEntryRow(entry, depth, expanded, index, busy) {
|
|
|
512
593
|
busy: busy || void 0
|
|
513
594
|
};
|
|
514
595
|
}
|
|
515
|
-
function toFileTab(entry, content, maxLines, icon, openParent) {
|
|
596
|
+
function toFileTab(entry, content, maxLines, icon, openParent, truncated = content.split('\n').length >= maxLines) {
|
|
516
597
|
const name = nameFromUri(entry.uri);
|
|
517
598
|
return {
|
|
518
599
|
kind: 'file',
|
|
@@ -526,7 +607,7 @@ function toFileTab(entry, content, maxLines, icon, openParent) {
|
|
|
526
607
|
content,
|
|
527
608
|
fileName: name,
|
|
528
609
|
path: entry.uri,
|
|
529
|
-
truncated
|
|
610
|
+
truncated
|
|
530
611
|
}
|
|
531
612
|
};
|
|
532
613
|
}
|
|
@@ -611,6 +692,39 @@ function isAbort(error) {
|
|
|
611
692
|
function toError(cause) {
|
|
612
693
|
return cause instanceof Error ? cause : new Error(String(cause));
|
|
613
694
|
}
|
|
695
|
+
async function readDirectory(client, uri, options) {
|
|
696
|
+
const read = (path)=>client.request({
|
|
697
|
+
method: 'GET',
|
|
698
|
+
path,
|
|
699
|
+
query: {
|
|
700
|
+
uri
|
|
701
|
+
},
|
|
702
|
+
options
|
|
703
|
+
}).then((value)=>({
|
|
704
|
+
ok: true,
|
|
705
|
+
text: 'string' == typeof value ? value : ''
|
|
706
|
+
})).catch((cause)=>({
|
|
707
|
+
ok: false,
|
|
708
|
+
cause
|
|
709
|
+
}));
|
|
710
|
+
const [abstractResult, overviewResult] = await Promise.all([
|
|
711
|
+
read(OV_PATHS.contentAbstract),
|
|
712
|
+
read(OV_PATHS.contentOverview)
|
|
713
|
+
]);
|
|
714
|
+
const aborted = [
|
|
715
|
+
abstractResult,
|
|
716
|
+
overviewResult
|
|
717
|
+
].find((result)=>!result.ok && isAbort(result.cause));
|
|
718
|
+
if (aborted && !aborted.ok) throw aborted.cause;
|
|
719
|
+
if (!abstractResult.ok && !overviewResult.ok) throw abstractResult.cause;
|
|
720
|
+
const reason = (result)=>result.ok ? void 0 : result.cause instanceof Error ? result.cause.message : String(result.cause);
|
|
721
|
+
return {
|
|
722
|
+
abstract: abstractResult.ok ? abstractResult.text : '',
|
|
723
|
+
overview: overviewResult.ok ? overviewResult.text : '',
|
|
724
|
+
abstractError: reason(abstractResult),
|
|
725
|
+
overviewError: reason(overviewResult)
|
|
726
|
+
};
|
|
727
|
+
}
|
|
614
728
|
const BINARY_EXTENSIONS = new Set([
|
|
615
729
|
'png',
|
|
616
730
|
'jpg',
|
|
@@ -694,38 +808,152 @@ function toBinaryTab(uri, name, file, icon, openParent) {
|
|
|
694
808
|
}
|
|
695
809
|
};
|
|
696
810
|
}
|
|
697
|
-
|
|
698
|
-
|
|
811
|
+
const LINE_BREAK_CODES = new Set([
|
|
812
|
+
0x0a,
|
|
813
|
+
0x0b,
|
|
814
|
+
0x0c,
|
|
815
|
+
0x0d,
|
|
816
|
+
0x1c,
|
|
817
|
+
0x1d,
|
|
818
|
+
0x1e,
|
|
819
|
+
0x85,
|
|
820
|
+
0x2028,
|
|
821
|
+
0x2029
|
|
822
|
+
]);
|
|
823
|
+
function splitLines(text) {
|
|
824
|
+
if (!text) return [];
|
|
825
|
+
const lines = [];
|
|
826
|
+
let start = 0;
|
|
827
|
+
for(let index = 0; index < text.length; index++){
|
|
828
|
+
if (!LINE_BREAK_CODES.has(text.charCodeAt(index))) continue;
|
|
829
|
+
const paired = 0x0d === text.charCodeAt(index) && 0x0a === text.charCodeAt(index + 1);
|
|
830
|
+
const end = index + (paired ? 2 : 1);
|
|
831
|
+
lines.push(text.slice(start, end));
|
|
832
|
+
start = end;
|
|
833
|
+
index = end - 1;
|
|
834
|
+
}
|
|
835
|
+
if (start < text.length) lines.push(text.slice(start));
|
|
836
|
+
return lines;
|
|
837
|
+
}
|
|
838
|
+
function joinLines(lines) {
|
|
839
|
+
return lines.join('');
|
|
840
|
+
}
|
|
841
|
+
const PY_WHITESPACE_CODES = [
|
|
842
|
+
0x09,
|
|
843
|
+
0x0a,
|
|
844
|
+
0x0b,
|
|
845
|
+
0x0c,
|
|
846
|
+
0x0d,
|
|
847
|
+
0x1c,
|
|
848
|
+
0x1d,
|
|
849
|
+
0x1e,
|
|
850
|
+
0x1f,
|
|
851
|
+
0x20,
|
|
852
|
+
0x85,
|
|
853
|
+
0xa0,
|
|
854
|
+
0x1680,
|
|
855
|
+
0x2000,
|
|
856
|
+
0x2001,
|
|
857
|
+
0x2002,
|
|
858
|
+
0x2003,
|
|
859
|
+
0x2004,
|
|
860
|
+
0x2005,
|
|
861
|
+
0x2006,
|
|
862
|
+
0x2007,
|
|
863
|
+
0x2008,
|
|
864
|
+
0x2009,
|
|
865
|
+
0x200a,
|
|
866
|
+
0x2028,
|
|
867
|
+
0x2029,
|
|
868
|
+
0x202f,
|
|
869
|
+
0x205f,
|
|
870
|
+
0x3000
|
|
871
|
+
];
|
|
872
|
+
const PY_WHITESPACE = String.fromCharCode(...PY_WHITESPACE_CODES);
|
|
873
|
+
const PY_WORD = '\\p{L}\\p{N}_';
|
|
874
|
+
const MEMORY_FIELDS_COMMENT = new RegExp(`<!--[${PY_WHITESPACE}]*MEMORY_FIELDS(?![${PY_WORD}])[\\s\\S]*?[${PY_WHITESPACE}]*-->`, 'gu');
|
|
875
|
+
function isPythonBlank(text) {
|
|
876
|
+
for (const char of text)if (!PY_WHITESPACE.includes(char)) return false;
|
|
877
|
+
return true;
|
|
878
|
+
}
|
|
879
|
+
function trimPythonEnd(text) {
|
|
880
|
+
let end = text.length;
|
|
881
|
+
while(end > 0 && PY_WHITESPACE.includes(text[end - 1] ?? ''))end--;
|
|
882
|
+
return text.slice(0, end);
|
|
883
|
+
}
|
|
884
|
+
function uriParts(uri) {
|
|
885
|
+
const [beforeQuery = ''] = uri.split('?');
|
|
886
|
+
const path = beforeQuery.replace(/\/+$/, '');
|
|
887
|
+
if (!path.startsWith('viking://')) return [];
|
|
888
|
+
return path.slice(9).split('/').filter(Boolean);
|
|
889
|
+
}
|
|
890
|
+
function isMemoryUri(uri) {
|
|
891
|
+
const parts = uriParts(uri);
|
|
892
|
+
if (parts.length < 3) return false;
|
|
893
|
+
if ('user' !== parts[0] && '~' !== parts[0]) return false;
|
|
894
|
+
const scoped = '~' === parts[0] ? [
|
|
895
|
+
'user',
|
|
896
|
+
'~',
|
|
897
|
+
...parts.slice(1)
|
|
898
|
+
] : parts;
|
|
899
|
+
if ('memories' === scoped[2]) return true;
|
|
900
|
+
return scoped.length >= 5 && 'peers' === scoped[2] && 'memories' === scoped[4];
|
|
901
|
+
}
|
|
902
|
+
function stripMemoryFieldsTrailer(text) {
|
|
903
|
+
let visible = text;
|
|
904
|
+
for(;;){
|
|
905
|
+
let start = -1;
|
|
906
|
+
MEMORY_FIELDS_COMMENT.lastIndex = 0;
|
|
907
|
+
let match;
|
|
908
|
+
while(null !== (match = MEMORY_FIELDS_COMMENT.exec(visible))){
|
|
909
|
+
const after = visible.slice(match.index + match[0].length);
|
|
910
|
+
if (isPythonBlank(after)) start = match.index;
|
|
911
|
+
}
|
|
912
|
+
if (start < 0) return visible;
|
|
913
|
+
visible = trimPythonEnd(visible.slice(0, start));
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
const MAX_LINES = 2000;
|
|
917
|
+
async function readFile(client, uri, options, openParent) {
|
|
918
|
+
const name = nameFromUri(uri);
|
|
919
|
+
const icon = fileTypeIcon(name);
|
|
920
|
+
if (isBinaryFile(name)) {
|
|
921
|
+
const blob = await client.request({
|
|
699
922
|
method: 'GET',
|
|
700
|
-
path,
|
|
923
|
+
path: OV_PATHS.contentDownload,
|
|
701
924
|
query: {
|
|
702
925
|
uri
|
|
703
926
|
},
|
|
927
|
+
responseType: 'blob',
|
|
704
928
|
options
|
|
705
|
-
})
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
const
|
|
723
|
-
return {
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
929
|
+
});
|
|
930
|
+
const typed = new Blob([
|
|
931
|
+
blob
|
|
932
|
+
], {
|
|
933
|
+
type: mimeTypeOf(name)
|
|
934
|
+
});
|
|
935
|
+
return toBinaryTab(uri, name, typed, icon, openParent);
|
|
936
|
+
}
|
|
937
|
+
const read = (limit)=>client.request({
|
|
938
|
+
method: 'GET',
|
|
939
|
+
path: OV_PATHS.contentRead,
|
|
940
|
+
query: {
|
|
941
|
+
uri,
|
|
942
|
+
limit
|
|
943
|
+
},
|
|
944
|
+
options
|
|
945
|
+
}).then((value)=>'string' == typeof value ? value : '');
|
|
946
|
+
const first = await read(MAX_LINES);
|
|
947
|
+
if (!isMemoryUri(uri)) return toFileTab({
|
|
948
|
+
uri
|
|
949
|
+
}, first, MAX_LINES, icon, openParent, splitLines(first).length >= MAX_LINES);
|
|
950
|
+
const full = splitLines(first).length < MAX_LINES ? first : await read(-1);
|
|
951
|
+
const lines = splitLines(stripMemoryFieldsTrailer(full));
|
|
952
|
+
const truncated = lines.length > MAX_LINES;
|
|
953
|
+
const visible = joinLines(truncated ? lines.slice(0, MAX_LINES) : lines);
|
|
954
|
+
return toFileTab({
|
|
955
|
+
uri
|
|
956
|
+
}, visible, MAX_LINES, icon, openParent, truncated);
|
|
729
957
|
}
|
|
730
958
|
async function resolveIsDirectory(client, uri, options) {
|
|
731
959
|
try {
|
|
@@ -747,7 +975,6 @@ function abortError() {
|
|
|
747
975
|
error.name = 'AbortError';
|
|
748
976
|
return error;
|
|
749
977
|
}
|
|
750
|
-
const MAX_LINES = 2000;
|
|
751
978
|
function useFsPreview({ client, uri, resourceType = 'file', labels = resolveSummaryLabels('en-US'), formatCharacterCount = resolveLabels(void 0, 'en-US').formatCharacterCount, openParent, generation = 0, requestOptions }) {
|
|
752
979
|
const [directory, setDirectory] = useState(null);
|
|
753
980
|
const [tabs, setTabs] = useState(null);
|
|
@@ -866,39 +1093,6 @@ function loadingTab(uri, isDirectory) {
|
|
|
866
1093
|
}
|
|
867
1094
|
};
|
|
868
1095
|
}
|
|
869
|
-
async function readFile(client, uri, options, openParent) {
|
|
870
|
-
const name = nameFromUri(uri);
|
|
871
|
-
const icon = fileTypeIcon(name);
|
|
872
|
-
if (isBinaryFile(name)) {
|
|
873
|
-
const blob = await client.request({
|
|
874
|
-
method: 'GET',
|
|
875
|
-
path: OV_PATHS.contentDownload,
|
|
876
|
-
query: {
|
|
877
|
-
uri
|
|
878
|
-
},
|
|
879
|
-
responseType: 'blob',
|
|
880
|
-
options
|
|
881
|
-
});
|
|
882
|
-
const typed = new Blob([
|
|
883
|
-
blob
|
|
884
|
-
], {
|
|
885
|
-
type: mimeTypeOf(name)
|
|
886
|
-
});
|
|
887
|
-
return toBinaryTab(uri, name, typed, icon, openParent);
|
|
888
|
-
}
|
|
889
|
-
const content = await client.request({
|
|
890
|
-
method: 'GET',
|
|
891
|
-
path: OV_PATHS.contentRead,
|
|
892
|
-
query: {
|
|
893
|
-
uri,
|
|
894
|
-
limit: MAX_LINES
|
|
895
|
-
},
|
|
896
|
-
options
|
|
897
|
-
});
|
|
898
|
-
return toFileTab({
|
|
899
|
-
uri
|
|
900
|
-
}, 'string' == typeof content ? content : '', MAX_LINES, icon, openParent);
|
|
901
|
-
}
|
|
902
1096
|
function mergeFindResult(result) {
|
|
903
1097
|
const seen = new Set();
|
|
904
1098
|
const entries = [];
|
|
@@ -970,6 +1164,659 @@ function useFsSearch({ client, query, targetUri, generation = 0, requestOptions
|
|
|
970
1164
|
error
|
|
971
1165
|
};
|
|
972
1166
|
}
|
|
1167
|
+
const isHomeUri = (uri)=>'viking://~' === uri || uri.startsWith('viking://~/');
|
|
1168
|
+
async function readDashboardStat(client, uri, options) {
|
|
1169
|
+
const stat = await client.request({
|
|
1170
|
+
method: 'GET',
|
|
1171
|
+
path: OV_PATHS.fsStat,
|
|
1172
|
+
query: {
|
|
1173
|
+
uri
|
|
1174
|
+
},
|
|
1175
|
+
options
|
|
1176
|
+
});
|
|
1177
|
+
const canonical = stat?.uri ?? uri;
|
|
1178
|
+
if ('boolean' != typeof stat?.isDir || 'string' != typeof canonical || !canonical || isHomeUri(canonical)) throw new TypeError('Invalid canonical resource stat');
|
|
1179
|
+
return {
|
|
1180
|
+
uri: canonical,
|
|
1181
|
+
isDir: stat.isDir
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
async function resolveDashboardUri(client, uri, options) {
|
|
1185
|
+
return isHomeUri(uri) ? (await readDashboardStat(client, uri, options)).uri : uri;
|
|
1186
|
+
}
|
|
1187
|
+
async function readDashboardHint(client, uri, options) {
|
|
1188
|
+
const result = await client.request({
|
|
1189
|
+
method: 'GET',
|
|
1190
|
+
path: OV_PATHS.fsAttrs,
|
|
1191
|
+
query: {
|
|
1192
|
+
uri
|
|
1193
|
+
},
|
|
1194
|
+
options
|
|
1195
|
+
});
|
|
1196
|
+
return {
|
|
1197
|
+
uri: await resolveDashboardUri(client, result?.uri ?? uri, options),
|
|
1198
|
+
tags: result?.attrs?.tags ?? []
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
const EXPERIENCE_PAGE_SIZE = 20;
|
|
1202
|
+
const isExperienceDirectory = (uri)=>/^viking:\/\/(?:user\/[^/]+|~)\/memories\/experiences\/?$/.test(uri);
|
|
1203
|
+
const isExperienceFile = (uri)=>/^viking:\/\/(?:user\/[^/]+|~)\/memories\/experiences\/[^/]+\.md$/i.test(uri);
|
|
1204
|
+
function experienceDateRange(days, now = new Date()) {
|
|
1205
|
+
if (!days) return {};
|
|
1206
|
+
const start = new Date(now);
|
|
1207
|
+
start.setUTCDate(start.getUTCDate() - days + 1);
|
|
1208
|
+
return {
|
|
1209
|
+
start_date: start.toISOString().slice(0, 10),
|
|
1210
|
+
end_date: now.toISOString().slice(0, 10)
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
async function readExperiences(client, uri, page, options) {
|
|
1214
|
+
uri = await resolveDashboardUri(client, uri, options);
|
|
1215
|
+
const result = await client.requestEnvelope({
|
|
1216
|
+
method: 'GET',
|
|
1217
|
+
path: OV_PATHS.fsLs,
|
|
1218
|
+
query: {
|
|
1219
|
+
uri,
|
|
1220
|
+
output: 'original',
|
|
1221
|
+
limit: EXPERIENCE_PAGE_SIZE,
|
|
1222
|
+
offset: page * EXPERIENCE_PAGE_SIZE,
|
|
1223
|
+
sort_by: 'mtime',
|
|
1224
|
+
sort_order: 'desc'
|
|
1225
|
+
},
|
|
1226
|
+
options
|
|
1227
|
+
});
|
|
1228
|
+
if (!Array.isArray(result.result)) throw new TypeError('Invalid Experience listing');
|
|
1229
|
+
const prefix = `${uri.replace(/\/+$/, '')}/`;
|
|
1230
|
+
return {
|
|
1231
|
+
items: result.result.filter((item)=>!item.isDir && item.uri.startsWith(prefix) && isExperienceFile(item.uri)),
|
|
1232
|
+
hasMore: result.hasMore
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
async function readExperienceSources(client, uri, options) {
|
|
1236
|
+
uri = await resolveDashboardUri(client, uri, options);
|
|
1237
|
+
const result = await client.request({
|
|
1238
|
+
method: 'GET',
|
|
1239
|
+
path: OV_PATHS.fsAttrs,
|
|
1240
|
+
query: {
|
|
1241
|
+
uri
|
|
1242
|
+
},
|
|
1243
|
+
options
|
|
1244
|
+
});
|
|
1245
|
+
const links = result?.attrs?.memory?.links;
|
|
1246
|
+
if (void 0 !== links && !Array.isArray(links)) throw new TypeError('Invalid Experience links');
|
|
1247
|
+
const prefix = uri.slice(0, uri.indexOf('/memories/experiences/')) + '/memories/trajectories/';
|
|
1248
|
+
const seen = new Set();
|
|
1249
|
+
return (links ?? []).flatMap((link)=>{
|
|
1250
|
+
if ('derived_from' !== link.link_type || 'string' != typeof link.to_uri || !link.to_uri.startsWith(prefix) || seen.has(link.to_uri)) return [];
|
|
1251
|
+
seen.add(link.to_uri);
|
|
1252
|
+
return [
|
|
1253
|
+
{
|
|
1254
|
+
uri: link.to_uri,
|
|
1255
|
+
name: link.to_uri.split('/').pop() ?? link.to_uri,
|
|
1256
|
+
description: link.description ?? link.match_text
|
|
1257
|
+
}
|
|
1258
|
+
];
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
const dashboardKey = (uri)=>`dashboard:${uri}`;
|
|
1262
|
+
const within = (uri, root)=>uri === root || uri.startsWith(`${root.replace(/\/+$/, '')}/`);
|
|
1263
|
+
function resolveDashboard(uri, rows, targets) {
|
|
1264
|
+
if (isExperienceDirectory(uri) || isExperienceFile(uri)) return {
|
|
1265
|
+
kind: 'experience',
|
|
1266
|
+
uri
|
|
1267
|
+
};
|
|
1268
|
+
const entries = rows.filter((row)=>'entry' === row.kind);
|
|
1269
|
+
const row = entries.find((item)=>item.uri === uri);
|
|
1270
|
+
const hasWiki = entries.some((item)=>item.tags?.includes('compile_target=true') && within(uri, item.uri));
|
|
1271
|
+
const owner = targets.filter((item)=>within(uri, item.to)).sort((a, b)=>b.to.length - a.to.length)[0];
|
|
1272
|
+
if (!hasWiki && !owner) return;
|
|
1273
|
+
const tagged = row?.tags?.find((tag)=>tag.startsWith('has_conflict='));
|
|
1274
|
+
return {
|
|
1275
|
+
kind: 'wiki',
|
|
1276
|
+
uri,
|
|
1277
|
+
isRoot: Boolean(row?.tags?.includes('compile_target=true') || owner?.to === uri),
|
|
1278
|
+
pendingConflicts: tagged ? 'has_conflict=true' === tagged : owner?.to === uri && void 0 !== owner.conflicts_num ? owner.conflicts_num > 0 : void 0
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
async function readCompileTargets(client, rootUri, options) {
|
|
1282
|
+
rootUri = await resolveDashboardUri(client, rootUri, options);
|
|
1283
|
+
const targets = [];
|
|
1284
|
+
let cursor;
|
|
1285
|
+
const seen = new Set();
|
|
1286
|
+
do {
|
|
1287
|
+
const result = await client.request({
|
|
1288
|
+
method: 'GET',
|
|
1289
|
+
path: OV_PATHS.compileConfigs,
|
|
1290
|
+
query: {
|
|
1291
|
+
limit: 100,
|
|
1292
|
+
cursor
|
|
1293
|
+
},
|
|
1294
|
+
options
|
|
1295
|
+
});
|
|
1296
|
+
if (!Array.isArray(result?.targets)) throw new TypeError('Invalid Compile target registry');
|
|
1297
|
+
targets.push(...result.targets.filter((item)=>'string' == typeof item.to && 'memory' !== item.compile_type && false !== item.initialized && (within(item.to, rootUri) || within(rootUri, item.to))));
|
|
1298
|
+
cursor = result.next_cursor ?? void 0;
|
|
1299
|
+
if (cursor && seen.has(cursor)) throw new TypeError('Compile target cursor did not advance');
|
|
1300
|
+
if (cursor) seen.add(cursor);
|
|
1301
|
+
}while (cursor)
|
|
1302
|
+
return targets;
|
|
1303
|
+
}
|
|
1304
|
+
function useDashboardQuery(load, requestOptions, enabled = true, refreshGeneration = 0) {
|
|
1305
|
+
const client = useOvClient();
|
|
1306
|
+
const inheritedSignal = useOvSignal();
|
|
1307
|
+
const { baseURL, apiKey, accountId, userId, resourceId, signal } = requestOptions ?? {};
|
|
1308
|
+
const [generation, setGeneration] = useState(0);
|
|
1309
|
+
const [state, setState] = useState({
|
|
1310
|
+
owner: [],
|
|
1311
|
+
error: null
|
|
1312
|
+
});
|
|
1313
|
+
const owner = useMemo(()=>[
|
|
1314
|
+
client,
|
|
1315
|
+
load,
|
|
1316
|
+
baseURL,
|
|
1317
|
+
apiKey,
|
|
1318
|
+
accountId,
|
|
1319
|
+
userId,
|
|
1320
|
+
resourceId,
|
|
1321
|
+
signal,
|
|
1322
|
+
inheritedSignal,
|
|
1323
|
+
generation,
|
|
1324
|
+
enabled,
|
|
1325
|
+
refreshGeneration
|
|
1326
|
+
], [
|
|
1327
|
+
client,
|
|
1328
|
+
load,
|
|
1329
|
+
baseURL,
|
|
1330
|
+
apiKey,
|
|
1331
|
+
accountId,
|
|
1332
|
+
userId,
|
|
1333
|
+
resourceId,
|
|
1334
|
+
signal,
|
|
1335
|
+
inheritedSignal,
|
|
1336
|
+
generation,
|
|
1337
|
+
enabled,
|
|
1338
|
+
refreshGeneration
|
|
1339
|
+
]);
|
|
1340
|
+
const current = owner.every((value, i)=>value === state.owner[i]);
|
|
1341
|
+
useEffect(()=>{
|
|
1342
|
+
if (!enabled) return;
|
|
1343
|
+
if (!client) return void setState({
|
|
1344
|
+
owner,
|
|
1345
|
+
error: new Error('OpenVikingProvider is required')
|
|
1346
|
+
});
|
|
1347
|
+
const controller = new AbortController();
|
|
1348
|
+
const signals = [
|
|
1349
|
+
controller.signal,
|
|
1350
|
+
signal,
|
|
1351
|
+
inheritedSignal
|
|
1352
|
+
].filter((value)=>Boolean(value));
|
|
1353
|
+
const options = {
|
|
1354
|
+
baseURL,
|
|
1355
|
+
apiKey,
|
|
1356
|
+
accountId,
|
|
1357
|
+
userId,
|
|
1358
|
+
resourceId,
|
|
1359
|
+
signal: AbortSignal.any(signals)
|
|
1360
|
+
};
|
|
1361
|
+
load(client, options).then((data)=>{
|
|
1362
|
+
if (!options.signal.aborted) setState({
|
|
1363
|
+
owner,
|
|
1364
|
+
data,
|
|
1365
|
+
error: null
|
|
1366
|
+
});
|
|
1367
|
+
}, (cause)=>{
|
|
1368
|
+
if (!options.signal.aborted) setState({
|
|
1369
|
+
owner,
|
|
1370
|
+
error: cause instanceof Error ? cause : new Error(String(cause))
|
|
1371
|
+
});
|
|
1372
|
+
});
|
|
1373
|
+
return ()=>controller.abort();
|
|
1374
|
+
}, [
|
|
1375
|
+
client,
|
|
1376
|
+
load,
|
|
1377
|
+
baseURL,
|
|
1378
|
+
apiKey,
|
|
1379
|
+
accountId,
|
|
1380
|
+
userId,
|
|
1381
|
+
resourceId,
|
|
1382
|
+
signal,
|
|
1383
|
+
inheritedSignal,
|
|
1384
|
+
generation,
|
|
1385
|
+
enabled,
|
|
1386
|
+
owner
|
|
1387
|
+
]);
|
|
1388
|
+
return {
|
|
1389
|
+
data: current ? state.data : void 0,
|
|
1390
|
+
loading: enabled && !current,
|
|
1391
|
+
error: current ? state.error : null,
|
|
1392
|
+
retry: ()=>setGeneration((value)=>value + 1)
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
function useExperienceDashboard({ uri, requestOptions, enabled = true, refreshGeneration = 0 }) {
|
|
1396
|
+
const client = useOvClient();
|
|
1397
|
+
const signal = useOvSignal();
|
|
1398
|
+
const owner = useMemo(()=>[
|
|
1399
|
+
uri,
|
|
1400
|
+
client,
|
|
1401
|
+
signal,
|
|
1402
|
+
requestOptions?.baseURL,
|
|
1403
|
+
requestOptions?.apiKey,
|
|
1404
|
+
requestOptions?.accountId,
|
|
1405
|
+
requestOptions?.userId,
|
|
1406
|
+
requestOptions?.resourceId
|
|
1407
|
+
], [
|
|
1408
|
+
uri,
|
|
1409
|
+
client,
|
|
1410
|
+
signal,
|
|
1411
|
+
requestOptions?.baseURL,
|
|
1412
|
+
requestOptions?.apiKey,
|
|
1413
|
+
requestOptions?.accountId,
|
|
1414
|
+
requestOptions?.userId,
|
|
1415
|
+
requestOptions?.resourceId
|
|
1416
|
+
]);
|
|
1417
|
+
const [state, setState] = useState({
|
|
1418
|
+
owner,
|
|
1419
|
+
page: 0,
|
|
1420
|
+
days: 7,
|
|
1421
|
+
tab: 'impact'
|
|
1422
|
+
});
|
|
1423
|
+
const current = state.owner === owner ? state : {
|
|
1424
|
+
owner,
|
|
1425
|
+
page: 0,
|
|
1426
|
+
days: 7,
|
|
1427
|
+
tab: 'impact'
|
|
1428
|
+
};
|
|
1429
|
+
const { page, days, tab } = current;
|
|
1430
|
+
const setPage = (value)=>setState({
|
|
1431
|
+
...current,
|
|
1432
|
+
page: Math.max(0, value)
|
|
1433
|
+
});
|
|
1434
|
+
const setDays = (value)=>setState({
|
|
1435
|
+
...current,
|
|
1436
|
+
days: value,
|
|
1437
|
+
page: 0
|
|
1438
|
+
});
|
|
1439
|
+
const setTab = (value)=>setState({
|
|
1440
|
+
...current,
|
|
1441
|
+
tab: value,
|
|
1442
|
+
page: 0
|
|
1443
|
+
});
|
|
1444
|
+
const directory = isExperienceDirectory(uri);
|
|
1445
|
+
const loadList = useCallback((client, options)=>readExperiences(client, uri, page, options), [
|
|
1446
|
+
uri,
|
|
1447
|
+
page
|
|
1448
|
+
]);
|
|
1449
|
+
const loadSources = useCallback((client, options)=>readExperienceSources(client, uri, options), [
|
|
1450
|
+
uri
|
|
1451
|
+
]);
|
|
1452
|
+
const loadTrajectories = useCallback(async (client, options)=>{
|
|
1453
|
+
const result = await client.request({
|
|
1454
|
+
method: 'GET',
|
|
1455
|
+
path: OV_PATHS.experienceTrajectories,
|
|
1456
|
+
query: {
|
|
1457
|
+
experience_uri: uri,
|
|
1458
|
+
offset: 20 * page,
|
|
1459
|
+
limit: 20,
|
|
1460
|
+
...experienceDateRange(days)
|
|
1461
|
+
},
|
|
1462
|
+
options
|
|
1463
|
+
});
|
|
1464
|
+
if (!Array.isArray(result?.items) || !Number.isSafeInteger(result.total) || result.total < 0 || result.items.some((item)=>'string' != typeof item?.uri || 'string' != typeof item.name)) throw new TypeError('Invalid Experience trajectories');
|
|
1465
|
+
return result;
|
|
1466
|
+
}, [
|
|
1467
|
+
uri,
|
|
1468
|
+
page,
|
|
1469
|
+
days
|
|
1470
|
+
]);
|
|
1471
|
+
const loadOutcomes = useCallback(async (client, options)=>{
|
|
1472
|
+
const result = await client.request({
|
|
1473
|
+
method: 'GET',
|
|
1474
|
+
path: OV_PATHS.experienceOutcomes,
|
|
1475
|
+
query: {
|
|
1476
|
+
experience_uri: uri,
|
|
1477
|
+
...experienceDateRange(days)
|
|
1478
|
+
},
|
|
1479
|
+
options
|
|
1480
|
+
});
|
|
1481
|
+
if (!Array.isArray(result?.outcome_distribution) || result.outcome_distribution.some((entry)=>![
|
|
1482
|
+
'success',
|
|
1483
|
+
'partial',
|
|
1484
|
+
'unfinished',
|
|
1485
|
+
'failure',
|
|
1486
|
+
'unknown'
|
|
1487
|
+
].includes(entry?.outcome) || !Number.isSafeInteger(entry.count) || entry.count < 0)) throw new TypeError('Invalid Experience outcomes');
|
|
1488
|
+
return result.outcome_distribution;
|
|
1489
|
+
}, [
|
|
1490
|
+
uri,
|
|
1491
|
+
days
|
|
1492
|
+
]);
|
|
1493
|
+
const list = useDashboardQuery(loadList, requestOptions, enabled && directory, refreshGeneration);
|
|
1494
|
+
const sources = useDashboardQuery(loadSources, requestOptions, enabled && !directory && 'source' === tab, refreshGeneration);
|
|
1495
|
+
const trajectories = useDashboardQuery(loadTrajectories, requestOptions, enabled && !directory && 'impact' === tab, refreshGeneration);
|
|
1496
|
+
const outcomes = useDashboardQuery(loadOutcomes, requestOptions, enabled && !directory && 'impact' === tab, refreshGeneration);
|
|
1497
|
+
return {
|
|
1498
|
+
list,
|
|
1499
|
+
sources,
|
|
1500
|
+
trajectories,
|
|
1501
|
+
outcomes,
|
|
1502
|
+
page,
|
|
1503
|
+
setPage,
|
|
1504
|
+
days,
|
|
1505
|
+
setDays,
|
|
1506
|
+
tab,
|
|
1507
|
+
setTab
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
function ExperienceDashboardPane({ uri, locale, requestOptions, refreshGeneration, onOpenUri }) {
|
|
1511
|
+
const browser = useExperienceDashboard({
|
|
1512
|
+
uri,
|
|
1513
|
+
requestOptions,
|
|
1514
|
+
refreshGeneration
|
|
1515
|
+
});
|
|
1516
|
+
const directory = isExperienceDirectory(uri);
|
|
1517
|
+
const status = (query)=>({
|
|
1518
|
+
loading: query.loading,
|
|
1519
|
+
error: query.error,
|
|
1520
|
+
onRetry: query.retry
|
|
1521
|
+
});
|
|
1522
|
+
return /*#__PURE__*/ jsx(ExperienceDashboard, {
|
|
1523
|
+
uri: uri,
|
|
1524
|
+
kind: directory ? 'directory' : 'file',
|
|
1525
|
+
locale: locale,
|
|
1526
|
+
onOpenUri: onOpenUri,
|
|
1527
|
+
data: {
|
|
1528
|
+
experiences: browser.list.data?.items,
|
|
1529
|
+
outcomes: browser.outcomes.data,
|
|
1530
|
+
trajectories: browser.trajectories.data?.items,
|
|
1531
|
+
trajectoryTotal: browser.trajectories.data?.total,
|
|
1532
|
+
sources: browser.sources.data
|
|
1533
|
+
},
|
|
1534
|
+
tab: browser.tab,
|
|
1535
|
+
days: browser.days,
|
|
1536
|
+
page: browser.page,
|
|
1537
|
+
startIndex: 20 * browser.page,
|
|
1538
|
+
hasMore: Boolean(directory ? browser.list.data?.hasMore : 'impact' === browser.tab && browser.trajectories.data?.has_more),
|
|
1539
|
+
states: {
|
|
1540
|
+
list: status(browser.list),
|
|
1541
|
+
sources: status(browser.sources),
|
|
1542
|
+
outcomes: status(browser.outcomes),
|
|
1543
|
+
trajectories: status(browser.trajectories)
|
|
1544
|
+
},
|
|
1545
|
+
onTabChange: browser.setTab,
|
|
1546
|
+
onDaysChange: browser.setDays,
|
|
1547
|
+
onPageChange: browser.setPage
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
const wiki_conflicts_prefix = '<!-- CONFLICTS_CONTENT';
|
|
1551
|
+
const manualResolutionBasis = '\u4eba\u5de5\u4fee\u590d';
|
|
1552
|
+
const timestamp = (value)=>'number' == typeof value && Number.isSafeInteger(value) && value >= 0 && Number.isFinite(new Date(1000 * value).getTime());
|
|
1553
|
+
const locateWikiConflict = (document, matchText)=>{
|
|
1554
|
+
const mask = (value)=>value.replace(/[^\r\n]/g, ' ');
|
|
1555
|
+
const body = document.replace(/^(?:\uFEFF)?---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/, mask).replace(/<!--[\s\S]*?(?:-->|$)/g, mask);
|
|
1556
|
+
const start = matchText ? body.indexOf(matchText) : -1;
|
|
1557
|
+
if (start < 0) return {
|
|
1558
|
+
status: 'missing'
|
|
1559
|
+
};
|
|
1560
|
+
if (body.indexOf(matchText, start + 1) >= 0) return {
|
|
1561
|
+
status: 'ambiguous'
|
|
1562
|
+
};
|
|
1563
|
+
return {
|
|
1564
|
+
status: 'unique',
|
|
1565
|
+
start,
|
|
1566
|
+
end: start + matchText.length,
|
|
1567
|
+
line: document.slice(0, start).split('\n').length
|
|
1568
|
+
};
|
|
1569
|
+
};
|
|
1570
|
+
const parseWikiFileConflicts = (content)=>{
|
|
1571
|
+
const start = content.lastIndexOf(wiki_conflicts_prefix);
|
|
1572
|
+
if (start < 0) return {
|
|
1573
|
+
status: 'missing'
|
|
1574
|
+
};
|
|
1575
|
+
const footer = content.slice(start).trimEnd();
|
|
1576
|
+
if (!footer.endsWith('-->')) return {
|
|
1577
|
+
status: 'invalid'
|
|
1578
|
+
};
|
|
1579
|
+
const document = content.slice(0, start);
|
|
1580
|
+
const source = footer.slice(wiki_conflicts_prefix.length, -3).trim();
|
|
1581
|
+
let parsed;
|
|
1582
|
+
try {
|
|
1583
|
+
parsed = source ? JSON.parse(`[${source}]`) : [];
|
|
1584
|
+
} catch {
|
|
1585
|
+
return {
|
|
1586
|
+
status: 'invalid'
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
if (!Array.isArray(parsed)) return {
|
|
1590
|
+
status: 'invalid'
|
|
1591
|
+
};
|
|
1592
|
+
const records = [];
|
|
1593
|
+
for (const [index, raw] of parsed.entries()){
|
|
1594
|
+
if (!raw || 'object' != typeof raw || Array.isArray(raw)) return {
|
|
1595
|
+
status: 'invalid'
|
|
1596
|
+
};
|
|
1597
|
+
const value = raw;
|
|
1598
|
+
if ('string' != typeof value.match_text || !value.match_text || 'string' != typeof value.problem_description || 'string' != typeof value.reason || ![
|
|
1599
|
+
'high',
|
|
1600
|
+
'medium',
|
|
1601
|
+
'low'
|
|
1602
|
+
].includes(value.severity) || ![
|
|
1603
|
+
'unfixed',
|
|
1604
|
+
'fixed'
|
|
1605
|
+
].includes(value.state) || !timestamp(value.begin_time) || 'string' != typeof value.fix_plan || 'string' != typeof value.resolution_basis) return {
|
|
1606
|
+
status: 'invalid'
|
|
1607
|
+
};
|
|
1608
|
+
if ('fixed' === value.state ? !timestamp(value.fix_time) || value.fix_time < value.begin_time : null !== value.fix_time) return {
|
|
1609
|
+
status: 'invalid'
|
|
1610
|
+
};
|
|
1611
|
+
const matchText = value.match_text;
|
|
1612
|
+
const location = locateWikiConflict(document, matchText);
|
|
1613
|
+
records.push({
|
|
1614
|
+
id: JSON.stringify([
|
|
1615
|
+
index,
|
|
1616
|
+
value.begin_time,
|
|
1617
|
+
matchText
|
|
1618
|
+
]),
|
|
1619
|
+
matchText,
|
|
1620
|
+
description: value.problem_description,
|
|
1621
|
+
reason: value.reason,
|
|
1622
|
+
severity: value.severity,
|
|
1623
|
+
state: value.state,
|
|
1624
|
+
beginTime: value.begin_time,
|
|
1625
|
+
fixTime: value.fix_time,
|
|
1626
|
+
fixPlan: value.fix_plan,
|
|
1627
|
+
resolutionBasis: value.resolution_basis,
|
|
1628
|
+
resolutionSource: 'fixed' === value.state && value.resolution_basis.trim() ? value.resolution_basis.trim() === manualResolutionBasis ? 'manual' : 'automatic' : void 0,
|
|
1629
|
+
location
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1632
|
+
return {
|
|
1633
|
+
status: 'available',
|
|
1634
|
+
document,
|
|
1635
|
+
records
|
|
1636
|
+
};
|
|
1637
|
+
};
|
|
1638
|
+
async function readWikiDashboard(client, uri, options) {
|
|
1639
|
+
const stat = await readDashboardStat(client, uri, options);
|
|
1640
|
+
uri = stat.uri;
|
|
1641
|
+
if (!stat.isDir) {
|
|
1642
|
+
const result = await client.request({
|
|
1643
|
+
method: 'GET',
|
|
1644
|
+
path: OV_PATHS.contentRead,
|
|
1645
|
+
query: {
|
|
1646
|
+
uri,
|
|
1647
|
+
limit: -1
|
|
1648
|
+
},
|
|
1649
|
+
options
|
|
1650
|
+
});
|
|
1651
|
+
if ('string' != typeof result) throw new TypeError('Invalid Wiki content response');
|
|
1652
|
+
const parsed = parseWikiFileConflicts(result);
|
|
1653
|
+
if ('invalid' === parsed.status) throw new TypeError('Invalid CONFLICTS_CONTENT metadata');
|
|
1654
|
+
return {
|
|
1655
|
+
kind: 'file',
|
|
1656
|
+
data: {
|
|
1657
|
+
path: uri,
|
|
1658
|
+
conflicts: 'available' === parsed.status ? parsed.records : []
|
|
1659
|
+
}
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
const page = await client.requestEnvelope({
|
|
1663
|
+
method: 'GET',
|
|
1664
|
+
path: OV_PATHS.fsLs,
|
|
1665
|
+
query: {
|
|
1666
|
+
uri,
|
|
1667
|
+
recursive: true,
|
|
1668
|
+
output: 'agent',
|
|
1669
|
+
tags: [
|
|
1670
|
+
'has_conflict=true'
|
|
1671
|
+
],
|
|
1672
|
+
limit: 100,
|
|
1673
|
+
sort_by: 'mtime',
|
|
1674
|
+
sort_order: 'desc'
|
|
1675
|
+
},
|
|
1676
|
+
options
|
|
1677
|
+
});
|
|
1678
|
+
if (!Array.isArray(page.result)) throw new TypeError('Invalid Wiki conflict listing');
|
|
1679
|
+
const prefix = `${uri.replace(/\/+$/, '')}/`;
|
|
1680
|
+
const files = page.result.filter((entry)=>!entry.isDir && entry.uri.startsWith(prefix)).map((entry)=>entry.uri);
|
|
1681
|
+
return {
|
|
1682
|
+
kind: 'directory',
|
|
1683
|
+
data: {
|
|
1684
|
+
files,
|
|
1685
|
+
conflictFileCount: files.length,
|
|
1686
|
+
limited: page.hasMore || files.length >= 100
|
|
1687
|
+
}
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
function useWikiDashboard({ uri, requestOptions, enabled = true, refreshGeneration = 0 }) {
|
|
1691
|
+
const load = useCallback((client, options)=>readWikiDashboard(client, uri, options), [
|
|
1692
|
+
uri
|
|
1693
|
+
]);
|
|
1694
|
+
return useDashboardQuery(load, requestOptions, enabled, refreshGeneration);
|
|
1695
|
+
}
|
|
1696
|
+
function WikiDashboardPane({ uri, kind, requestOptions, refreshGeneration, onOpenUri, onOpenDashboard, onEdit, onDiscuss, ...props }) {
|
|
1697
|
+
const query = useWikiDashboard({
|
|
1698
|
+
uri,
|
|
1699
|
+
requestOptions,
|
|
1700
|
+
refreshGeneration
|
|
1701
|
+
});
|
|
1702
|
+
const common = {
|
|
1703
|
+
...props,
|
|
1704
|
+
loading: query.loading,
|
|
1705
|
+
error: query.error,
|
|
1706
|
+
onRetry: query.retry
|
|
1707
|
+
};
|
|
1708
|
+
if ((query.data?.kind ?? kind) === 'file') return /*#__PURE__*/ createElement(WikiDashboard, {
|
|
1709
|
+
...common,
|
|
1710
|
+
key: uri,
|
|
1711
|
+
kind: "file",
|
|
1712
|
+
data: query.data?.kind === 'file' ? query.data.data : void 0,
|
|
1713
|
+
onOpenUri: onOpenUri && (()=>onOpenUri(uri)),
|
|
1714
|
+
onEdit: onEdit && ((conflict)=>onEdit(uri, conflict)),
|
|
1715
|
+
onDiscuss: onDiscuss && ((conflict)=>onDiscuss(uri, conflict))
|
|
1716
|
+
});
|
|
1717
|
+
return /*#__PURE__*/ createElement(WikiDashboard, {
|
|
1718
|
+
...common,
|
|
1719
|
+
key: uri,
|
|
1720
|
+
kind: "directory",
|
|
1721
|
+
data: query.data?.kind === 'directory' ? query.data.data : void 0,
|
|
1722
|
+
onOpenUri: onOpenUri,
|
|
1723
|
+
onOpenDashboard: onOpenDashboard,
|
|
1724
|
+
onEdit: onEdit
|
|
1725
|
+
});
|
|
1726
|
+
}
|
|
1727
|
+
function useBrowserDashboards({ rows, metadataRows, uri, rootUri, generation, locale, requestOptions, onOpenUri, dashboardKinds, renderDashboard, dashboardLabels }) {
|
|
1728
|
+
const [opened, setOpened] = useState(null);
|
|
1729
|
+
const load = useCallback((client, options)=>readCompileTargets(client, rootUri, options), [
|
|
1730
|
+
rootUri
|
|
1731
|
+
]);
|
|
1732
|
+
const wikiEnabled = void 0 === dashboardKinds || dashboardKinds.includes('wiki');
|
|
1733
|
+
const catalog = useDashboardQuery(load, requestOptions, wikiEnabled, generation);
|
|
1734
|
+
const loadHint = useCallback(async (client, options)=>uri ? readDashboardHint(client, uri, options) : void 0, [
|
|
1735
|
+
uri
|
|
1736
|
+
]);
|
|
1737
|
+
const hint = useDashboardQuery(loadHint, requestOptions, wikiEnabled && Boolean(uri), generation);
|
|
1738
|
+
const canonicalUri = hint.data?.uri ?? uri;
|
|
1739
|
+
const knownRows = canonicalUri && hint.data?.tags.includes('compile_target=true') ? [
|
|
1740
|
+
...metadataRows,
|
|
1741
|
+
{
|
|
1742
|
+
kind: 'entry',
|
|
1743
|
+
uri: canonicalUri,
|
|
1744
|
+
id: canonicalUri,
|
|
1745
|
+
name: canonicalUri,
|
|
1746
|
+
depth: 0,
|
|
1747
|
+
type: 'directory',
|
|
1748
|
+
tags: hint.data.tags
|
|
1749
|
+
}
|
|
1750
|
+
] : metadataRows;
|
|
1751
|
+
const unsupported = isOvClientError(catalog.error) && 404 === catalog.error.statusCode;
|
|
1752
|
+
const targets = catalog.data ?? [];
|
|
1753
|
+
const resolve = (target)=>{
|
|
1754
|
+
const match = resolveDashboard(target === uri ? canonicalUri ?? target : target, knownRows, targets);
|
|
1755
|
+
return match ? {
|
|
1756
|
+
...match,
|
|
1757
|
+
uri: target
|
|
1758
|
+
} : void 0;
|
|
1759
|
+
};
|
|
1760
|
+
const dashboards = new Map(rows.filter((row)=>'entry' === row.kind).flatMap((row)=>{
|
|
1761
|
+
const dashboard = resolve(row.uri);
|
|
1762
|
+
return dashboard && (void 0 === dashboardKinds || dashboardKinds.includes(dashboard.kind)) ? [
|
|
1763
|
+
[
|
|
1764
|
+
row.uri,
|
|
1765
|
+
dashboard
|
|
1766
|
+
]
|
|
1767
|
+
] : [];
|
|
1768
|
+
}));
|
|
1769
|
+
const resolved = uri ? resolve(uri) : void 0;
|
|
1770
|
+
const current = resolved && (void 0 === dashboardKinds || dashboardKinds.includes(resolved.kind)) ? resolved : void 0;
|
|
1771
|
+
const open = useCallback((target)=>{
|
|
1772
|
+
setOpened(target);
|
|
1773
|
+
onOpenUri(target);
|
|
1774
|
+
}, [
|
|
1775
|
+
onOpenUri
|
|
1776
|
+
]);
|
|
1777
|
+
const close = useCallback(()=>setOpened(null), []);
|
|
1778
|
+
const text = dashboard_labels_dashboardLabels(locale, dashboardLabels);
|
|
1779
|
+
const title = current?.kind === 'experience' ? text.experienceTitle : text.wikiTitle;
|
|
1780
|
+
const tab = current && uri ? {
|
|
1781
|
+
key: dashboardKey(uri),
|
|
1782
|
+
title,
|
|
1783
|
+
icon: createElement('experience' === current.kind ? ExperienceBoardIcon : WikiBoardIcon, {
|
|
1784
|
+
width: 14,
|
|
1785
|
+
height: 14
|
|
1786
|
+
}),
|
|
1787
|
+
kind: 'content',
|
|
1788
|
+
content: renderDashboard?.(current) ?? ('experience' === current.kind ? createElement(ExperienceDashboardPane, {
|
|
1789
|
+
uri,
|
|
1790
|
+
locale,
|
|
1791
|
+
requestOptions,
|
|
1792
|
+
refreshGeneration: generation,
|
|
1793
|
+
onOpenUri: (target)=>{
|
|
1794
|
+
setOpened(null);
|
|
1795
|
+
onOpenUri(target);
|
|
1796
|
+
}
|
|
1797
|
+
}) : createElement(WikiDashboardPane, {
|
|
1798
|
+
uri,
|
|
1799
|
+
kind: knownRows.some((row)=>'entry' === row.kind && row.uri === canonicalUri && 'file' === row.type) ? 'file' : 'directory',
|
|
1800
|
+
locale,
|
|
1801
|
+
requestOptions,
|
|
1802
|
+
refreshGeneration: generation,
|
|
1803
|
+
onOpenUri: (target)=>{
|
|
1804
|
+
setOpened(null);
|
|
1805
|
+
onOpenUri(target);
|
|
1806
|
+
},
|
|
1807
|
+
onOpenDashboard: open
|
|
1808
|
+
}))
|
|
1809
|
+
} : void 0;
|
|
1810
|
+
return {
|
|
1811
|
+
dashboards,
|
|
1812
|
+
tab,
|
|
1813
|
+
isOpen: null !== uri && opened === uri && Boolean(current),
|
|
1814
|
+
open,
|
|
1815
|
+
close,
|
|
1816
|
+
error: unsupported ? null : catalog.error,
|
|
1817
|
+
retry: catalog.retry
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
973
1820
|
function knownDirectories(rootUri, dirs) {
|
|
974
1821
|
const known = new Set([
|
|
975
1822
|
rootUri
|
|
@@ -993,6 +1840,21 @@ function useKnownFile(dirs) {
|
|
|
993
1840
|
files
|
|
994
1841
|
]);
|
|
995
1842
|
}
|
|
1843
|
+
function useTreeMetadata(rootUri, dirs) {
|
|
1844
|
+
const directoryUris = useMemo(()=>knownDirectories(rootUri, dirs), [
|
|
1845
|
+
rootUri,
|
|
1846
|
+
dirs
|
|
1847
|
+
]);
|
|
1848
|
+
const isKnownFile = useKnownFile(dirs);
|
|
1849
|
+
const metadataRows = useMemo(()=>Object.values(dirs).flatMap((dir)=>dir.entries.map((entry)=>toEntryRow(entry, 0, false))), [
|
|
1850
|
+
dirs
|
|
1851
|
+
]);
|
|
1852
|
+
return {
|
|
1853
|
+
directoryUris,
|
|
1854
|
+
isKnownFile,
|
|
1855
|
+
metadataRows
|
|
1856
|
+
};
|
|
1857
|
+
}
|
|
996
1858
|
const ids = new WeakMap();
|
|
997
1859
|
let nextId = 1;
|
|
998
1860
|
function idOf(value) {
|
|
@@ -1063,6 +1925,7 @@ async function loadPage(client, uri, offset, signal, requestOptions) {
|
|
|
1063
1925
|
query: {
|
|
1064
1926
|
uri,
|
|
1065
1927
|
output: 'agent',
|
|
1928
|
+
include_tags: true,
|
|
1066
1929
|
node_limit: PAGE_SIZE,
|
|
1067
1930
|
offset
|
|
1068
1931
|
},
|
|
@@ -1188,6 +2051,14 @@ function useFsTree({ client, rootUri, defaultExpandedUri, requestOptions }) {
|
|
|
1188
2051
|
setExpanded((prev)=>new Set(prev).add(uri));
|
|
1189
2052
|
if (!dirsRef.current[uri]) await fetchPage(uri, 0);
|
|
1190
2053
|
},
|
|
2054
|
+
openPath: async (uri)=>{
|
|
2055
|
+
const current = scope.current();
|
|
2056
|
+
for (const parent of expandChain(rootUri, uri)){
|
|
2057
|
+
if (current.controller.signal.aborted || scope.current().key !== current.key) return;
|
|
2058
|
+
setExpanded((prev)=>new Set(prev).add(parent));
|
|
2059
|
+
if (!dirsRef.current[parent]) await fetchPage(parent, 0);
|
|
2060
|
+
}
|
|
2061
|
+
},
|
|
1191
2062
|
toggleExpand: async (row)=>{
|
|
1192
2063
|
const isOpen = expandedRef.current.has(row.uri);
|
|
1193
2064
|
setExpanded((prev)=>{
|
|
@@ -1225,21 +2096,17 @@ function useFsTree({ client, rootUri, defaultExpandedUri, requestOptions }) {
|
|
|
1225
2096
|
dirs,
|
|
1226
2097
|
expanded
|
|
1227
2098
|
]);
|
|
1228
|
-
const
|
|
1229
|
-
rootUri,
|
|
1230
|
-
dirs
|
|
1231
|
-
]);
|
|
1232
|
-
const isKnownFile = useKnownFile(dirs);
|
|
2099
|
+
const metadata = useTreeMetadata(rootUri, dirs);
|
|
1233
2100
|
return {
|
|
1234
2101
|
rows,
|
|
2102
|
+
...metadata,
|
|
1235
2103
|
isReady,
|
|
1236
2104
|
error,
|
|
1237
|
-
directoryUris,
|
|
1238
|
-
isKnownFile,
|
|
1239
2105
|
...state
|
|
1240
2106
|
};
|
|
1241
2107
|
}
|
|
1242
|
-
function useFileBrowser({ rootUri, locale
|
|
2108
|
+
function useFileBrowser({ rootUri, locale: localeProp, dashboardKinds, renderDashboard, dashboardLabels, controlled = false, summaryLabels, formatCharacterCount, defaultExpandedUri, currentUri, requestOptions, onUriChange }) {
|
|
2109
|
+
const locale = useLocale(localeProp);
|
|
1243
2110
|
const client = useOvClient();
|
|
1244
2111
|
const [query, setQuery] = useState('');
|
|
1245
2112
|
const [pendingUri, setPendingUri] = useState(currentUri);
|
|
@@ -1287,17 +2154,36 @@ function useFileBrowser({ rootUri, locale = 'en-US', controlled = false, summary
|
|
|
1287
2154
|
search.results,
|
|
1288
2155
|
tree.rows
|
|
1289
2156
|
]);
|
|
1290
|
-
const
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
2157
|
+
const openPath = tree.openPath;
|
|
2158
|
+
const openResource = useMemo(()=>async (uri)=>{
|
|
2159
|
+
setPendingUri(uri);
|
|
2160
|
+
notifyUriChange.current(uri);
|
|
2161
|
+
const directory = tree.directoryUris.has(uri) ? uri : uri.slice(0, uri.lastIndexOf('/'));
|
|
2162
|
+
await openPath(directory);
|
|
2163
|
+
}, [
|
|
2164
|
+
openPath,
|
|
2165
|
+
tree.directoryUris
|
|
1297
2166
|
]);
|
|
2167
|
+
const boards = useBrowserDashboards({
|
|
2168
|
+
rows,
|
|
2169
|
+
metadataRows: tree.metadataRows,
|
|
2170
|
+
uri: activeUri,
|
|
2171
|
+
rootUri,
|
|
2172
|
+
generation: refreshGeneration,
|
|
2173
|
+
locale,
|
|
2174
|
+
requestOptions,
|
|
2175
|
+
onOpenUri: openResource,
|
|
2176
|
+
dashboardKinds,
|
|
2177
|
+
renderDashboard,
|
|
2178
|
+
dashboardLabels
|
|
2179
|
+
});
|
|
2180
|
+
const selectedId = selectedRowId(activeUri, search.results);
|
|
1298
2181
|
const { open, toggleExpand, loadMore, retry, refresh } = tree;
|
|
2182
|
+
const { open: openDashboard, close: closeDashboard } = boards;
|
|
2183
|
+
const setActiveKey = preview.setActiveKey;
|
|
1299
2184
|
const actions = useMemo(()=>({
|
|
1300
2185
|
select: async (row)=>{
|
|
2186
|
+
closeDashboard();
|
|
1301
2187
|
setPendingUri(row.uri);
|
|
1302
2188
|
notifyUriChange.current(row.uri);
|
|
1303
2189
|
if ('directory' === row.type) await open(row.uri);
|
|
@@ -1320,15 +2206,25 @@ function useFileBrowser({ rootUri, locale = 'en-US', controlled = false, summary
|
|
|
1320
2206
|
setRefreshing(false);
|
|
1321
2207
|
}
|
|
1322
2208
|
},
|
|
1323
|
-
|
|
2209
|
+
openDashboard: openDashboard,
|
|
2210
|
+
setPreviewKey: (key)=>{
|
|
2211
|
+
if (activeUri && key === dashboardKey(activeUri)) openDashboard(activeUri);
|
|
2212
|
+
else {
|
|
2213
|
+
closeDashboard();
|
|
2214
|
+
setActiveKey(key);
|
|
2215
|
+
}
|
|
2216
|
+
},
|
|
1324
2217
|
setQuery
|
|
1325
2218
|
}), [
|
|
1326
|
-
|
|
2219
|
+
setActiveKey,
|
|
1327
2220
|
open,
|
|
1328
2221
|
toggleExpand,
|
|
1329
2222
|
loadMore,
|
|
1330
2223
|
retry,
|
|
1331
|
-
refresh
|
|
2224
|
+
refresh,
|
|
2225
|
+
openDashboard,
|
|
2226
|
+
closeDashboard,
|
|
2227
|
+
activeUri
|
|
1332
2228
|
]);
|
|
1333
2229
|
return {
|
|
1334
2230
|
rows,
|
|
@@ -1339,8 +2235,13 @@ function useFileBrowser({ rootUri, locale = 'en-US', controlled = false, summary
|
|
|
1339
2235
|
treeError: tree.error,
|
|
1340
2236
|
previewError: preview.error,
|
|
1341
2237
|
searchError: search.error,
|
|
1342
|
-
|
|
1343
|
-
|
|
2238
|
+
dashboards: boards.dashboards,
|
|
2239
|
+
dashboardError: boards.error,
|
|
2240
|
+
previewTabs: boards.tab ? [
|
|
2241
|
+
...preview.tabs ?? [],
|
|
2242
|
+
boards.tab
|
|
2243
|
+
] : preview.tabs,
|
|
2244
|
+
previewKey: boards.isOpen && activeUri ? dashboardKey(activeUri) : preview.activeKey,
|
|
1344
2245
|
previewFooter: preview.footer,
|
|
1345
2246
|
query,
|
|
1346
2247
|
searching: null !== search.results,
|
|
@@ -1349,7 +2250,8 @@ function useFileBrowser({ rootUri, locale = 'en-US', controlled = false, summary
|
|
|
1349
2250
|
actions
|
|
1350
2251
|
};
|
|
1351
2252
|
}
|
|
1352
|
-
function FileBrowser({ uri, defaultUri, rootUri = 'viking://', defaultExpandedUri, locale, agentConnect, onUriChange, onImportResources, renderImportResources, labels, requestOptions, className, style, ...rest }) {
|
|
2253
|
+
function FileBrowser({ uri, defaultUri, rootUri = 'viking://', defaultExpandedUri, locale: localeProp, agentConnect, dashboardKinds, renderDashboard, onUriChange, onImportResources, renderImportResources, labels, requestOptions, className, style, ...rest }) {
|
|
2254
|
+
const locale = useLocale(localeProp);
|
|
1353
2255
|
const [internalUri, setInternalUri] = useState(()=>defaultUri ?? null);
|
|
1354
2256
|
const [preferredTreeWidth, setPreferredTreeWidth] = useState(352);
|
|
1355
2257
|
const searchId = useId();
|
|
@@ -1382,6 +2284,9 @@ function FileBrowser({ uri, defaultUri, rootUri = 'viking://', defaultExpandedUr
|
|
|
1382
2284
|
const browser = useFileBrowser({
|
|
1383
2285
|
rootUri,
|
|
1384
2286
|
locale,
|
|
2287
|
+
dashboardKinds,
|
|
2288
|
+
renderDashboard,
|
|
2289
|
+
dashboardLabels: labels?.dashboard,
|
|
1385
2290
|
controlled: isControlled,
|
|
1386
2291
|
summaryLabels,
|
|
1387
2292
|
formatCharacterCount: text.formatCharacterCount,
|
|
@@ -1390,77 +2295,81 @@ function FileBrowser({ uri, defaultUri, rootUri = 'viking://', defaultExpandedUr
|
|
|
1390
2295
|
requestOptions,
|
|
1391
2296
|
onUriChange: changeUri
|
|
1392
2297
|
});
|
|
1393
|
-
return /*#__PURE__*/
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
className
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
2298
|
+
return /*#__PURE__*/ jsx(LocaleProvider, {
|
|
2299
|
+
locale: locale,
|
|
2300
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
2301
|
+
...rest,
|
|
2302
|
+
ref: layoutRef,
|
|
2303
|
+
className: [
|
|
2304
|
+
'ov-file-browser',
|
|
2305
|
+
className
|
|
2306
|
+
].filter(Boolean).join(' '),
|
|
2307
|
+
style: {
|
|
2308
|
+
...style,
|
|
2309
|
+
'--ov-file-browser-tree-width': `${treeWidth}px`
|
|
2310
|
+
},
|
|
2311
|
+
children: [
|
|
2312
|
+
/*#__PURE__*/ jsx("div", {
|
|
2313
|
+
className: "ov-file-browser__tree",
|
|
2314
|
+
children: /*#__PURE__*/ jsx(FileBrowserTreePane, {
|
|
2315
|
+
entries: {
|
|
2316
|
+
agentConnect,
|
|
2317
|
+
onImportResources,
|
|
2318
|
+
renderImportResources,
|
|
2319
|
+
labels: labels?.entries
|
|
2320
|
+
},
|
|
2321
|
+
searchId: searchId,
|
|
2322
|
+
browser: browser,
|
|
2323
|
+
treeLabels: text.tree,
|
|
2324
|
+
locale: locale,
|
|
2325
|
+
dashboardLabels: labels?.dashboard,
|
|
2326
|
+
searchPlaceholder: text.searchPlaceholder,
|
|
2327
|
+
refreshLabel: text.refresh,
|
|
2328
|
+
searchLoading: text.searchLoading,
|
|
2329
|
+
searchEmpty: text.searchEmpty,
|
|
2330
|
+
searchErrorLabel: text.searchFailed,
|
|
2331
|
+
retryLabel: text.retry
|
|
2332
|
+
})
|
|
2333
|
+
}),
|
|
2334
|
+
/*#__PURE__*/ jsx(ResizableHandle, {
|
|
2335
|
+
label: text.resizeTree,
|
|
2336
|
+
min: 200,
|
|
2337
|
+
max: treeMaxWidth,
|
|
2338
|
+
value: treeWidth,
|
|
2339
|
+
onResize: setPreferredTreeWidth,
|
|
2340
|
+
className: "ov-file-browser__resizer"
|
|
2341
|
+
}),
|
|
2342
|
+
browser.previewTabs && browser.previewTabs.length > 0 ? /*#__PURE__*/ jsx(FileBrowserDetail, {
|
|
2343
|
+
tabs: browser.previewTabs,
|
|
2344
|
+
activeKey: browser.previewKey,
|
|
1417
2345
|
locale: locale,
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
source: text.sourceMode,
|
|
1443
|
-
copyPath: text.copyPath,
|
|
1444
|
-
copyContent: text.copyContent,
|
|
1445
|
-
download: text.download,
|
|
1446
|
-
viewSwitch: text.viewSwitch
|
|
1447
|
-
},
|
|
1448
|
-
onActiveKeyChange: browser.actions.setPreviewKey
|
|
1449
|
-
}) : browser.currentUri && browser.previewError ? /*#__PURE__*/ jsx("div", {
|
|
1450
|
-
className: "ov-file-browser__detail",
|
|
1451
|
-
children: /*#__PURE__*/ jsx(FileBrowserFailure, {
|
|
1452
|
-
message: text.error,
|
|
1453
|
-
detail: browser.previewError.message,
|
|
1454
|
-
retryLabel: text.retry,
|
|
1455
|
-
onRetry: ()=>void browser.actions.refresh()
|
|
1456
|
-
})
|
|
1457
|
-
}) : /*#__PURE__*/ jsx("div", {
|
|
1458
|
-
className: "ov-file-browser__detail",
|
|
1459
|
-
children: /*#__PURE__*/ jsx(FileBrowserEmpty, {
|
|
1460
|
-
label: text.empty
|
|
2346
|
+
labels: previewLabels,
|
|
2347
|
+
footer: browser.previewFooter,
|
|
2348
|
+
viewLabels: {
|
|
2349
|
+
preview: text.previewMode,
|
|
2350
|
+
source: text.sourceMode,
|
|
2351
|
+
copyPath: text.copyPath,
|
|
2352
|
+
copyContent: text.copyContent,
|
|
2353
|
+
download: text.download,
|
|
2354
|
+
viewSwitch: text.viewSwitch
|
|
2355
|
+
},
|
|
2356
|
+
onActiveKeyChange: browser.actions.setPreviewKey
|
|
2357
|
+
}) : browser.currentUri && browser.previewError ? /*#__PURE__*/ jsx("div", {
|
|
2358
|
+
className: "ov-file-browser__detail",
|
|
2359
|
+
children: /*#__PURE__*/ jsx(FileBrowserFailure, {
|
|
2360
|
+
message: text.error,
|
|
2361
|
+
detail: browser.previewError.message,
|
|
2362
|
+
retryLabel: text.retry,
|
|
2363
|
+
onRetry: ()=>void browser.actions.refresh()
|
|
2364
|
+
})
|
|
2365
|
+
}) : /*#__PURE__*/ jsx("div", {
|
|
2366
|
+
className: "ov-file-browser__detail",
|
|
2367
|
+
children: /*#__PURE__*/ jsx(FileBrowserEmpty, {
|
|
2368
|
+
label: text.empty
|
|
2369
|
+
})
|
|
1461
2370
|
})
|
|
1462
|
-
|
|
1463
|
-
|
|
2371
|
+
]
|
|
2372
|
+
})
|
|
1464
2373
|
});
|
|
1465
2374
|
}
|
|
1466
|
-
export { FileBrowser
|
|
2375
|
+
export { FileBrowser };
|