@openviking/react 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -11
- package/dist/37~0.js +27 -0
- package/dist/3c~0.js +14 -8
- package/dist/3~0.js +1 -1
- package/dist/a~0.js +2 -2
- package/dist/ck~0.js +4 -0
- package/dist/client/paths.d.ts +4 -0
- package/dist/components/agent-connect/style.css +48 -4
- package/dist/components/directory-tour/style.css +46 -2
- 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/style.css +144 -12
- package/dist/components/file-preview/style.css +48 -4
- package/dist/components/file-tree/style.css +63 -4
- package/dist/components/scope-switcher/style.css +48 -4
- package/dist/components/scope-switcher.js +1 -1
- package/dist/components/style.css +2168 -84
- package/dist/components/tui/style.css +122 -36
- package/dist/components/viking-bot/style.css +159 -12
- 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 +1 -1
- package/dist/fi~0.js +354 -0
- package/dist/fj~0.js +503 -0
- package/dist/f~0.js +661 -315
- 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 +52 -13
- package/dist/l~0.js +1021 -118
- package/dist/modules/console/index.d.ts +1 -2
- package/dist/modules/console/style.css +377 -56
- 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 +1768 -24
- package/dist/modules/file-browser/types.d.ts +62 -0
- 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 +1 -1
- package/dist/modules/scope-cascade/style.css +48 -4
- package/dist/modules/scope-cascade/types.d.ts +8 -3
- 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 +2344 -191
- package/dist/n~0.js +13 -129
- 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/static/image/dashboard-background.png +0 -0
- package/dist/style.css +8897 -4616
- package/dist/viking-bot-composer~0.js +1 -1
- package/package.json +12 -2
package/dist/l~0.js
CHANGED
|
@@ -1,14 +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 { isOvClientError, useOvSignal, useOvClient } from "./ae~0.js";
|
|
11
|
+
import { ExperienceDashboard } from "./f~0.js";
|
|
12
|
+
import { WikiDashboard } from "./fj~0.js";
|
|
10
13
|
import { useLocale, LocaleProvider } from "./28~0.js";
|
|
11
|
-
import { useOvClient } from "./ae~0.js";
|
|
12
14
|
function clampResizableWidth(width, min, max) {
|
|
13
15
|
const rounded = Math.round(width);
|
|
14
16
|
const lower = Math.max(min, rounded);
|
|
@@ -238,6 +240,26 @@ function resolveTreeMaxWidth(containerWidth) {
|
|
|
238
240
|
if (!containerWidth) return TREE_MAX_WIDTH;
|
|
239
241
|
return Math.max(TREE_MIN_WIDTH, Math.min(TREE_MAX_WIDTH, containerWidth - DETAIL_MIN_WIDTH - RESIZE_FOOTPRINT));
|
|
240
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
|
+
});
|
|
241
263
|
const file_browser_icons_SIZE = 16;
|
|
242
264
|
const strokeProps = {
|
|
243
265
|
width: file_browser_icons_SIZE,
|
|
@@ -304,6 +326,25 @@ function FileBrowserToolbar({ searchId, query, refreshing, canRefresh, placehold
|
|
|
304
326
|
]
|
|
305
327
|
});
|
|
306
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
|
+
}
|
|
307
348
|
function fileTypeIcon(name) {
|
|
308
349
|
const Icon = getFileTypeIcon(name);
|
|
309
350
|
const key = resolveFileTypeIconKey(name);
|
|
@@ -320,7 +361,7 @@ function directoryIcon() {
|
|
|
320
361
|
className: "ov-file-tree__file-type-icon"
|
|
321
362
|
});
|
|
322
363
|
}
|
|
323
|
-
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 }) {
|
|
324
365
|
return /*#__PURE__*/ jsxs(Fragment, {
|
|
325
366
|
children: [
|
|
326
367
|
/*#__PURE__*/ jsx(FileBrowserEntries, {
|
|
@@ -338,44 +379,77 @@ function FileBrowserTreePane({ entries, locale, searchId, browser, treeLabels, s
|
|
|
338
379
|
onQueryChange: browser.actions.setQuery,
|
|
339
380
|
onRefresh: ()=>void browser.actions.refresh()
|
|
340
381
|
}),
|
|
341
|
-
/*#__PURE__*/
|
|
382
|
+
/*#__PURE__*/ jsxs("div", {
|
|
342
383
|
className: "ov-file-browser__tree-scroll",
|
|
343
|
-
children:
|
|
344
|
-
|
|
345
|
-
rows: browser.rows,
|
|
346
|
-
selectedId: browser.selectedId,
|
|
347
|
-
isReady: browser.isReady,
|
|
348
|
-
labels: treeLabels,
|
|
349
|
-
emptyFallback: browser.searching ? browser.searchError ? /*#__PURE__*/ jsxs("div", {
|
|
384
|
+
children: [
|
|
385
|
+
browser.dashboardError ? /*#__PURE__*/ jsxs("div", {
|
|
350
386
|
className: "ov-file-browser__hint ov-file-browser__hint--error",
|
|
387
|
+
"aria-live": "polite",
|
|
351
388
|
children: [
|
|
352
|
-
/*#__PURE__*/
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
389
|
+
/*#__PURE__*/ jsxs("p", {
|
|
390
|
+
children: [
|
|
391
|
+
dashboard_labels_dashboardLabels(locale, dashboardLabels).failed,
|
|
392
|
+
":",
|
|
393
|
+
' ',
|
|
394
|
+
browser.dashboardError.message
|
|
395
|
+
]
|
|
359
396
|
}),
|
|
360
397
|
/*#__PURE__*/ jsx("button", {
|
|
361
398
|
type: "button",
|
|
362
|
-
className: "ov-file-browser__retry",
|
|
363
399
|
onClick: ()=>void browser.actions.refresh(),
|
|
364
400
|
children: retryLabel
|
|
365
401
|
})
|
|
366
402
|
]
|
|
367
|
-
}) :
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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
|
+
]
|
|
379
453
|
})
|
|
380
454
|
]
|
|
381
455
|
});
|
|
@@ -476,6 +550,11 @@ function useContainerWidth() {
|
|
|
476
550
|
width
|
|
477
551
|
};
|
|
478
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
|
+
}
|
|
479
558
|
const emptyDir = ()=>({
|
|
480
559
|
entries: [],
|
|
481
560
|
hasMore: false,
|
|
@@ -503,6 +582,7 @@ function nameFromUri(uri) {
|
|
|
503
582
|
function toEntryRow(entry, depth, expanded, index, busy) {
|
|
504
583
|
const isDir = true === entry.isDir;
|
|
505
584
|
return {
|
|
585
|
+
tags: entry.tags,
|
|
506
586
|
kind: 'entry',
|
|
507
587
|
id: void 0 === index ? entry.uri : `${entry.uri}#${index}`,
|
|
508
588
|
depth,
|
|
@@ -513,7 +593,7 @@ function toEntryRow(entry, depth, expanded, index, busy) {
|
|
|
513
593
|
busy: busy || void 0
|
|
514
594
|
};
|
|
515
595
|
}
|
|
516
|
-
function toFileTab(entry, content, maxLines, icon, openParent) {
|
|
596
|
+
function toFileTab(entry, content, maxLines, icon, openParent, truncated = content.split('\n').length >= maxLines) {
|
|
517
597
|
const name = nameFromUri(entry.uri);
|
|
518
598
|
return {
|
|
519
599
|
kind: 'file',
|
|
@@ -527,7 +607,7 @@ function toFileTab(entry, content, maxLines, icon, openParent) {
|
|
|
527
607
|
content,
|
|
528
608
|
fileName: name,
|
|
529
609
|
path: entry.uri,
|
|
530
|
-
truncated
|
|
610
|
+
truncated
|
|
531
611
|
}
|
|
532
612
|
};
|
|
533
613
|
}
|
|
@@ -612,6 +692,39 @@ function isAbort(error) {
|
|
|
612
692
|
function toError(cause) {
|
|
613
693
|
return cause instanceof Error ? cause : new Error(String(cause));
|
|
614
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
|
+
}
|
|
615
728
|
const BINARY_EXTENSIONS = new Set([
|
|
616
729
|
'png',
|
|
617
730
|
'jpg',
|
|
@@ -695,38 +808,152 @@ function toBinaryTab(uri, name, file, icon, openParent) {
|
|
|
695
808
|
}
|
|
696
809
|
};
|
|
697
810
|
}
|
|
698
|
-
|
|
699
|
-
|
|
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({
|
|
700
922
|
method: 'GET',
|
|
701
|
-
path,
|
|
923
|
+
path: OV_PATHS.contentDownload,
|
|
702
924
|
query: {
|
|
703
925
|
uri
|
|
704
926
|
},
|
|
927
|
+
responseType: 'blob',
|
|
705
928
|
options
|
|
706
|
-
})
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
const
|
|
724
|
-
return {
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
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);
|
|
730
957
|
}
|
|
731
958
|
async function resolveIsDirectory(client, uri, options) {
|
|
732
959
|
try {
|
|
@@ -748,7 +975,6 @@ function abortError() {
|
|
|
748
975
|
error.name = 'AbortError';
|
|
749
976
|
return error;
|
|
750
977
|
}
|
|
751
|
-
const MAX_LINES = 2000;
|
|
752
978
|
function useFsPreview({ client, uri, resourceType = 'file', labels = resolveSummaryLabels('en-US'), formatCharacterCount = resolveLabels(void 0, 'en-US').formatCharacterCount, openParent, generation = 0, requestOptions }) {
|
|
753
979
|
const [directory, setDirectory] = useState(null);
|
|
754
980
|
const [tabs, setTabs] = useState(null);
|
|
@@ -867,39 +1093,6 @@ function loadingTab(uri, isDirectory) {
|
|
|
867
1093
|
}
|
|
868
1094
|
};
|
|
869
1095
|
}
|
|
870
|
-
async function readFile(client, uri, options, openParent) {
|
|
871
|
-
const name = nameFromUri(uri);
|
|
872
|
-
const icon = fileTypeIcon(name);
|
|
873
|
-
if (isBinaryFile(name)) {
|
|
874
|
-
const blob = await client.request({
|
|
875
|
-
method: 'GET',
|
|
876
|
-
path: OV_PATHS.contentDownload,
|
|
877
|
-
query: {
|
|
878
|
-
uri
|
|
879
|
-
},
|
|
880
|
-
responseType: 'blob',
|
|
881
|
-
options
|
|
882
|
-
});
|
|
883
|
-
const typed = new Blob([
|
|
884
|
-
blob
|
|
885
|
-
], {
|
|
886
|
-
type: mimeTypeOf(name)
|
|
887
|
-
});
|
|
888
|
-
return toBinaryTab(uri, name, typed, icon, openParent);
|
|
889
|
-
}
|
|
890
|
-
const content = await client.request({
|
|
891
|
-
method: 'GET',
|
|
892
|
-
path: OV_PATHS.contentRead,
|
|
893
|
-
query: {
|
|
894
|
-
uri,
|
|
895
|
-
limit: MAX_LINES
|
|
896
|
-
},
|
|
897
|
-
options
|
|
898
|
-
});
|
|
899
|
-
return toFileTab({
|
|
900
|
-
uri
|
|
901
|
-
}, 'string' == typeof content ? content : '', MAX_LINES, icon, openParent);
|
|
902
|
-
}
|
|
903
1096
|
function mergeFindResult(result) {
|
|
904
1097
|
const seen = new Set();
|
|
905
1098
|
const entries = [];
|
|
@@ -971,6 +1164,659 @@ function useFsSearch({ client, query, targetUri, generation = 0, requestOptions
|
|
|
971
1164
|
error
|
|
972
1165
|
};
|
|
973
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
|
+
}
|
|
974
1820
|
function knownDirectories(rootUri, dirs) {
|
|
975
1821
|
const known = new Set([
|
|
976
1822
|
rootUri
|
|
@@ -994,6 +1840,21 @@ function useKnownFile(dirs) {
|
|
|
994
1840
|
files
|
|
995
1841
|
]);
|
|
996
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
|
+
}
|
|
997
1858
|
const ids = new WeakMap();
|
|
998
1859
|
let nextId = 1;
|
|
999
1860
|
function idOf(value) {
|
|
@@ -1064,6 +1925,7 @@ async function loadPage(client, uri, offset, signal, requestOptions) {
|
|
|
1064
1925
|
query: {
|
|
1065
1926
|
uri,
|
|
1066
1927
|
output: 'agent',
|
|
1928
|
+
include_tags: true,
|
|
1067
1929
|
node_limit: PAGE_SIZE,
|
|
1068
1930
|
offset
|
|
1069
1931
|
},
|
|
@@ -1189,6 +2051,14 @@ function useFsTree({ client, rootUri, defaultExpandedUri, requestOptions }) {
|
|
|
1189
2051
|
setExpanded((prev)=>new Set(prev).add(uri));
|
|
1190
2052
|
if (!dirsRef.current[uri]) await fetchPage(uri, 0);
|
|
1191
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
|
+
},
|
|
1192
2062
|
toggleExpand: async (row)=>{
|
|
1193
2063
|
const isOpen = expandedRef.current.has(row.uri);
|
|
1194
2064
|
setExpanded((prev)=>{
|
|
@@ -1226,21 +2096,16 @@ function useFsTree({ client, rootUri, defaultExpandedUri, requestOptions }) {
|
|
|
1226
2096
|
dirs,
|
|
1227
2097
|
expanded
|
|
1228
2098
|
]);
|
|
1229
|
-
const
|
|
1230
|
-
rootUri,
|
|
1231
|
-
dirs
|
|
1232
|
-
]);
|
|
1233
|
-
const isKnownFile = useKnownFile(dirs);
|
|
2099
|
+
const metadata = useTreeMetadata(rootUri, dirs);
|
|
1234
2100
|
return {
|
|
1235
2101
|
rows,
|
|
2102
|
+
...metadata,
|
|
1236
2103
|
isReady,
|
|
1237
2104
|
error,
|
|
1238
|
-
directoryUris,
|
|
1239
|
-
isKnownFile,
|
|
1240
2105
|
...state
|
|
1241
2106
|
};
|
|
1242
2107
|
}
|
|
1243
|
-
function useFileBrowser({ rootUri, locale: localeProp, controlled = false, summaryLabels, formatCharacterCount, defaultExpandedUri, currentUri, requestOptions, onUriChange }) {
|
|
2108
|
+
function useFileBrowser({ rootUri, locale: localeProp, dashboardKinds, renderDashboard, dashboardLabels, controlled = false, summaryLabels, formatCharacterCount, defaultExpandedUri, currentUri, requestOptions, onUriChange }) {
|
|
1244
2109
|
const locale = useLocale(localeProp);
|
|
1245
2110
|
const client = useOvClient();
|
|
1246
2111
|
const [query, setQuery] = useState('');
|
|
@@ -1289,17 +2154,36 @@ function useFileBrowser({ rootUri, locale: localeProp, controlled = false, summa
|
|
|
1289
2154
|
search.results,
|
|
1290
2155
|
tree.rows
|
|
1291
2156
|
]);
|
|
1292
|
-
const
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
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
|
|
1299
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);
|
|
1300
2181
|
const { open, toggleExpand, loadMore, retry, refresh } = tree;
|
|
2182
|
+
const { open: openDashboard, close: closeDashboard } = boards;
|
|
2183
|
+
const setActiveKey = preview.setActiveKey;
|
|
1301
2184
|
const actions = useMemo(()=>({
|
|
1302
2185
|
select: async (row)=>{
|
|
2186
|
+
closeDashboard();
|
|
1303
2187
|
setPendingUri(row.uri);
|
|
1304
2188
|
notifyUriChange.current(row.uri);
|
|
1305
2189
|
if ('directory' === row.type) await open(row.uri);
|
|
@@ -1322,15 +2206,25 @@ function useFileBrowser({ rootUri, locale: localeProp, controlled = false, summa
|
|
|
1322
2206
|
setRefreshing(false);
|
|
1323
2207
|
}
|
|
1324
2208
|
},
|
|
1325
|
-
|
|
2209
|
+
openDashboard: openDashboard,
|
|
2210
|
+
setPreviewKey: (key)=>{
|
|
2211
|
+
if (activeUri && key === dashboardKey(activeUri)) openDashboard(activeUri);
|
|
2212
|
+
else {
|
|
2213
|
+
closeDashboard();
|
|
2214
|
+
setActiveKey(key);
|
|
2215
|
+
}
|
|
2216
|
+
},
|
|
1326
2217
|
setQuery
|
|
1327
2218
|
}), [
|
|
1328
|
-
|
|
2219
|
+
setActiveKey,
|
|
1329
2220
|
open,
|
|
1330
2221
|
toggleExpand,
|
|
1331
2222
|
loadMore,
|
|
1332
2223
|
retry,
|
|
1333
|
-
refresh
|
|
2224
|
+
refresh,
|
|
2225
|
+
openDashboard,
|
|
2226
|
+
closeDashboard,
|
|
2227
|
+
activeUri
|
|
1334
2228
|
]);
|
|
1335
2229
|
return {
|
|
1336
2230
|
rows,
|
|
@@ -1341,8 +2235,13 @@ function useFileBrowser({ rootUri, locale: localeProp, controlled = false, summa
|
|
|
1341
2235
|
treeError: tree.error,
|
|
1342
2236
|
previewError: preview.error,
|
|
1343
2237
|
searchError: search.error,
|
|
1344
|
-
|
|
1345
|
-
|
|
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,
|
|
1346
2245
|
previewFooter: preview.footer,
|
|
1347
2246
|
query,
|
|
1348
2247
|
searching: null !== search.results,
|
|
@@ -1351,7 +2250,7 @@ function useFileBrowser({ rootUri, locale: localeProp, controlled = false, summa
|
|
|
1351
2250
|
actions
|
|
1352
2251
|
};
|
|
1353
2252
|
}
|
|
1354
|
-
function FileBrowser({ uri, defaultUri, rootUri = 'viking://', defaultExpandedUri, locale: localeProp, 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 }) {
|
|
1355
2254
|
const locale = useLocale(localeProp);
|
|
1356
2255
|
const [internalUri, setInternalUri] = useState(()=>defaultUri ?? null);
|
|
1357
2256
|
const [preferredTreeWidth, setPreferredTreeWidth] = useState(352);
|
|
@@ -1385,6 +2284,9 @@ function FileBrowser({ uri, defaultUri, rootUri = 'viking://', defaultExpandedUr
|
|
|
1385
2284
|
const browser = useFileBrowser({
|
|
1386
2285
|
rootUri,
|
|
1387
2286
|
locale,
|
|
2287
|
+
dashboardKinds,
|
|
2288
|
+
renderDashboard,
|
|
2289
|
+
dashboardLabels: labels?.dashboard,
|
|
1388
2290
|
controlled: isControlled,
|
|
1389
2291
|
summaryLabels,
|
|
1390
2292
|
formatCharacterCount: text.formatCharacterCount,
|
|
@@ -1420,6 +2322,7 @@ function FileBrowser({ uri, defaultUri, rootUri = 'viking://', defaultExpandedUr
|
|
|
1420
2322
|
browser: browser,
|
|
1421
2323
|
treeLabels: text.tree,
|
|
1422
2324
|
locale: locale,
|
|
2325
|
+
dashboardLabels: labels?.dashboard,
|
|
1423
2326
|
searchPlaceholder: text.searchPlaceholder,
|
|
1424
2327
|
refreshLabel: text.refresh,
|
|
1425
2328
|
searchLoading: text.searchLoading,
|
|
@@ -1469,4 +2372,4 @@ function FileBrowser({ uri, defaultUri, rootUri = 'viking://', defaultExpandedUr
|
|
|
1469
2372
|
})
|
|
1470
2373
|
});
|
|
1471
2374
|
}
|
|
1472
|
-
export { FileBrowser
|
|
2375
|
+
export { FileBrowser };
|