@unson/brainbase-mcp 0.41.11 → 0.42.0
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 +1 -1
- package/contracts/judgment-dag/digest.json +2 -2
- package/dist/local-web-host.d.ts +6 -0
- package/dist/local-web-host.js +54 -3
- package/dist/personal-memory.d.ts +101 -0
- package/dist/personal-memory.js +204 -0
- package/dist/ssot.d.ts +3 -1
- package/dist/ssot.js +4 -0
- package/package.json +13 -2
- package/ui/area-nav.css +79 -0
- package/ui/area-nav.js +249 -0
- package/ui/foundation-overview.css +9 -0
- package/ui/foundation-overview.js +75 -5
- package/ui/graph-ontology-view.css +88 -0
- package/ui/graph-ontology-view.js +248 -0
- package/ui/graph-own-share.js +167 -0
- package/ui/graph-registry-view.css +272 -50
- package/ui/graph-registry-view.js +539 -456
- package/ui/graph-view-shared.css +32 -0
- package/ui/graph-view-shared.js +191 -12
- package/ui/judgment-history.js +74 -3
- package/ui/local-web-shell.css +1 -13
- package/ui/local-web-shell.js +119 -41
- package/ui/outcome-knowledge.js +6 -2
- package/ui/people-and-companies-view.css +166 -15
- package/ui/people-and-companies-view.js +307 -93
- package/ui/personal-memory-http-port.js +72 -0
- package/ui/personal-memory.css +254 -0
- package/ui/personal-memory.js +677 -0
- package/ui/world/world-canvas-notes.js +3 -2
- package/ui/world/world-view.css +19 -0
- package/ui/world/world-view.js +52 -10
- package/ui/world/world-work-rail.js +114 -8
package/ui/area-nav.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Area navigation shared by OSS Personal and the organization edition
|
|
3
|
+
* (brainbase-project ledger D10, stage 2).
|
|
4
|
+
*
|
|
5
|
+
* The left side lists only the areas; the screens of the current area are tabs
|
|
6
|
+
* above the page. An area link opens the screen last used in that area, which
|
|
7
|
+
* is remembered in the viewer's browser only (a display preference, not a fact
|
|
8
|
+
* of the organization). Every area link and tab is a link to a screen, so
|
|
9
|
+
* screen addresses never change. The part draws links only: showing and
|
|
10
|
+
* loading screens stays with the caller (`show` in, `onSelect` out).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const AREA_NAV_CONTRACT_VERSION = 'brainbase.area-nav.v1';
|
|
14
|
+
export const AREA_NAV_MEMORY_KEY = 'brainbase.area-nav.last-screen.v1';
|
|
15
|
+
|
|
16
|
+
function makeElement(doc, tag, { className, text, attrs = {} } = {}) {
|
|
17
|
+
const element = doc.createElement(tag);
|
|
18
|
+
if (className) element.className = className;
|
|
19
|
+
if (text !== undefined && text !== null) element.textContent = String(text);
|
|
20
|
+
for (const [name, value] of Object.entries(attrs)) {
|
|
21
|
+
if (value === undefined || value === null || value === false) continue;
|
|
22
|
+
element.setAttribute(name, value === true ? '' : String(value));
|
|
23
|
+
}
|
|
24
|
+
return element;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The last screen per area, kept in the given storage (for example the
|
|
29
|
+
* browser's localStorage). A storage that is missing, full or blocked behaves
|
|
30
|
+
* as if nothing was remembered.
|
|
31
|
+
*/
|
|
32
|
+
export function createAreaMemory(storage, key = AREA_NAV_MEMORY_KEY) {
|
|
33
|
+
const read = () => {
|
|
34
|
+
try {
|
|
35
|
+
const raw = storage?.getItem?.(key);
|
|
36
|
+
const value = raw ? JSON.parse(raw) : null;
|
|
37
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
38
|
+
} catch {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
return Object.freeze({
|
|
43
|
+
get(areaId) {
|
|
44
|
+
const value = read()[areaId];
|
|
45
|
+
return typeof value === 'string' ? value : null;
|
|
46
|
+
},
|
|
47
|
+
set(areaId, screenId) {
|
|
48
|
+
try {
|
|
49
|
+
storage?.setItem?.(key, JSON.stringify({ ...read(), [areaId]: screenId }));
|
|
50
|
+
} catch {
|
|
51
|
+
// Not remembered; the area opens its default screen next time.
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The browser's localStorage when it can be reached, otherwise null. */
|
|
58
|
+
export function browserAreaStorage() {
|
|
59
|
+
try {
|
|
60
|
+
return globalThis.localStorage ?? null;
|
|
61
|
+
} catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The screen an area link opens: the remembered screen if it is still shown
|
|
68
|
+
* there, else the area's default, else its first shown screen. External links
|
|
69
|
+
* (opened in another tab) are never a target.
|
|
70
|
+
*/
|
|
71
|
+
export function resolveAreaTarget(area, { remembered = null, isShown = () => true } = {}) {
|
|
72
|
+
const candidates = area.screens.filter((screen) => !screen.external && isShown(screen.id)).map((screen) => screen.id);
|
|
73
|
+
if (remembered && candidates.includes(remembered)) return remembered;
|
|
74
|
+
if (area.defaultScreen && candidates.includes(area.defaultScreen)) return area.defaultScreen;
|
|
75
|
+
return candidates[0] ?? null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @param {object} options
|
|
80
|
+
* @param {Document} options.document
|
|
81
|
+
* @param {Array<{id: string, label: string|null, defaultScreen?: string, screenIds: string[]}>} options.areas
|
|
82
|
+
* In menu order. A null label takes the label of the area's only screen.
|
|
83
|
+
* @param {Array<{id: string, label: string, href?: string, external?: boolean, hidden?: boolean}>} options.screens
|
|
84
|
+
* @param {{get(areaId: string): string|null, set(areaId: string, screenId: string): void}} [options.memory]
|
|
85
|
+
* @param {(screenId: string) => string} [options.hrefFor] Address of a screen (default `#<id>`).
|
|
86
|
+
* @param {(screenId: string, event: Event) => void} [options.onSelect]
|
|
87
|
+
* @param {(area: object) => Node|null} [options.iconFor] Icon in front of an area link.
|
|
88
|
+
* @param {string} [options.linkClassName] Extra class for the area links (the host's look).
|
|
89
|
+
*/
|
|
90
|
+
export function createAreaNav({
|
|
91
|
+
document: doc,
|
|
92
|
+
areas: areaInput,
|
|
93
|
+
screens: screenInput,
|
|
94
|
+
memory = createAreaMemory(null),
|
|
95
|
+
hrefFor = (screenId) => `#${screenId}`,
|
|
96
|
+
onSelect,
|
|
97
|
+
iconFor,
|
|
98
|
+
linkClassName = '',
|
|
99
|
+
label = '画面',
|
|
100
|
+
} = {}) {
|
|
101
|
+
if (!doc || typeof doc.createElement !== 'function') throw new Error('document_unavailable');
|
|
102
|
+
const screens = new Map((screenInput ?? []).map((screen) => [screen.id, {
|
|
103
|
+
id: screen.id,
|
|
104
|
+
label: screen.label,
|
|
105
|
+
href: screen.href ?? null,
|
|
106
|
+
external: screen.external === true,
|
|
107
|
+
hidden: screen.hidden === true,
|
|
108
|
+
count: null,
|
|
109
|
+
waiting: false,
|
|
110
|
+
}]));
|
|
111
|
+
const areas = (areaInput ?? []).map((area) => ({
|
|
112
|
+
id: area.id,
|
|
113
|
+
label: area.label ?? null,
|
|
114
|
+
defaultScreen: area.defaultScreen ?? null,
|
|
115
|
+
screens: area.screenIds.map((id) => screens.get(id)).filter(Boolean),
|
|
116
|
+
})).filter((area) => area.screens.length > 0);
|
|
117
|
+
const areaByScreen = new Map();
|
|
118
|
+
for (const area of areas) for (const screen of area.screens) areaByScreen.set(screen.id, area);
|
|
119
|
+
|
|
120
|
+
let activeScreenId = null;
|
|
121
|
+
const isShown = (screenId) => screens.get(screenId)?.hidden === false;
|
|
122
|
+
const shownScreens = (area) => area.screens.filter((screen) => isShown(screen.id));
|
|
123
|
+
const targetFor = (areaId) => {
|
|
124
|
+
const area = areas.find((candidate) => candidate.id === areaId);
|
|
125
|
+
return area ? resolveAreaTarget(area, { remembered: memory.get(area.id), isShown }) : null;
|
|
126
|
+
};
|
|
127
|
+
const screenHref = (screen) => screen.href ?? hrefFor(screen.id);
|
|
128
|
+
const areaLabel = (area) => area.label ?? area.screens[0].label;
|
|
129
|
+
|
|
130
|
+
const countBadge = (count, ariaLabel) => makeElement(doc, 'span', {
|
|
131
|
+
className: 'bb-area-count',
|
|
132
|
+
text: count,
|
|
133
|
+
attrs: { 'aria-label': ariaLabel },
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const nav = makeElement(doc, 'nav', { className: 'bb-area-nav', attrs: { 'aria-label': label, 'data-contract-version': AREA_NAV_CONTRACT_VERSION } });
|
|
137
|
+
const tabs = makeElement(doc, 'nav', { className: 'bb-area-tabs' });
|
|
138
|
+
tabs.hidden = true;
|
|
139
|
+
const areaLinks = new Map();
|
|
140
|
+
|
|
141
|
+
for (const area of areas) {
|
|
142
|
+
const link = makeElement(doc, 'a', {
|
|
143
|
+
className: ['bb-area-link', linkClassName].filter(Boolean).join(' '),
|
|
144
|
+
attrs: { 'data-area': area.id },
|
|
145
|
+
});
|
|
146
|
+
link.addEventListener('click', (event) => {
|
|
147
|
+
const target = targetFor(area.id);
|
|
148
|
+
if (target) onSelect?.(target, event);
|
|
149
|
+
});
|
|
150
|
+
areaLinks.set(area.id, link);
|
|
151
|
+
nav.append(link);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function renderAreaLink(area) {
|
|
155
|
+
const link = areaLinks.get(area.id);
|
|
156
|
+
const shown = shownScreens(area);
|
|
157
|
+
link.hidden = !shown.some((screen) => !screen.external);
|
|
158
|
+
const target = targetFor(area.id);
|
|
159
|
+
if (target) link.setAttribute('href', screenHref(screens.get(target)));
|
|
160
|
+
else link.removeAttribute('href');
|
|
161
|
+
if (areaByScreen.get(activeScreenId) === area) link.setAttribute('aria-current', 'page');
|
|
162
|
+
else link.removeAttribute('aria-current');
|
|
163
|
+
const waiting = shown.reduce((sum, screen) => sum + (screen.waiting && Number.isInteger(screen.count) ? screen.count : 0), 0);
|
|
164
|
+
const icon = iconFor?.(area) ?? null;
|
|
165
|
+
link.replaceChildren(...[
|
|
166
|
+
icon,
|
|
167
|
+
makeElement(doc, 'span', { className: 'bb-area-link-label', text: areaLabel(area) }),
|
|
168
|
+
waiting > 0 ? countBadge(waiting, `待っているもの${waiting}件`) : null,
|
|
169
|
+
].filter(Boolean));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function renderTabs() {
|
|
173
|
+
const area = areaByScreen.get(activeScreenId) ?? null;
|
|
174
|
+
const shown = area ? shownScreens(area) : [];
|
|
175
|
+
if (!area || shown.length < 2) {
|
|
176
|
+
tabs.hidden = true;
|
|
177
|
+
tabs.replaceChildren();
|
|
178
|
+
tabs.removeAttribute('aria-label');
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
tabs.hidden = false;
|
|
182
|
+
tabs.setAttribute('aria-label', `${areaLabel(area)}の画面`);
|
|
183
|
+
tabs.replaceChildren(...shown.map((screen) => {
|
|
184
|
+
const tab = makeElement(doc, 'a', {
|
|
185
|
+
className: 'bb-area-tab',
|
|
186
|
+
attrs: {
|
|
187
|
+
href: screenHref(screen),
|
|
188
|
+
'data-screen-tab': screen.id,
|
|
189
|
+
'aria-current': screen.id === activeScreenId ? 'page' : null,
|
|
190
|
+
target: screen.external ? '_blank' : null,
|
|
191
|
+
rel: screen.external ? 'noopener' : null,
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
tab.append(makeElement(doc, 'span', { text: screen.label }));
|
|
195
|
+
if (Number.isInteger(screen.count)) {
|
|
196
|
+
tab.append(countBadge(screen.count, screen.waiting ? `待っているもの${screen.count}件` : `${screen.count}件`));
|
|
197
|
+
}
|
|
198
|
+
if (!screen.external) tab.addEventListener('click', (event) => onSelect?.(screen.id, event));
|
|
199
|
+
return tab;
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function render() {
|
|
204
|
+
for (const area of areas) renderAreaLink(area);
|
|
205
|
+
renderTabs();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const controller = {
|
|
209
|
+
nav,
|
|
210
|
+
tabs,
|
|
211
|
+
get state() {
|
|
212
|
+
const area = areaByScreen.get(activeScreenId) ?? null;
|
|
213
|
+
return { activeScreenId, activeAreaId: area?.id ?? null };
|
|
214
|
+
},
|
|
215
|
+
areaOf(screenId) {
|
|
216
|
+
return areaByScreen.get(screenId)?.id ?? null;
|
|
217
|
+
},
|
|
218
|
+
targetFor,
|
|
219
|
+
/** Marks the shown screen; a screen in an area becomes that area's last screen. */
|
|
220
|
+
show(screenId) {
|
|
221
|
+
activeScreenId = screenId;
|
|
222
|
+
const area = areaByScreen.get(screenId);
|
|
223
|
+
const screen = screens.get(screenId);
|
|
224
|
+
if (area && screen && !screen.external && isShown(screenId)) memory.set(area.id, screenId);
|
|
225
|
+
render();
|
|
226
|
+
return controller;
|
|
227
|
+
},
|
|
228
|
+
setHidden(screenId, hidden) {
|
|
229
|
+
const screen = screens.get(screenId);
|
|
230
|
+
if (!screen) return controller;
|
|
231
|
+
screen.hidden = hidden === true;
|
|
232
|
+
render();
|
|
233
|
+
return controller;
|
|
234
|
+
},
|
|
235
|
+
/** `count` null removes it. `waiting` counts are added up on the area link too. */
|
|
236
|
+
setCount(screenId, count, { waiting = false } = {}) {
|
|
237
|
+
const screen = screens.get(screenId);
|
|
238
|
+
if (!screen) return controller;
|
|
239
|
+
screen.count = Number.isInteger(count) && count >= 0 ? count : null;
|
|
240
|
+
screen.waiting = waiting === true;
|
|
241
|
+
render();
|
|
242
|
+
return controller;
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
render();
|
|
246
|
+
return controller;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export default createAreaNav;
|
|
@@ -248,3 +248,12 @@
|
|
|
248
248
|
.bb-fov-philosophy-card .bb-fov-original { border-top: 0; padding-top: 0; }
|
|
249
249
|
.bb-fov-model-card .bb-fov-original { margin-top: 12px; padding-top: 10px; overflow-wrap: anywhere; }
|
|
250
250
|
.bb-fov-objective-ledger .bb-ws-ledger-row:focus-visible { outline: 2px solid var(--bb-color-focus); outline-offset: 2px; }
|
|
251
|
+
/* Whose what an objective waits for, and what can be done with it (story-objective-row-actions-v1). */
|
|
252
|
+
.bb-fov-waiting { display: grid; gap: 2px; min-width: 0; }
|
|
253
|
+
.bb-fov-waiting strong { font-weight: 600; }
|
|
254
|
+
.bb-fov-waiting small { color: var(--bb-color-muted); font-size: 12px; line-height: 1.4; }
|
|
255
|
+
.bb-fov-ledger-hint { margin: 8px 0 0; color: var(--bb-color-muted); font-size: 12px; }
|
|
256
|
+
.bb-fov-actions { display: grid; gap: 8px; justify-items: start; padding: 12px; border: 1px solid var(--bb-color-border); border-radius: 8px; background: var(--bb-color-surface-subtle, rgb(0 0 0 / 2%)); }
|
|
257
|
+
.bb-fov-actions h3 { margin: 0; }
|
|
258
|
+
.bb-fov-action-note { margin: 0; color: var(--bb-color-muted); font-size: 13px; }
|
|
259
|
+
.bb-fov-action-note.is-unavailable { color: var(--bb-color-ink); }
|
|
@@ -507,13 +507,79 @@ function objectiveCard(doc, record, variableMap) {
|
|
|
507
507
|
return card;
|
|
508
508
|
}
|
|
509
509
|
|
|
510
|
-
|
|
510
|
+
/**
|
|
511
|
+
* Whose what an objective waits for (story-objective-row-actions-v1), from its own record: the items its
|
|
512
|
+
* current state says were not confirmed when it was saved, or else the fields it has not recorded, and
|
|
513
|
+
* the accountable person who would settle them. Nothing is waited for when the record names nothing.
|
|
514
|
+
*/
|
|
515
|
+
export function objectiveWaiting(record) {
|
|
516
|
+
const definition = recordDefinition(record);
|
|
517
|
+
const current = currentStateFor(record);
|
|
518
|
+
const accountable = nonEmpty(definition.accountableId);
|
|
519
|
+
const items = current.missing.length ? current.missing : missingObjectiveFields(record);
|
|
520
|
+
if (items.length === 0) return null;
|
|
521
|
+
const what = `${current.missing.length ? '未確認' : '未記録'}:${items.join('・')}`;
|
|
522
|
+
const who = accountable ? '責任者の確認待ち' : '責任者が未記録のため、確かめる人が決まっていません';
|
|
523
|
+
return { what, who, items, kind: current.missing.length ? 'unconfirmed' : 'unrecorded', accountableRecorded: Boolean(accountable) };
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function waitingElement(doc, waiting) {
|
|
527
|
+
const cell = makeElement(doc, 'span', { className: 'bb-fov-waiting' });
|
|
528
|
+
if (!waiting) {
|
|
529
|
+
cell.append(makeElement(doc, 'span', { className: 'bb-fov-missing', text: '記録上はありません' }));
|
|
530
|
+
return cell;
|
|
531
|
+
}
|
|
532
|
+
cell.append(makeElement(doc, 'strong', { className: 'bb-fov-missing', text: waiting.what }), makeElement(doc, 'small', { text: waiting.who }));
|
|
533
|
+
return cell;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* What the reader can do with this objective, from the host (`callbacks.objectiveAction`): a button that
|
|
538
|
+
* goes where it is corrected, or the reason it cannot be from here. Without a host action the screen says
|
|
539
|
+
* it only reads; it never shows a control that does nothing.
|
|
540
|
+
*/
|
|
541
|
+
function objectiveActionElement(doc, record, recordContexts, callbacks, dialog) {
|
|
542
|
+
const definition = recordDefinition(record), details = detailsFor(record);
|
|
543
|
+
const part = makeElement(doc, 'section', { className: 'bb-fov-actions' });
|
|
544
|
+
part.append(makeElement(doc, 'h3', { text: 'この目的でできること' }));
|
|
545
|
+
const context = recordContexts?.get(record);
|
|
546
|
+
const action = typeof callbacks?.objectiveAction === 'function'
|
|
547
|
+
? callbacks.objectiveAction({
|
|
548
|
+
objectiveId: definition.id ?? null,
|
|
549
|
+
revision: definition.revision ?? null,
|
|
550
|
+
title: formatAny(details.title) ?? formatAny(definition.meaning) ?? null,
|
|
551
|
+
scopeIds: context?.scopeIds ?? [],
|
|
552
|
+
record,
|
|
553
|
+
})
|
|
554
|
+
: null;
|
|
555
|
+
if (action && typeof action.onSelect === 'function') {
|
|
556
|
+
part.append(workspaceButton(doc, {
|
|
557
|
+
text: `${action.label ?? '目的を直す・現状を記録する'} ›`,
|
|
558
|
+
variant: 'primary',
|
|
559
|
+
onClick: () => { dialog()?.close(); action.onSelect(); },
|
|
560
|
+
}));
|
|
561
|
+
part.append(makeElement(doc, 'p', { className: 'bb-fov-action-note', text: action.description ?? '目指す状態・評価基準・現状を直し、新しい版として保存します。保存すると、この一覧の「待っていること」が変わります。' }));
|
|
562
|
+
} else {
|
|
563
|
+
part.append(makeElement(doc, 'p', {
|
|
564
|
+
className: 'bb-fov-action-note is-unavailable',
|
|
565
|
+
text: nonEmpty(action?.unavailable) ?? 'この画面は読むだけです。ここからは記録を変えられません。',
|
|
566
|
+
}));
|
|
567
|
+
}
|
|
568
|
+
return part;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function objectiveReading(doc, record, variableMap, recordContexts, callbacks = {}, dialog = () => null) {
|
|
511
572
|
const definition = recordDefinition(record), details = detailsFor(record);
|
|
512
573
|
const body = makeElement(doc, 'div', { className: 'bb-fov-reading' });
|
|
513
574
|
const section = (title, content) => {
|
|
514
575
|
const part = makeElement(doc, 'section');
|
|
515
576
|
part.append(makeElement(doc, 'h3', { text: title }), content); body.append(part);
|
|
516
577
|
};
|
|
578
|
+
const waiting = objectiveWaiting(record);
|
|
579
|
+
section('待っていること', waiting
|
|
580
|
+
? workspaceDefinition(doc, [['何を', waiting.what], ['誰が', waiting.who]])
|
|
581
|
+
: makeElement(doc, 'p', { text: '記録上、待っていることはありません。達成・採用・検証済みを意味しません。' }));
|
|
582
|
+
body.append(objectiveActionElement(doc, record, recordContexts, callbacks, dialog));
|
|
517
583
|
section('達成条件', workspaceDefinition(doc, [
|
|
518
584
|
['目指す状態', formatAny(definition.desiredState)],
|
|
519
585
|
['評価基準', criteriaElement(doc, definition, details, variableMap)],
|
|
@@ -560,18 +626,21 @@ function renderObjectives(doc, catalog, viewState, callbacks, recordContexts) {
|
|
|
560
626
|
viewState.dialog?.close();
|
|
561
627
|
viewState.dialog = workspaceDialog(doc, {
|
|
562
628
|
title: formatAny(details.title) ?? formatAny(definition.meaning) ?? UNNAMED_RECORD, opener,
|
|
563
|
-
content: objectiveReading(doc, record, recordContexts?.get(record)?.variableMap ?? variableMap, recordContexts),
|
|
629
|
+
content: objectiveReading(doc, record, recordContexts?.get(record)?.variableMap ?? variableMap, recordContexts, callbacks, () => viewState.dialog),
|
|
564
630
|
});
|
|
565
631
|
},
|
|
566
632
|
cells: [
|
|
567
633
|
{ primary: formatAny(details.title) ?? formatAny(definition.meaning) ?? UNNAMED_RECORD },
|
|
568
634
|
current.text ?? current.status ?? '未記録',
|
|
569
|
-
|
|
635
|
+
waitingElement(doc, objectiveWaiting(record)),
|
|
570
636
|
formatDate(current.asOf),
|
|
571
637
|
],
|
|
572
638
|
};
|
|
573
639
|
});
|
|
574
|
-
section.append(workspaceLedger(doc, { className: 'bb-fov-objective-ledger', ariaLabel: '登録された目的', columns: ['目的', '現状', '
|
|
640
|
+
section.append(workspaceLedger(doc, { className: 'bb-fov-objective-ledger', ariaLabel: '登録された目的', columns: ['目的', '現状', '待っていること', '確認日'], rows }));
|
|
641
|
+
section.append(makeElement(doc, 'p', { className: 'bb-fov-ledger-hint', text: typeof callbacks?.objectiveAction === 'function'
|
|
642
|
+
? '行を押すと、目的の詳細と、この目的でできること(直す・現状を記録する)が開きます。'
|
|
643
|
+
: '行を押すと、目的の詳細が開きます。この画面は読むだけです。' }));
|
|
575
644
|
return section;
|
|
576
645
|
}
|
|
577
646
|
|
|
@@ -912,13 +981,14 @@ export function renderFoundationCollectionOverview(root, sources, {
|
|
|
912
981
|
if (existing) {
|
|
913
982
|
const context = contexts.get(existing);
|
|
914
983
|
if (!context.sources.includes(source.label)) context.sources.push(source.label);
|
|
984
|
+
if (!context.scopeIds.includes(source.scopeId)) context.scopeIds.push(source.scopeId);
|
|
915
985
|
context.label = `${shared ? '組織共通 / ' : ''}${context.sources.join('・')}`;
|
|
916
986
|
continue;
|
|
917
987
|
}
|
|
918
988
|
const record = { ...original };
|
|
919
989
|
seen.set(key, record);
|
|
920
990
|
catalog[kind].push(record);
|
|
921
|
-
contexts.set(record, { key, variableMap, sources: [source.label], label: `${shared ? '組織共通 / ' : ''}${source.label}` });
|
|
991
|
+
contexts.set(record, { key, variableMap, sources: [source.label], scopeIds: [source.scopeId], label: `${shared ? '組織共通 / ' : ''}${source.label}` });
|
|
922
992
|
}
|
|
923
993
|
}
|
|
924
994
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 「情報の種類とつながり方」. Load after workspace-kit.css and graph-view-shared.css.
|
|
3
|
+
* Column templates of the kinds and relations ledgers, with and without the
|
|
4
|
+
* count column, and a 760px variant.
|
|
5
|
+
* Uses only the shared tokens in brainbase-tokens.css.
|
|
6
|
+
*/
|
|
7
|
+
.bb-go .bb-go-caption,
|
|
8
|
+
.bb-go .bb-go-note {
|
|
9
|
+
margin: 0 0 10px;
|
|
10
|
+
color: var(--bb-color-muted);
|
|
11
|
+
font-size: 12px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.bb-go .bb-ws-section-title {
|
|
15
|
+
margin-top: 30px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.bb-go > .bb-graph-plain-list {
|
|
19
|
+
color: var(--bb-color-muted);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.bb-go > .bb-graph-audit {
|
|
23
|
+
margin-top: 14px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.bb-go-type-ledger .bb-ws-ledger-row {
|
|
27
|
+
grid-template-columns: 160px minmax(0, 1fr);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.bb-go-type-ledger.is-counted .bb-ws-ledger-row {
|
|
31
|
+
grid-template-columns: 160px minmax(0, 1fr) 96px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.bb-go-relation-ledger .bb-ws-ledger-row {
|
|
35
|
+
grid-template-columns: 140px minmax(0, 1.4fr) minmax(0, 1.6fr);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.bb-go-relation-ledger.is-counted .bb-ws-ledger-row {
|
|
39
|
+
grid-template-columns: 140px minmax(0, 1.4fr) minmax(0, 1.6fr) minmax(0, .8fr);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.bb-go-type-ledger .bb-ws-ledger-row,
|
|
43
|
+
.bb-go-relation-ledger .bb-ws-ledger-row {
|
|
44
|
+
min-height: 48px;
|
|
45
|
+
align-items: start;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Meanings and kinds are read, not scanned: let them wrap. */
|
|
49
|
+
.bb-go-type-ledger .bb-ws-ledger-row > span,
|
|
50
|
+
.bb-go-relation-ledger .bb-ws-ledger-row > span {
|
|
51
|
+
white-space: normal;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.bb-go-type-ledger .bb-ws-ledger-row:not(.bb-ws-ledger-head) > :first-child,
|
|
55
|
+
.bb-go-relation-ledger .bb-ws-ledger-row:not(.bb-ws-ledger-head) > :first-child {
|
|
56
|
+
color: var(--bb-color-ink);
|
|
57
|
+
font-weight: 690;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.bb-go-kinds {
|
|
61
|
+
margin: 0;
|
|
62
|
+
padding: 0;
|
|
63
|
+
list-style: none;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.bb-go-kinds > li + li {
|
|
67
|
+
margin-top: 4px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@media (max-width: 760px) {
|
|
71
|
+
.bb-go-type-ledger .bb-ws-ledger-row,
|
|
72
|
+
.bb-go-type-ledger.is-counted .bb-ws-ledger-row {
|
|
73
|
+
grid-template-columns: 96px minmax(0, 1fr);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.bb-go-type-ledger.is-counted .bb-ws-ledger-row > :nth-child(3) {
|
|
77
|
+
display: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.bb-go-relation-ledger .bb-ws-ledger-row,
|
|
81
|
+
.bb-go-relation-ledger.is-counted .bb-ws-ledger-row {
|
|
82
|
+
grid-template-columns: 96px minmax(0, 1fr);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.bb-go-relation-ledger .bb-ws-ledger-row > :nth-child(n + 3) {
|
|
86
|
+
display: none;
|
|
87
|
+
}
|
|
88
|
+
}
|