@unson/brainbase-mcp 0.41.2 → 0.41.4
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 +9 -0
- package/contracts/judgment-dag/digest.json +2 -2
- package/dist/judgment-history-http.js +52 -11
- package/dist/judgment-history.d.ts +70 -2
- package/dist/judgment-history.js +381 -122
- package/dist/local-web-host.js +1 -1
- package/package.json +5 -3
- package/ui/brainbase-tokens.css +17 -0
- package/ui/foundation-overview.css +18 -0
- package/ui/foundation-overview.js +77 -77
- package/ui/graph-own-share.js +30 -3
- package/ui/judgment-history.css +215 -22
- package/ui/judgment-history.js +398 -104
- package/ui/local-web-shell.css +1 -0
- package/ui/local-web-shell.js +3 -0
- package/ui/native-scrollbars.css +18 -0
- package/ui/native-scrollbars.js +18 -0
- package/ui/workspace-kit.css +36 -0
- package/ui/workspace-kit.js +65 -0
package/ui/brainbase-tokens.css
CHANGED
|
@@ -50,6 +50,23 @@
|
|
|
50
50
|
--bb-color-rail-active: #efedff;
|
|
51
51
|
--bb-color-rail-strong: #202124;
|
|
52
52
|
--bb-color-overlay: rgb(32 33 36 / 40%);
|
|
53
|
+
--bb-color-notice-border: #ffffff20;
|
|
54
|
+
--bb-color-notice-danger: #e29494;
|
|
55
|
+
--bb-color-notice-warning: #d9a441;
|
|
56
|
+
--bb-color-notice-background: linear-gradient(110deg,rgb(13 25 46 / 88%),rgb(36 50 75 / 72%));
|
|
57
|
+
--bb-color-notice-text: #ffffff;
|
|
58
|
+
--bb-color-notice-danger-symbol-border: #e2949470;
|
|
59
|
+
--bb-color-notice-danger-text: #f2bbbb;
|
|
60
|
+
--bb-color-notice-warning-text: #f4d68a;
|
|
61
|
+
--bb-color-notice-warning-symbol-border: #d9a44180;
|
|
62
|
+
--bb-color-notice-control-border: #ffffff45;
|
|
63
|
+
--bb-color-inline-error: #9b3d3d;
|
|
64
|
+
--bb-color-record-missing: #80601c;
|
|
65
|
+
--bb-color-dialog-overlay: #0d192e66;
|
|
66
|
+
--bb-color-scrollbar-rgb: 36,50,75;
|
|
67
|
+
--bb-color-scrollbar-dark-rgb: 203,212,225;
|
|
68
|
+
--bb-shadow-help: 0 6px 24px #0d192e20;
|
|
69
|
+
--bb-font-help: Georgia,serif;
|
|
53
70
|
--bb-shadow: 0 16px 42px rgb(32 33 36 / 10%);
|
|
54
71
|
--bb-font-sans: Geist, "Noto Sans JP", "Hiragino Sans", system-ui, sans-serif;
|
|
55
72
|
--bb-font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
@@ -237,3 +237,21 @@
|
|
|
237
237
|
|
|
238
238
|
/* Catalog provenance is secondary to the topic, but remains visible on every card. */
|
|
239
239
|
.bb-fov-source { display: inline-block; margin: 0 0 12px; padding: 4px 10px; border-radius: 999px; background: var(--bb-surface-subtle, #f4f4f8); color: var(--bb-text-muted, #62626e); font-size: 12px; overflow-wrap: anywhere; }
|
|
240
|
+
|
|
241
|
+
.bb-fov-objective-ledger .bb-ws-ledger-row { grid-template-columns: minmax(180px,1.2fr) minmax(200px,1.3fr) minmax(150px,1fr) 110px; }
|
|
242
|
+
.bb-fov-objective-ledger .bb-ws-ledger-row > span { white-space: normal; line-height: 1.7; }
|
|
243
|
+
.bb-fov-objective-ledger .bb-ws-ledger-row:is(.is-selected,:hover) { background: var(--bb-color-accent-soft); box-shadow: inset 3px 0 var(--bb-color-accent); }
|
|
244
|
+
.bb-fov .bb-ws-section-title { display: flex; align-items: center; gap: 8px; }
|
|
245
|
+
.bb-fov-philosophy-grid { grid-template-columns: minmax(0,1fr); }
|
|
246
|
+
.bb-fov-philosophy-card { border-top: 0; width: 100%; box-sizing: border-box; }
|
|
247
|
+
.bb-fov-reading { display: grid; gap: 26px; }
|
|
248
|
+
.bb-fov-reading > section > h3 { margin: 0 0 10px; color: var(--bb-color-muted); font-size: 12px; font-weight: 600; line-height: 1.5; }
|
|
249
|
+
.bb-fov-reading .bb-ws-definition { margin: 0; grid-template-columns: 100px minmax(0,1fr); gap: 10px 20px; font-size: 14px; line-height: 1.8; }
|
|
250
|
+
.bb-fov-reading .bb-fov-current-state { padding: 16px; border: 1px solid var(--bb-color-border); border-radius: 10px; background: var(--bb-color-canvas); gap: 12px; }
|
|
251
|
+
.bb-fov-original { margin-top: 24px; padding-top: 18px; border-top: 1px solid var(--bb-color-border); font-size: 12px; color: var(--bb-color-muted); }
|
|
252
|
+
.bb-fov-original > summary { cursor: pointer; }
|
|
253
|
+
.bb-fov-missing { color: var(--bb-color-record-missing); }
|
|
254
|
+
@media (max-width: 760px) { .bb-fov-objective-ledger { overflow-x: auto; } .bb-fov-objective-ledger .bb-ws-ledger-row { min-width: 760px; } }
|
|
255
|
+
@media (max-width: 480px) { .bb-fov-reading .bb-ws-definition { grid-template-columns: 1fr; gap: 4px; } .bb-fov-reading dd { margin-bottom: 12px; } }
|
|
256
|
+
.bb-fov-philosophy-card .bb-fov-original { border-top: 0; padding-top: 0; }
|
|
257
|
+
.bb-fov-objective-ledger .bb-ws-ledger-row:focus-visible { outline: 2px solid var(--bb-color-focus); outline-offset: 2px; }
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
workspaceNotice,
|
|
15
15
|
workspacePageHeader,
|
|
16
16
|
workspaceSectionTitle,
|
|
17
|
+
workspaceHelp, workspaceDialog, workspaceDisclosure, workspaceErrorCard,
|
|
17
18
|
} from './workspace-kit.js';
|
|
18
19
|
|
|
19
20
|
export const FOUNDATION_OVERVIEW_CONTRACT_VERSION = 'foundation-overview.v1';
|
|
@@ -429,59 +430,66 @@ function objectiveCard(doc, record, variableMap) {
|
|
|
429
430
|
return card;
|
|
430
431
|
}
|
|
431
432
|
|
|
433
|
+
function objectiveReading(doc, record, variableMap, recordContexts) {
|
|
434
|
+
const definition = recordDefinition(record), details = detailsFor(record);
|
|
435
|
+
const body = makeElement(doc, 'div', { className: 'bb-fov-reading' });
|
|
436
|
+
const section = (title, content) => {
|
|
437
|
+
const part = makeElement(doc, 'section');
|
|
438
|
+
part.append(makeElement(doc, 'h3', { text: title }), content); body.append(part);
|
|
439
|
+
};
|
|
440
|
+
section('達成条件', workspaceDefinition(doc, [
|
|
441
|
+
['目指す状態', formatAny(definition.desiredState)],
|
|
442
|
+
['評価基準', criteriaElement(doc, definition, details, variableMap)],
|
|
443
|
+
['評価期間', formatAny(firstValue(details, 'evaluation_period_note', 'evaluationPeriodNote')) ?? formatPeriod(definition.evaluationPeriod)],
|
|
444
|
+
]));
|
|
445
|
+
section('確認の根拠', recordedStateElement(doc, record));
|
|
446
|
+
const provenance = Array.isArray(definition.provenance) ? definition.provenance : [];
|
|
447
|
+
section('出典', workspaceDefinition(doc, [
|
|
448
|
+
['記録元', recordContexts?.get(record)?.label ?? formatAny(record.source) ?? '未記録'],
|
|
449
|
+
['根拠', provenance.length ? formatStructuredValue(provenance) : '未記録'],
|
|
450
|
+
]));
|
|
451
|
+
const original = makeElement(doc, 'details', { className: 'bb-fov-original' });
|
|
452
|
+
original.append(makeElement(doc, 'summary', { text: '記録の詳細・参照・原文' }), objectiveCard(doc, record, variableMap),
|
|
453
|
+
workspaceDefinition(doc, [['目的ID', definition.id], ['版', definition.revision], ['digest', record.digest]]));
|
|
454
|
+
body.append(original); return body;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function topicTitle(doc, title, text) {
|
|
458
|
+
const head = workspaceSectionTitle(doc, { title });
|
|
459
|
+
head.append(workspaceHelp(doc, { label: title, text })); return head;
|
|
460
|
+
}
|
|
461
|
+
|
|
432
462
|
function renderObjectives(doc, catalog, viewState, callbacks, recordContexts) {
|
|
433
463
|
const section = makeElement(doc, 'section', { className: 'bb-fov-section', attrs: { 'aria-label': '目的' } });
|
|
434
|
-
section.append(
|
|
435
|
-
title: '目的',
|
|
436
|
-
lead: '目指す状態、評価の定義、記録上の現状を分けて確認します。',
|
|
437
|
-
}));
|
|
464
|
+
section.append(topicTitle(doc, '目的', '目指す状態、評価の定義、記録上の現状を分けて確認します。'));
|
|
438
465
|
if (catalog.objectives.length === 0) {
|
|
439
466
|
section.append(workspaceNotice(doc, { label: '目的', text: 'この対象範囲には登録された目的がありません。' }));
|
|
440
467
|
return section;
|
|
441
468
|
}
|
|
442
|
-
const variableMap = new Map(catalog.variables.map(
|
|
443
|
-
const rows = catalog.objectives.map(
|
|
444
|
-
const definition = recordDefinition(record);
|
|
445
|
-
const details = detailsFor(record);
|
|
469
|
+
const variableMap = new Map(catalog.variables.map(record => [foundationKey(recordDefinition(record)), record]));
|
|
470
|
+
const rows = catalog.objectives.map(record => {
|
|
471
|
+
const definition = recordDefinition(record), details = detailsFor(record), current = currentStateFor(record);
|
|
446
472
|
const key = recordContexts?.get(record)?.key ?? `${definition.id}@${definition.revision}`;
|
|
447
473
|
return {
|
|
448
|
-
key,
|
|
449
|
-
selected: key === viewState.objectiveKey,
|
|
474
|
+
key, selected: key === viewState.objectiveKey,
|
|
450
475
|
onSelect: () => {
|
|
451
476
|
viewState.objectiveKey = key;
|
|
452
|
-
|
|
477
|
+
const opener = doc.activeElement;
|
|
478
|
+
viewState.dialog?.close();
|
|
479
|
+
viewState.dialog = workspaceDialog(doc, {
|
|
480
|
+
title: formatAny(details.title) ?? formatAny(definition.meaning) ?? definition.id, opener,
|
|
481
|
+
content: objectiveReading(doc, record, recordContexts?.get(record)?.variableMap ?? variableMap, recordContexts),
|
|
482
|
+
});
|
|
453
483
|
},
|
|
454
484
|
cells: [
|
|
455
|
-
{ primary: formatAny(
|
|
456
|
-
|
|
457
|
-
|
|
485
|
+
{ primary: formatAny(details.title) ?? formatAny(definition.meaning) ?? definition.id },
|
|
486
|
+
current.text ?? current.status ?? '未記録',
|
|
487
|
+
{ text: current.missing.length ? current.missing.join('・') : missingObjectiveFields(record).join('・') || '記録なし', className: 'bb-fov-missing' },
|
|
488
|
+
formatDate(current.asOf),
|
|
458
489
|
],
|
|
459
490
|
};
|
|
460
491
|
});
|
|
461
|
-
section.append(workspaceLedger(doc, {
|
|
462
|
-
className: 'bb-fov-objective-ledger',
|
|
463
|
-
ariaLabel: '登録された目的',
|
|
464
|
-
columns: ['目的', '目指す状態', '登録状態'],
|
|
465
|
-
rows,
|
|
466
|
-
}));
|
|
467
|
-
const selected = catalog.objectives.find((record) => {
|
|
468
|
-
const definition = recordDefinition(record);
|
|
469
|
-
return (recordContexts?.get(record)?.key ?? `${definition.id}@${definition.revision}`) === viewState.objectiveKey;
|
|
470
|
-
}) ?? (recordContexts ? null : catalog.objectives[0]);
|
|
471
|
-
if (!selected && recordContexts) section.append(makeElement(doc, 'p', { className: 'bb-fov-recorded-notice', text: '目的の行を選ぶと、評価基準と記録上の現状を確認できます。' }));
|
|
472
|
-
if (selected) {
|
|
473
|
-
const selectedDefinition = recordDefinition(selected);
|
|
474
|
-
viewState.objectiveKey = recordContexts?.get(selected)?.key ?? `${selectedDefinition.id}@${selectedDefinition.revision}`;
|
|
475
|
-
if (catalog.objectives.length > 1) {
|
|
476
|
-
section.append(workspaceNotice(doc, {
|
|
477
|
-
label: '詳細表示',
|
|
478
|
-
text: `目的${catalog.objectives.length}件のうち1件を選択して詳細を表示しています。`,
|
|
479
|
-
}));
|
|
480
|
-
}
|
|
481
|
-
const card = objectiveCard(doc, selected, recordContexts?.get(selected)?.variableMap ?? variableMap);
|
|
482
|
-
appendRecordSource(doc, card, selected, recordContexts);
|
|
483
|
-
section.append(card);
|
|
484
|
-
}
|
|
492
|
+
section.append(workspaceLedger(doc, { className: 'bb-fov-objective-ledger', ariaLabel: '登録された目的', columns: ['目的', '現状', '確認待ち', '確認日'], rows }));
|
|
485
493
|
return section;
|
|
486
494
|
}
|
|
487
495
|
|
|
@@ -506,9 +514,7 @@ function philosophyCard(doc, record) {
|
|
|
506
514
|
const card = makeElement(doc, 'article', { className: 'bb-fov-philosophy-card' });
|
|
507
515
|
const title = formatAny(payload.title) ?? record.id;
|
|
508
516
|
card.append(makeElement(doc, 'h3', { text: title }));
|
|
509
|
-
|
|
510
|
-
const status = rawStatus ? (PHILOSOPHY_STATUS_LABELS[rawStatus] ?? `未確認(${rawStatus})`) : '状態未確認';
|
|
511
|
-
card.append(makeElement(doc, 'p', { className: 'bb-fov-status', text: `状態: ${status} / 版: ${record.revision}` }));
|
|
517
|
+
|
|
512
518
|
if (formatAny(payload.statement)) card.append(makeElement(doc, 'p', { className: 'bb-fov-philosophy-statement', text: formatAny(payload.statement) }));
|
|
513
519
|
if (formatAny(payload.summary)) card.append(makeElement(doc, 'p', { text: formatAny(payload.summary) }));
|
|
514
520
|
const applicability = record.applicability?.scope
|
|
@@ -523,10 +529,7 @@ function philosophyCard(doc, record) {
|
|
|
523
529
|
|
|
524
530
|
function renderPhilosophies(doc, catalog, recordContexts) {
|
|
525
531
|
const section = makeElement(doc, 'section', { className: 'bb-fov-section', attrs: { 'aria-label': '哲学' } });
|
|
526
|
-
|
|
527
|
-
title: '哲学',
|
|
528
|
-
lead: '判断の前提となる考え方です。登録された本文と、判断への適用範囲を分けて表示します。',
|
|
529
|
-
}));
|
|
532
|
+
|
|
530
533
|
if (catalog.philosophies.length === 0) {
|
|
531
534
|
section.append(workspaceNotice(doc, { label: '哲学', text: 'この対象範囲には登録された哲学がありません。' }));
|
|
532
535
|
return section;
|
|
@@ -534,8 +537,9 @@ function renderPhilosophies(doc, catalog, recordContexts) {
|
|
|
534
537
|
const grid = makeElement(doc, 'div', { className: 'bb-fov-philosophy-grid' });
|
|
535
538
|
for (const record of catalog.philosophies) {
|
|
536
539
|
const card = philosophyCard(doc, record);
|
|
537
|
-
|
|
538
|
-
|
|
540
|
+
const refs = makeElement(doc, 'details', { className: 'bb-fov-original' });
|
|
541
|
+
refs.append(makeElement(doc, 'summary', { text: '記録の詳細' }), workspaceDefinition(doc, [['出典', recordContexts?.get(record)?.label ?? '未記録'], ['状態', record.payload.status], ['版', record.revision], ['記録ID', record.id], ['digest', record.digest]]));
|
|
542
|
+
card.append(refs); grid.append(card);
|
|
539
543
|
}
|
|
540
544
|
section.append(grid);
|
|
541
545
|
return section;
|
|
@@ -592,10 +596,7 @@ function modelCard(doc, record, variableMap) {
|
|
|
592
596
|
|
|
593
597
|
function renderModels(doc, catalog, viewState, callbacks, recordContexts) {
|
|
594
598
|
const section = makeElement(doc, 'section', { className: 'bb-fov-section', attrs: { 'aria-label': '世界モデル' } });
|
|
595
|
-
|
|
596
|
-
title: '世界モデル',
|
|
597
|
-
lead: '変数の関係として登録された見方です。仮説・未検証・許可用途を、それぞれの状態として表示します。',
|
|
598
|
-
}));
|
|
599
|
+
|
|
599
600
|
const searchWrap = makeElement(doc, 'div', { className: 'bb-fov-model-search' });
|
|
600
601
|
const label = makeElement(doc, 'label', { text: 'モデルを検索', attrs: { for: 'bb-fov-model-search' } });
|
|
601
602
|
const input = makeElement(doc, 'input', {
|
|
@@ -682,6 +683,7 @@ export function renderFoundationOverview(root, state, {
|
|
|
682
683
|
showHeader = true,
|
|
683
684
|
recordContexts,
|
|
684
685
|
partial = false,
|
|
686
|
+
onNotice,
|
|
685
687
|
} = {}) {
|
|
686
688
|
if (!root) throw new TypeError('root is required');
|
|
687
689
|
const doc = getDocument(explicitDocument);
|
|
@@ -698,28 +700,26 @@ export function renderFoundationOverview(root, state, {
|
|
|
698
700
|
source: `正本: ${scopeId}`,
|
|
699
701
|
}));
|
|
700
702
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
}
|
|
703
|
+
const notify = notice => {
|
|
704
|
+
if (onNotice) onNotice(notice);
|
|
705
|
+
else surface.append(workspaceErrorCard(doc, notice));
|
|
706
|
+
};
|
|
705
707
|
if (state.status === 'loading') {
|
|
706
|
-
surface.append(renderLoading(doc, state, callbacks));
|
|
707
|
-
root.append(surface);
|
|
708
|
-
return surface;
|
|
708
|
+
surface.append(renderLoading(doc, state, callbacks)); root.append(surface); return surface;
|
|
709
709
|
}
|
|
710
710
|
if (state.status !== 'ready') {
|
|
711
|
-
|
|
712
|
-
root.append(surface);
|
|
713
|
-
return surface;
|
|
711
|
+
notify({ title: '取得失敗', message: `${state.error?.message ?? '目的・哲学・世界モデルを確認できません。'} 登録なし・0件として表示していません。`, onRetry: callbacks.load });
|
|
712
|
+
root.append(surface); return surface;
|
|
714
713
|
}
|
|
715
714
|
const catalog = state.catalog;
|
|
716
|
-
if (partial)
|
|
717
|
-
surface.append(recordContexts
|
|
718
|
-
? makeElement(doc, 'p', { className: 'bb-fov-recorded-notice', text: '記録上の現状は保存時点の記述です。登録状態と検証状態を分けて読みます。' })
|
|
719
|
-
: workspaceNotice(doc, { label: '読み方', text: '登録は達成・採用・検証済みを意味しません。記録上の現状は保存時点の記述です。' }));
|
|
715
|
+
if (partial) notify({ title: '取得済みの範囲', tone: 'warning', message: '以下の登録なし・検索結果は取得できた記録だけが対象です。全体は未確認です。' });
|
|
720
716
|
surface.append(renderObjectives(doc, catalog, viewState, callbacks, recordContexts));
|
|
721
|
-
|
|
722
|
-
|
|
717
|
+
const fold = (title, help, content, initialOpen) => {
|
|
718
|
+
const key = title === '哲学' ? 'philosophyOpen' : 'modelsOpen';
|
|
719
|
+
return workspaceDisclosure(doc, { title, help, content, open: viewState[key] ?? initialOpen, onToggle: open => { viewState[key] = open; } });
|
|
720
|
+
};
|
|
721
|
+
surface.append(fold('哲学', '判断の前提となる考え方です。登録された本文と、判断への適用範囲を分けて表示します。', renderPhilosophies(doc, catalog, recordContexts), true));
|
|
722
|
+
surface.append(fold('世界モデル', '何をすると結果が変わるか、という仮説。未検証・許可用途を分けて確認します。', renderModels(doc, catalog, viewState, callbacks, recordContexts), false));
|
|
723
723
|
root.append(surface);
|
|
724
724
|
return surface;
|
|
725
725
|
}
|
|
@@ -731,7 +731,7 @@ function appendRecordSource(doc, card, record, contexts) {
|
|
|
731
731
|
|
|
732
732
|
/** Compose independently validated catalogs by topic, preserving each reference's source context. */
|
|
733
733
|
export function renderFoundationCollectionOverview(root, sources, {
|
|
734
|
-
document: explicitDocument, viewState = { query: '', page: 0 }, callbacks = {}, scopeLabel = '全体',
|
|
734
|
+
document: explicitDocument, viewState = { query: '', page: 0 }, callbacks = {}, scopeLabel = '全体', onNotice,
|
|
735
735
|
} = {}) {
|
|
736
736
|
const doc = getDocument(explicitDocument);
|
|
737
737
|
root.replaceChildren();
|
|
@@ -741,14 +741,12 @@ export function renderFoundationCollectionOverview(root, sources, {
|
|
|
741
741
|
let ready = 0;
|
|
742
742
|
for (const source of sources) {
|
|
743
743
|
if (source.state.status !== 'ready') {
|
|
744
|
-
|
|
745
|
-
label: source.label,
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
}
|
|
750
|
-
notice.append(workspaceButton(doc, { text: '再試行', variant: 'quiet', onClick: callbacks.load }));
|
|
751
|
-
root.append(notice);
|
|
744
|
+
if (source.state.status === 'loading') {
|
|
745
|
+
root.append(workspaceNotice(doc, { label: source.label, text: '目的・哲学・世界モデルを読み込んでいます。' }));
|
|
746
|
+
} else {
|
|
747
|
+
const notice = { title: source.label, message: `取得失敗: ${source.state.error?.message ?? 'この対象は未確認です。0件ではありません。'}`, onRetry: callbacks.load };
|
|
748
|
+
if (onNotice) onNotice(notice); else root.append(workspaceErrorCard(doc, notice));
|
|
749
|
+
}
|
|
752
750
|
continue;
|
|
753
751
|
}
|
|
754
752
|
const value = normalizeFoundationCatalog(source.state.catalog, source.scopeId);
|
|
@@ -780,7 +778,7 @@ export function renderFoundationCollectionOverview(root, sources, {
|
|
|
780
778
|
const mount = makeElement(doc, 'div');
|
|
781
779
|
renderFoundationOverview(mount, { status: 'ready', catalog }, {
|
|
782
780
|
document: doc, scopeId: scopeLabel, showHeader: false, viewState, callbacks,
|
|
783
|
-
recordContexts: contexts, partial: ready !== sources.length,
|
|
781
|
+
recordContexts: contexts, partial: ready !== sources.length, onNotice,
|
|
784
782
|
});
|
|
785
783
|
root.append(mount);
|
|
786
784
|
}
|
|
@@ -813,6 +811,7 @@ export function createFoundationOverview({ root, port, scopeId, document: explic
|
|
|
813
811
|
},
|
|
814
812
|
async load() {
|
|
815
813
|
if (destroyed) return state;
|
|
814
|
+
viewState.dialog?.close();
|
|
816
815
|
const requestGeneration = ++generation;
|
|
817
816
|
state.status = 'loading';
|
|
818
817
|
state.catalog = null;
|
|
@@ -841,6 +840,7 @@ export function createFoundationOverview({ root, port, scopeId, document: explic
|
|
|
841
840
|
destroy() {
|
|
842
841
|
destroyed = true;
|
|
843
842
|
generation += 1;
|
|
843
|
+
viewState.dialog?.close();
|
|
844
844
|
root.replaceChildren();
|
|
845
845
|
},
|
|
846
846
|
};
|
package/ui/graph-own-share.js
CHANGED
|
@@ -282,11 +282,15 @@ export function createOwnObjectivesView({
|
|
|
282
282
|
basePath = '/api/graph/own',
|
|
283
283
|
label = GRAPH_OWN_OBJECTIVES_LABEL,
|
|
284
284
|
autoLoad = true,
|
|
285
|
+
compact = false,
|
|
286
|
+
onState,
|
|
287
|
+
onNotice,
|
|
285
288
|
} = {}) {
|
|
286
289
|
if (!root) throw new TypeError('root is required');
|
|
287
290
|
const doc = explicitDocument ?? globalThis.document;
|
|
288
291
|
const source = graphOwnShareSource({ basePath, label }, { fetcher });
|
|
289
292
|
const state = { list: { state: 'loading' }, selectedId: null };
|
|
293
|
+
let destroyed = false, generation = 0;
|
|
290
294
|
|
|
291
295
|
function detail(objective) {
|
|
292
296
|
const wrap = makeElement(doc, 'div', { className: 'bb-graph-own-detail', attrs: { 'aria-label': '選んだ目的(引き継いだ自分の分)' } });
|
|
@@ -316,7 +320,17 @@ export function createOwnObjectivesView({
|
|
|
316
320
|
|
|
317
321
|
function body() {
|
|
318
322
|
const notice = ownShareStateNotice(doc, state.list, { onRetry: () => controller.load(), loadingText: '引き継いだ自分の目的を読み込んでいます。' });
|
|
319
|
-
if (notice)
|
|
323
|
+
if (notice) {
|
|
324
|
+
if (compact && state.list.state !== 'loading' && state.list.state !== 'not_handed_over') {
|
|
325
|
+
onNotice?.({ title: label, message: `${state.list.reason ?? '引き継いだ自分の目的を取得できません。'} 0件ではありません。`, onRetry: () => controller.load() });
|
|
326
|
+
return [makeElement(doc, 'p', { className: 'bb-ws-inline-error', text: '取得できません' })];
|
|
327
|
+
}
|
|
328
|
+
if (compact && state.list.state === 'not_handed_over') {
|
|
329
|
+
const guide = makeElement(doc, 'details'); guide.append(makeElement(doc, 'summary', { text: '引き継ぎの案内' }), notice);
|
|
330
|
+
return [makeElement(doc, 'p', { text: 'まだ引き継いだ目的はありません。' }), guide];
|
|
331
|
+
}
|
|
332
|
+
return [notice];
|
|
333
|
+
}
|
|
320
334
|
const { payload } = state.list;
|
|
321
335
|
if (payload.objectives.length === 0) {
|
|
322
336
|
return [makeElement(doc, 'p', { className: 'bb-graph-empty', text: payload.foundation === 'none' ? 'この束には、目的の定義がありません。' : 'この束には、目的がありません。' })];
|
|
@@ -346,18 +360,31 @@ export function createOwnObjectivesView({
|
|
|
346
360
|
const controller = {
|
|
347
361
|
get state() { return state; },
|
|
348
362
|
render() {
|
|
363
|
+
if (destroyed) return controller;
|
|
349
364
|
const handover = state.list.state === 'ok' ? state.list.payload.handover : null;
|
|
350
|
-
|
|
365
|
+
if (compact) {
|
|
366
|
+
const facts = makeElement(doc, 'p', { className: 'bb-graph-own-facts', text: '読み取りのみ' });
|
|
367
|
+
const refs = makeElement(doc, 'details');
|
|
368
|
+
refs.append(makeElement(doc, 'summary', { text: '出典' }), makeElement(doc, 'p', { text: ownShareHandoverText(handover) ?? (state.list.state === 'not_handed_over' ? 'まだ引き継いでいません。' : '出典は確認できません。') }));
|
|
369
|
+
root.replaceChildren(facts, ...body(), refs);
|
|
370
|
+
}
|
|
371
|
+
else root.replaceChildren(ownShareSection(doc, { label: source.label, lead: OBJECTIVES_LEAD, handover, children: body(), className: 'bb-graph-own-objectives' }));
|
|
372
|
+
onState?.(state.list);
|
|
351
373
|
return controller;
|
|
352
374
|
},
|
|
353
375
|
async load() {
|
|
376
|
+
if (destroyed) return state.list;
|
|
377
|
+
const requestGeneration = ++generation;
|
|
354
378
|
state.list = { state: 'loading' };
|
|
355
379
|
controller.render();
|
|
356
|
-
|
|
380
|
+
const result = await source.client.read('/objectives');
|
|
381
|
+
if (destroyed || requestGeneration !== generation) return state.list;
|
|
382
|
+
state.list = normalizeOwnObjectives(result);
|
|
357
383
|
if (state.list.state !== 'ok' || !state.list.payload.objectives.some((objective) => objective.id === state.selectedId)) state.selectedId = null;
|
|
358
384
|
controller.render();
|
|
359
385
|
return state.list;
|
|
360
386
|
},
|
|
387
|
+
destroy() { destroyed = true; generation++; root.replaceChildren(); },
|
|
361
388
|
select(id) {
|
|
362
389
|
state.selectedId = textOrNull(id);
|
|
363
390
|
return controller.render();
|