@unson/brainbase-mcp 0.41.6 → 0.41.8
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/dist/graph-foundation-reader.d.ts +6 -2
- package/dist/graph-foundation-reader.js +10 -9
- package/package.json +2 -2
- package/ui/brainbase-tokens.css +2 -0
- package/ui/foundation-overview.css +1 -8
- package/ui/foundation-overview.js +98 -20
- package/ui/graph-own-share.js +28 -9
- package/ui/meeting-minutes.css +293 -60
- package/ui/meeting-minutes.js +555 -201
- package/ui/outcome-knowledge.css +18 -0
- package/ui/outcome-knowledge.js +265 -9
- package/ui/world/world-work-rail.js +15 -2
|
@@ -78,9 +78,13 @@ export interface FoundationObjectiveDetails {
|
|
|
78
78
|
readonly evaluator_note?: unknown;
|
|
79
79
|
readonly current_state?: unknown;
|
|
80
80
|
}
|
|
81
|
-
/**
|
|
81
|
+
/** The words a World Model record gives for where it applies. */
|
|
82
|
+
export interface FoundationModelDetails {
|
|
83
|
+
readonly applicability_text?: unknown;
|
|
84
|
+
}
|
|
85
|
+
/** Runtime shape used by the overview contract for Objective and World Model records. */
|
|
82
86
|
export interface FoundationOverviewObjectiveRecord extends FoundationCatalogRecord {
|
|
83
|
-
readonly details?: FoundationObjectiveDetails;
|
|
87
|
+
readonly details?: FoundationObjectiveDetails | FoundationModelDetails;
|
|
84
88
|
}
|
|
85
89
|
export interface GraphFoundationReaders {
|
|
86
90
|
readonly store: Pick<FoundationRevisionStore, 'read' | 'readLatest' | 'list'>;
|
|
@@ -525,12 +525,10 @@ function validateFoundationRecord(row, reference, context, selectedProjectCode,
|
|
|
525
525
|
definition: cloneFoundationDefinition(history.definition),
|
|
526
526
|
digest: digestFoundationDefinition(history.definition)
|
|
527
527
|
};
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
}
|
|
533
|
-
return record;
|
|
528
|
+
const details = reference.type === 'objective'
|
|
529
|
+
? projectDetails(history.payload, OBJECTIVE_DETAIL_KEYS)
|
|
530
|
+
: reference.type === 'model' ? projectDetails(history.payload, MODEL_DETAIL_KEYS) : undefined;
|
|
531
|
+
return details === undefined ? record : { ...record, details };
|
|
534
532
|
}
|
|
535
533
|
const OBJECTIVE_DETAIL_KEYS = [
|
|
536
534
|
'title',
|
|
@@ -540,15 +538,18 @@ const OBJECTIVE_DETAIL_KEYS = [
|
|
|
540
538
|
'evaluator_note',
|
|
541
539
|
'current_state'
|
|
542
540
|
];
|
|
543
|
-
|
|
541
|
+
// A model's foundation scope carries ids and a registration time; its own words for where it
|
|
542
|
+
// applies live beside the definition.
|
|
543
|
+
const MODEL_DETAIL_KEYS = ['applicability_text'];
|
|
544
|
+
function projectDetails(payload, keys) {
|
|
544
545
|
const nestedDetails = isPlainRecord(payload.details) ? payload.details : undefined;
|
|
545
546
|
const foundation = isPlainRecord(payload.foundation) ? payload.foundation : undefined;
|
|
546
547
|
// Graphify payloads historically carried these descriptive fields at the
|
|
547
548
|
// payload root. Keep the two known nested forms compatible while exposing
|
|
548
|
-
// only the
|
|
549
|
+
// only the listed fields in the overview contract.
|
|
549
550
|
const candidates = [payload, nestedDetails, foundation].filter((candidate) => candidate !== undefined);
|
|
550
551
|
const projected = {};
|
|
551
|
-
for (const key of
|
|
552
|
+
for (const key of keys) {
|
|
552
553
|
const source = candidates.find((candidate) => Object.prototype.hasOwnProperty.call(candidate, key));
|
|
553
554
|
if (source !== undefined && source[key] !== undefined)
|
|
554
555
|
projected[key] = source[key];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unson/brainbase-mcp",
|
|
3
|
-
"version": "0.41.
|
|
3
|
+
"version": "0.41.8",
|
|
4
4
|
"description": "Local-first Brainbase judgment OS that lets supported AI agents reuse a user's approved goals, priorities, decisions, and judgment criteria.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -483,5 +483,5 @@
|
|
|
483
483
|
"engines": {
|
|
484
484
|
"node": ">=20"
|
|
485
485
|
},
|
|
486
|
-
"gitHead": "
|
|
486
|
+
"gitHead": "b061e1b0a7ccb22155c6e22459ad735dc5e7adb1"
|
|
487
487
|
}
|
package/ui/brainbase-tokens.css
CHANGED
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
--bb-color-accent: #5b4bd8;
|
|
27
27
|
--bb-color-accent-soft: #efedff;
|
|
28
28
|
--bb-color-accent-strong: #4939b8;
|
|
29
|
+
/* Minutes screen remaps its accent to this indigo. Shared accent stays purple. */
|
|
30
|
+
--bb-color-brand-indigo: #0F2A43;
|
|
29
31
|
--bb-color-action: #5b4bd8;
|
|
30
32
|
--bb-color-action-hover: #4939b8;
|
|
31
33
|
--bb-color-action-text: #ffffff;
|
|
@@ -151,14 +151,6 @@
|
|
|
151
151
|
line-height: 1.55;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
.bb-fov-record-id {
|
|
155
|
-
display: block;
|
|
156
|
-
margin-top: 7px;
|
|
157
|
-
color: var(--bb-color-quiet);
|
|
158
|
-
font-family: var(--bb-font-mono);
|
|
159
|
-
font-size: 10px;
|
|
160
|
-
overflow-wrap: anywhere;
|
|
161
|
-
}
|
|
162
154
|
|
|
163
155
|
.bb-fov-ref-list {
|
|
164
156
|
display: grid;
|
|
@@ -254,4 +246,5 @@
|
|
|
254
246
|
@media (max-width: 760px) { .bb-fov-objective-ledger { overflow-x: auto; } .bb-fov-objective-ledger .bb-ws-ledger-row { min-width: 760px; } }
|
|
255
247
|
@media (max-width: 480px) { .bb-fov-reading .bb-ws-definition { grid-template-columns: 1fr; gap: 4px; } .bb-fov-reading dd { margin-bottom: 12px; } }
|
|
256
248
|
.bb-fov-philosophy-card .bb-fov-original { border-top: 0; padding-top: 0; }
|
|
249
|
+
.bb-fov-model-card .bb-fov-original { margin-top: 12px; padding-top: 10px; overflow-wrap: anywhere; }
|
|
257
250
|
.bb-fov-objective-ledger .bb-ws-ledger-row:focus-visible { outline: 2px solid var(--bb-color-focus); outline-offset: 2px; }
|
|
@@ -55,6 +55,16 @@ const PHILOSOPHY_STATUS_LABELS = Object.freeze({
|
|
|
55
55
|
archived: '終了',
|
|
56
56
|
});
|
|
57
57
|
const OPERATOR_LABELS = Object.freeze({ at_least: '以上', at_most: '以下', equals: '一致' });
|
|
58
|
+
const SOURCE_KIND_LABELS = Object.freeze({
|
|
59
|
+
candidate: '候補からの登録',
|
|
60
|
+
document: '文書',
|
|
61
|
+
observation: '観察',
|
|
62
|
+
decision: '決定',
|
|
63
|
+
import: '取り込み',
|
|
64
|
+
});
|
|
65
|
+
// A record without a name is said to have none; its id stays in the record details (P9).
|
|
66
|
+
const UNNAMED_RECORD = '名前の記録なし';
|
|
67
|
+
const UNNAMED_VARIABLE = '名前の記録がない変数';
|
|
58
68
|
|
|
59
69
|
export class FoundationOverviewError extends Error {
|
|
60
70
|
constructor(code, message) {
|
|
@@ -225,12 +235,52 @@ const SCOPE_LABELS = Object.freeze({
|
|
|
225
235
|
company: '組織',
|
|
226
236
|
});
|
|
227
237
|
|
|
238
|
+
function formatValidity(from, until) {
|
|
239
|
+
if (!from && !until) return null;
|
|
240
|
+
if (!from) return `${formatDate(until)} まで`;
|
|
241
|
+
return `${formatDate(from)} から ${until ? `${formatDate(until)} まで` : '(終了日の記録なし)'}`;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* A scope in words: `{ type, id }` names the project or organization, and a validity scope
|
|
246
|
+
* (`subjectIds`, `validFrom`, `validUntil`) becomes its period and the number of subjects. The
|
|
247
|
+
* subject ids themselves belong to the record details.
|
|
248
|
+
*/
|
|
228
249
|
function formatScope(value) {
|
|
229
250
|
if (!isObject(value)) return formatStructuredValue(value);
|
|
230
251
|
const type = formatAny(value.type);
|
|
231
252
|
const id = formatAny(value.id);
|
|
232
253
|
if (type && id) return `${SCOPE_LABELS[type] ?? type}: ${id}`;
|
|
233
|
-
|
|
254
|
+
const subjects = firstValue(value, 'subjectIds', 'subject_ids');
|
|
255
|
+
const period = formatValidity(firstValue(value, 'validFrom', 'valid_from'), firstValue(value, 'validUntil', 'valid_until'));
|
|
256
|
+
const parts = [
|
|
257
|
+
Array.isArray(subjects) && subjects.length > 0 ? `対象 ${subjects.length}件` : null,
|
|
258
|
+
period ? `適用期間: ${period}` : null,
|
|
259
|
+
].filter(Boolean);
|
|
260
|
+
if (parts.length > 0) return parts.join(' / ');
|
|
261
|
+
return formatAny(firstValue(value, 'text', 'description', 'statement', 'label', 'name'))
|
|
262
|
+
?? '読める形の記録がありません(記録の詳細を参照)';
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Where a definition came from, as kinds of source; the source and evidence ids stay in the details. */
|
|
266
|
+
function formatProvenance(provenance) {
|
|
267
|
+
if (!Array.isArray(provenance) || provenance.length === 0) return null;
|
|
268
|
+
return provenance.map((item) => {
|
|
269
|
+
const kind = SOURCE_KIND_LABELS[item?.sourceKind] ?? '種類の記録なし';
|
|
270
|
+
const evidence = Array.isArray(item?.evidenceIds) ? item.evidenceIds.length : 0;
|
|
271
|
+
return evidence > 0 ? `${kind}(証拠${evidence}件)` : kind;
|
|
272
|
+
}).join('、');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** Ids, revisions and digests of one record, for the "記録の詳細" disclosure only. */
|
|
276
|
+
function recordDetailsElement(doc, rows, summary = '記録の詳細') {
|
|
277
|
+
const details = makeElement(doc, 'details', { className: 'bb-fov-original' });
|
|
278
|
+
details.append(makeElement(doc, 'summary', { text: summary }), workspaceDefinition(doc, rows));
|
|
279
|
+
return details;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function referenceLabels(refs) {
|
|
283
|
+
return Array.isArray(refs) && refs.length > 0 ? refs.map(referenceLabel).join('、') : null;
|
|
234
284
|
}
|
|
235
285
|
|
|
236
286
|
function recordDefinition(record) { return isObject(record?.definition) ? record.definition : {}; }
|
|
@@ -265,6 +315,15 @@ function statusElement(doc, definition, className = '') {
|
|
|
265
315
|
return makeElement(doc, 'p', { className: `bb-fov-status${className ? ` ${className}` : ''}`, text: statusText(definition) });
|
|
266
316
|
}
|
|
267
317
|
|
|
318
|
+
/**
|
|
319
|
+
* The one state a reader needs in front of a model: whether it is held as verified or as a
|
|
320
|
+
* hypothesis. Adoption, validation and authorized uses stay in the record details.
|
|
321
|
+
*/
|
|
322
|
+
function certaintyText(definition) {
|
|
323
|
+
const label = EPISTEMIC_LABELS[definition.epistemicState] ?? VALIDATION_LABELS[definition.validationState];
|
|
324
|
+
return `確からしさ: ${label ?? '記録なし'}`;
|
|
325
|
+
}
|
|
326
|
+
|
|
268
327
|
function detailsFor(record) {
|
|
269
328
|
return isObject(record?.details) ? record.details : {};
|
|
270
329
|
}
|
|
@@ -310,9 +369,7 @@ function criteriaList(doc, definition, variableMap) {
|
|
|
310
369
|
const ref = criterion?.variableRef;
|
|
311
370
|
const exact = variableMap.get(foundationKey(ref));
|
|
312
371
|
const exactDefinition = exact ? recordDefinition(exact) : null;
|
|
313
|
-
const name = exactDefinition
|
|
314
|
-
? (formatAny(exactDefinition.meaning) ?? referenceLabel(ref))
|
|
315
|
-
: referenceLabel(ref);
|
|
372
|
+
const name = (exactDefinition ? formatAny(exactDefinition.meaning) : null) ?? UNNAMED_VARIABLE;
|
|
316
373
|
const variableDetails = exactDefinition
|
|
317
374
|
? [
|
|
318
375
|
['定義', exactDefinition.definition],
|
|
@@ -328,7 +385,7 @@ function criteriaList(doc, definition, variableMap) {
|
|
|
328
385
|
const status = exact ? '参照確認済み' : '参照未確認(基準変数の版が一致しません)';
|
|
329
386
|
list.append(makeElement(doc, 'li', {
|
|
330
387
|
className: exact ? '' : 'is-unrecorded',
|
|
331
|
-
text: `${name}${variableDetails.length > 0 ? `(${variableDetails.join(' / ')})` : ''}
|
|
388
|
+
text: `${name}${variableDetails.length > 0 ? `(${variableDetails.join(' / ')})` : ''} ${operator}${target === null ? '' : ` ${target}`} — ${status}`,
|
|
332
389
|
}));
|
|
333
390
|
}
|
|
334
391
|
return list;
|
|
@@ -395,7 +452,7 @@ function recordedStateElement(doc, record) {
|
|
|
395
452
|
function objectiveCard(doc, record, variableMap) {
|
|
396
453
|
const definition = recordDefinition(record);
|
|
397
454
|
const details = detailsFor(record);
|
|
398
|
-
const title = formatAny(firstValue(details, 'title')) ?? formatAny(definition.meaning) ??
|
|
455
|
+
const title = formatAny(firstValue(details, 'title')) ?? formatAny(definition.meaning) ?? UNNAMED_RECORD;
|
|
399
456
|
const gaps = missingObjectiveFields(record);
|
|
400
457
|
const current = currentStateFor(record);
|
|
401
458
|
const evaluationPeriod = formatAny(firstValue(details, 'evaluation_period_note', 'evaluationPeriodNote'))
|
|
@@ -446,11 +503,16 @@ function objectiveReading(doc, record, variableMap, recordContexts) {
|
|
|
446
503
|
const provenance = Array.isArray(definition.provenance) ? definition.provenance : [];
|
|
447
504
|
section('出典', workspaceDefinition(doc, [
|
|
448
505
|
['記録元', recordContexts?.get(record)?.label ?? formatAny(record.source) ?? '未記録'],
|
|
449
|
-
['根拠',
|
|
506
|
+
['根拠', formatProvenance(provenance) ?? '未記録'],
|
|
450
507
|
]));
|
|
508
|
+
const criteriaRefs = Array.isArray(definition.criteria) ? definition.criteria.map((criterion) => criterion?.variableRef) : [];
|
|
451
509
|
const original = makeElement(doc, 'details', { className: 'bb-fov-original' });
|
|
452
510
|
original.append(makeElement(doc, 'summary', { text: '記録の詳細・参照・原文' }), objectiveCard(doc, record, variableMap),
|
|
453
|
-
workspaceDefinition(doc, [
|
|
511
|
+
workspaceDefinition(doc, [
|
|
512
|
+
['目的ID', definition.id], ['版', definition.revision], ['digest', record.digest],
|
|
513
|
+
['基準変数の参照', referenceLabels(criteriaRefs)],
|
|
514
|
+
['根拠の記録', provenance.length ? formatStructuredValue(provenance) : null],
|
|
515
|
+
]));
|
|
454
516
|
body.append(original); return body;
|
|
455
517
|
}
|
|
456
518
|
|
|
@@ -477,12 +539,12 @@ function renderObjectives(doc, catalog, viewState, callbacks, recordContexts) {
|
|
|
477
539
|
const opener = doc.activeElement;
|
|
478
540
|
viewState.dialog?.close();
|
|
479
541
|
viewState.dialog = workspaceDialog(doc, {
|
|
480
|
-
title: formatAny(details.title) ?? formatAny(definition.meaning) ??
|
|
542
|
+
title: formatAny(details.title) ?? formatAny(definition.meaning) ?? UNNAMED_RECORD, opener,
|
|
481
543
|
content: objectiveReading(doc, record, recordContexts?.get(record)?.variableMap ?? variableMap, recordContexts),
|
|
482
544
|
});
|
|
483
545
|
},
|
|
484
546
|
cells: [
|
|
485
|
-
{ primary: formatAny(details.title) ?? formatAny(definition.meaning) ??
|
|
547
|
+
{ primary: formatAny(details.title) ?? formatAny(definition.meaning) ?? UNNAMED_RECORD },
|
|
486
548
|
current.text ?? current.status ?? '未記録',
|
|
487
549
|
{ text: current.missing.length ? current.missing.join('・') : missingObjectiveFields(record).join('・') || '記録なし', className: 'bb-fov-missing' },
|
|
488
550
|
formatDate(current.asOf),
|
|
@@ -506,13 +568,13 @@ function philosophyApplicability(payload) {
|
|
|
506
568
|
const period = validFrom
|
|
507
569
|
? `${formatDate(validFrom)}から${validUntil ? ` ${formatDate(validUntil)}まで` : ''}`
|
|
508
570
|
: null;
|
|
509
|
-
return [scope, period ? `適用期間: ${period}` : null].filter(Boolean).join(' / ') ||
|
|
571
|
+
return [scope, period ? `適用期間: ${period}` : null].filter(Boolean).join(' / ') || formatScope(legacy);
|
|
510
572
|
}
|
|
511
573
|
|
|
512
574
|
function philosophyCard(doc, record) {
|
|
513
575
|
const payload = record.payload;
|
|
514
576
|
const card = makeElement(doc, 'article', { className: 'bb-fov-philosophy-card' });
|
|
515
|
-
const title = formatAny(payload.title) ??
|
|
577
|
+
const title = formatAny(payload.title) ?? UNNAMED_RECORD;
|
|
516
578
|
card.append(makeElement(doc, 'h3', { text: title }));
|
|
517
579
|
|
|
518
580
|
if (formatAny(payload.statement)) card.append(makeElement(doc, 'p', { className: 'bb-fov-philosophy-statement', text: formatAny(payload.statement) }));
|
|
@@ -569,10 +631,10 @@ function renderReferenceList(doc, refs, variableMap, label) {
|
|
|
569
631
|
}
|
|
570
632
|
for (const ref of refs) {
|
|
571
633
|
const exact = variableMap.get(foundationKey(ref));
|
|
572
|
-
const name = exact ? formatAny(recordDefinition(exact).meaning)
|
|
634
|
+
const name = (exact ? formatAny(recordDefinition(exact).meaning) : null) ?? UNNAMED_VARIABLE;
|
|
573
635
|
list.append(makeElement(doc, 'li', {
|
|
574
636
|
className: exact ? '' : 'is-unrecorded',
|
|
575
|
-
text: exact ?
|
|
637
|
+
text: exact ? name : `${name} — 未接続(変数の版が一致しません)`,
|
|
576
638
|
}));
|
|
577
639
|
}
|
|
578
640
|
return list;
|
|
@@ -581,16 +643,32 @@ function renderReferenceList(doc, refs, variableMap, label) {
|
|
|
581
643
|
function modelCard(doc, record, variableMap) {
|
|
582
644
|
const definition = recordDefinition(record);
|
|
583
645
|
const card = makeElement(doc, 'article', { className: 'bb-fov-model-card' });
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
646
|
+
// The stored scope is ids and a registration time, not the reader's "where it applies"; the
|
|
647
|
+
// record's own words go in front, and the stored scope waits in the details.
|
|
648
|
+
const applicability = definition.applicability ?? definition.scope;
|
|
649
|
+
const registered = isObject(applicability) ? applicability : {};
|
|
650
|
+
const subjects = firstValue(registered, 'subjectIds', 'subject_ids');
|
|
651
|
+
const applicabilityText = formatAny(firstValue(detailsFor(record), 'applicability_text', 'applicabilityText'))
|
|
652
|
+
?? (isObject(applicability) ? null : formatAny(applicability));
|
|
653
|
+
card.append(makeElement(doc, 'h3', { text: formatAny(definition.meaning) ?? UNNAMED_RECORD }));
|
|
654
|
+
card.append(makeElement(doc, 'p', { className: 'bb-fov-status', text: certaintyText(definition) }));
|
|
587
655
|
card.append(workspaceDefinition(doc, [
|
|
588
656
|
['関係', formatAny(definition.relationship)],
|
|
589
|
-
['適用範囲',
|
|
657
|
+
['適用範囲', applicabilityText ?? { text: '範囲の説明は記録されていません', className: 'is-unrecorded' }],
|
|
590
658
|
['不確かさ', formatAny(definition.uncertainty)],
|
|
591
659
|
['入力変数', renderReferenceList(doc, definition.inputVariableRefs, variableMap, '入力変数')],
|
|
592
660
|
['出力変数', renderReferenceList(doc, definition.outputVariableRefs, variableMap, '出力変数')],
|
|
593
661
|
]));
|
|
662
|
+
card.append(recordDetailsElement(doc, [
|
|
663
|
+
['状態の内訳', statusText(definition)],
|
|
664
|
+
['記録ID', definition.id],
|
|
665
|
+
['版', definition.revision],
|
|
666
|
+
['digest', record.digest],
|
|
667
|
+
['登録上の対象', Array.isArray(subjects) && subjects.length > 0 ? subjects.join('、') : null],
|
|
668
|
+
['登録上の開始日時', formatValidity(firstValue(registered, 'validFrom', 'valid_from'), firstValue(registered, 'validUntil', 'valid_until'))],
|
|
669
|
+
['入力変数の参照', referenceLabels(definition.inputVariableRefs)],
|
|
670
|
+
['出力変数の参照', referenceLabels(definition.outputVariableRefs)],
|
|
671
|
+
]));
|
|
594
672
|
return card;
|
|
595
673
|
}
|
|
596
674
|
|
|
@@ -712,7 +790,7 @@ export function renderFoundationOverview(root, state, {
|
|
|
712
790
|
surface.append(workspacePageHeader(doc, {
|
|
713
791
|
crumbs: ['Brainbase', '目的と現状'],
|
|
714
792
|
title: '目的と現状',
|
|
715
|
-
lead: '
|
|
793
|
+
lead: '選択したプロジェクトの目的、哲学、世界モデルを、記録された内容と未確認の点を分けて読みます。',
|
|
716
794
|
source: `正本: ${scopeId}`,
|
|
717
795
|
}));
|
|
718
796
|
}
|
|
@@ -734,7 +812,7 @@ export function renderFoundationOverview(root, state, {
|
|
|
734
812
|
return workspaceDisclosure(doc, { title, help, content, open: viewState[key] ?? initialOpen, onToggle: open => { viewState[key] = open; } });
|
|
735
813
|
};
|
|
736
814
|
surface.append(fold('哲学', '判断の前提となる考え方です。登録された本文と、判断への適用範囲を分けて表示します。', renderPhilosophies(doc, catalog, recordContexts), true));
|
|
737
|
-
surface.append(fold('世界モデル', '
|
|
815
|
+
surface.append(fold('世界モデル', '何をすると結果が変わるか、という仮説。検証済みか仮説かを先に示し、ほかの状態や記録の番号は各モデルの「記録の詳細」で確認できます。', renderModels(doc, catalog, viewState, callbacks, recordContexts), false));
|
|
738
816
|
root.append(surface);
|
|
739
817
|
renderLoadingState(doc, root, viewState, false, onLoading);
|
|
740
818
|
return surface;
|
package/ui/graph-own-share.js
CHANGED
|
@@ -76,12 +76,25 @@ export function graphOwnShareSource(option, { fetcher } = {}) {
|
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
/** What the owner sent:
|
|
79
|
+
/** What the owner sent, in words: when it was sent. The snapshot ID and digest are in ownShareHandoverRows. */
|
|
80
80
|
export function ownShareHandoverText(handover) {
|
|
81
81
|
if (!isRecord(handover) || !textOrNull(handover.graphId)) return null;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
return `${formatDateTime(handover.createdAt)} に手元のOSSから送った束`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The snapshot ID, where it is kept and its digest, for the record details only. */
|
|
86
|
+
export function ownShareHandoverRows(handover) {
|
|
87
|
+
if (!isRecord(handover) || !textOrNull(handover.graphId)) return null;
|
|
88
|
+
return [
|
|
89
|
+
['束ID', handover.graphId],
|
|
90
|
+
['置き場所', textOrNull(handover.projectCode)],
|
|
91
|
+
['digest', textOrNull(handover.digest) ?? '未確認'],
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function handoverDetails(doc, handover) {
|
|
96
|
+
const rows = ownShareHandoverRows(handover);
|
|
97
|
+
return rows ? recordDetails(doc, rows) : null;
|
|
85
98
|
}
|
|
86
99
|
|
|
87
100
|
/**
|
|
@@ -113,6 +126,8 @@ export function ownShareSection(doc, { label, lead = OWN_LEAD, handover, childre
|
|
|
113
126
|
const sent = ownShareHandoverText(handover);
|
|
114
127
|
if (sent) facts.append(makeElement(doc, 'span', { text: sent }));
|
|
115
128
|
section.append(facts);
|
|
129
|
+
const sentDetails = handoverDetails(doc, handover);
|
|
130
|
+
if (sentDetails) section.append(sentDetails);
|
|
116
131
|
for (const child of children) if (child) section.append(child);
|
|
117
132
|
return section;
|
|
118
133
|
}
|
|
@@ -250,7 +265,7 @@ function personText(person) {
|
|
|
250
265
|
}
|
|
251
266
|
|
|
252
267
|
function criterionText(criterion) {
|
|
253
|
-
const variable = textOrNull(criterion.variable?.meaning) ??
|
|
268
|
+
const variable = textOrNull(criterion.variable?.meaning) ?? '名前の記録がない変数';
|
|
254
269
|
if (criterion.target === null || criterion.target === undefined) return `${variable}(目標値なし)`;
|
|
255
270
|
const value = `${String(criterion.target)}${textOrNull(criterion.variable?.unit) ? ` ${criterion.variable.unit}` : ''}`;
|
|
256
271
|
if (criterion.operator === 'at_least') return `${variable}: ${value}以上`;
|
|
@@ -295,7 +310,7 @@ export function createOwnObjectivesView({
|
|
|
295
310
|
function detail(objective) {
|
|
296
311
|
const wrap = makeElement(doc, 'div', { className: 'bb-graph-own-detail', attrs: { 'aria-label': '選んだ目的(引き継いだ自分の分)' } });
|
|
297
312
|
wrap.append(
|
|
298
|
-
workspaceRailHead(doc, { kicker: '目的(引き継いだ自分の分)', title: objective.meaning
|
|
313
|
+
workspaceRailHead(doc, { kicker: '目的(引き継いだ自分の分)', title: objective.meaning }),
|
|
299
314
|
closeButton(doc, () => controller.select(null)),
|
|
300
315
|
);
|
|
301
316
|
const criteria = makeElement(doc, 'ul', { className: 'bb-graph-plain-list' });
|
|
@@ -312,7 +327,11 @@ export function createOwnObjectivesView({
|
|
|
312
327
|
['状態', ownLabel(ADOPTION_LABELS, objective.adoptionState) ?? textOrNull(objective.adoptionState)],
|
|
313
328
|
['公開範囲(手元での設定)', ownLabel(VISIBILITY_LABELS, objective.visibility) ?? textOrNull(objective.visibility)],
|
|
314
329
|
]),
|
|
315
|
-
recordDetails(doc, [
|
|
330
|
+
recordDetails(doc, [
|
|
331
|
+
['目的ID', objective.id],
|
|
332
|
+
['版', objective.revision],
|
|
333
|
+
['基準変数のID', objective.criteria.map((criterion) => textOrNull(criterion.variable?.id)).filter(Boolean).join('、') || null],
|
|
334
|
+
]),
|
|
316
335
|
],
|
|
317
336
|
}));
|
|
318
337
|
return wrap;
|
|
@@ -344,7 +363,7 @@ export function createOwnObjectivesView({
|
|
|
344
363
|
selected: objective.id === state.selectedId,
|
|
345
364
|
onSelect: (id) => controller.select(id),
|
|
346
365
|
cells: [
|
|
347
|
-
{ primary: objective.meaning
|
|
366
|
+
{ primary: objective.meaning },
|
|
348
367
|
ownLabel(ADOPTION_LABELS, objective.adoptionState) ?? String(objective.adoptionState ?? ''),
|
|
349
368
|
periodText(objective.evaluationPeriod),
|
|
350
369
|
personText(objective.accountable) ?? { text: '未登録', className: 'is-unresolved' },
|
|
@@ -365,7 +384,7 @@ export function createOwnObjectivesView({
|
|
|
365
384
|
if (compact) {
|
|
366
385
|
const facts = makeElement(doc, 'p', { className: 'bb-graph-own-facts', text: '読み取りのみ' });
|
|
367
386
|
const refs = makeElement(doc, 'details');
|
|
368
|
-
refs.append(makeElement(doc, 'summary', { text: '出典' }), makeElement(doc, 'p', { text: ownShareHandoverText(handover) ?? (state.list.state === 'not_handed_over' ? 'まだ引き継いでいません。' : '出典は確認できません。') }));
|
|
387
|
+
refs.append(makeElement(doc, 'summary', { text: '出典' }), makeElement(doc, 'p', { text: ownShareHandoverText(handover) ?? (state.list.state === 'not_handed_over' ? 'まだ引き継いでいません。' : '出典は確認できません。') }), handoverDetails(doc, handover));
|
|
369
388
|
root.replaceChildren(facts, ...body(), refs);
|
|
370
389
|
}
|
|
371
390
|
else root.replaceChildren(ownShareSection(doc, { label: source.label, lead: OBJECTIVES_LEAD, handover, children: body(), className: 'bb-graph-own-objectives' }));
|