@quolu/lattice 0.12.14 → 0.12.15
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/package.json +1 -1
- package/src/todo-gantt-html.mjs +18 -5
package/package.json
CHANGED
package/src/todo-gantt-html.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from './todo-markdown-renderer.mjs';
|
|
7
7
|
import { renderTodoGanttSvg, TODO_GANTT_STATUS_PRESENTATION } from './todo-gantt-svg.mjs';
|
|
8
8
|
|
|
9
|
-
export const TODO_GANTT_RENDERER_VERSION = 'lattice.todo_gantt_renderer.
|
|
9
|
+
export const TODO_GANTT_RENDERER_VERSION = 'lattice.todo_gantt_renderer.v12';
|
|
10
10
|
export const TODO_GANTT_PROSE_MAX_BYTES = 8 * 1024 * 1024;
|
|
11
11
|
export const TODO_GANTT_HTML_MAX_BYTES = 24 * 1024 * 1024;
|
|
12
12
|
|
|
@@ -190,8 +190,12 @@ function renderRelationList(relations, sectionByKey, lookup, emptyText, folds =
|
|
|
190
190
|
}).join('')}</ul>`;
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
/** Phase states that are over: nothing is dispatched or judged under them again. */
|
|
194
|
+
const SETTLED_PHASE_STATUS = Object.freeze(['accepted', 'rejected']);
|
|
195
|
+
|
|
193
196
|
function renderPhaseProgress(readModel) {
|
|
194
197
|
const rows = [];
|
|
198
|
+
const settledRows = [];
|
|
195
199
|
for (const member of readModel.members) {
|
|
196
200
|
if (!['lattice.todo_plan.v4', 'lattice.todo_plan.v5'].includes(member.plan.schema)) continue;
|
|
197
201
|
const phases = new Map(member.snapshot.phases.map((phase) => [phase.phase_id, phase]));
|
|
@@ -200,15 +204,23 @@ function renderPhaseProgress(readModel) {
|
|
|
200
204
|
const states = new Map(member.tasks.map((task) => [task.task_id, task.status]));
|
|
201
205
|
const done = tasks.filter((task) => states.get(task.task_id) === 'done').length;
|
|
202
206
|
const state = phases.get(phase.phase_id);
|
|
203
|
-
|
|
207
|
+
const row = `<li class="phase-progress status-${escapeHtmlAttribute(state.status)}"><header><strong>${escapeHtmlText(phase.title ?? phase.phase_id)}</strong><span>${escapeHtmlText(state.status)}</span></header><p><code>${escapeHtmlText(`${member.plan.plan_key}/${phase.phase_id}`)}</code> — policy <code>${escapeHtmlText(phase.gate_policy)}</code> — ToDo ${done}/${tasks.length}</p><progress max="${tasks.length}" value="${done}">${done}/${tasks.length}</progress></li>`;
|
|
208
|
+
// A settled Phase is history. It stays reachable, but it does not push the
|
|
209
|
+
// live ones off the first screen.
|
|
210
|
+
(SETTLED_PHASE_STATUS.includes(state.status) ? settledRows : rows).push(row);
|
|
204
211
|
}
|
|
205
212
|
}
|
|
206
213
|
const decoupled = readModel.members.some(({ plan }) => plan.schema === 'lattice.todo_plan.v5');
|
|
207
214
|
const guidance = decoupled
|
|
208
215
|
? 'ToDo完了とPhase受理は別です。Phaseは重監査の順序を表し、通常ToDoの開始順はToDo依存だけで決まります。'
|
|
209
216
|
: 'ToDo完了とPhase受理は別です。<code>gate_ready</code>では後続Phaseはまだ解放されません。';
|
|
210
|
-
|
|
211
|
-
|
|
217
|
+
if (rows.length === 0 && settledRows.length === 0) return '';
|
|
218
|
+
const liveList = rows.length === 0
|
|
219
|
+
? '<p class="readiness-note">進行中のPhaseはありません。</p>'
|
|
220
|
+
: `<ol>${rows.join('')}</ol>`;
|
|
221
|
+
const settledList = settledRows.length === 0 ? ''
|
|
222
|
+
: `<details class="phase-settled"><summary>決着済みPhase ${settledRows.length}件</summary><ol>${settledRows.join('')}</ol></details>`;
|
|
223
|
+
return `<section class="phase-overview"><h2>Phase進捗</h2><p>${guidance}</p>${liveList}${settledList}</section>`;
|
|
212
224
|
}
|
|
213
225
|
|
|
214
226
|
function renderRightPane(sections, layout, presentation, readModel) {
|
|
@@ -347,7 +359,8 @@ body{display:grid;grid-template-rows:minmax(0,1fr);height:100vh;margin:0;backgro
|
|
|
347
359
|
.fold-chip{padding:2px 8px;border:1px solid var(--border);border-radius:9999px;background:var(--surface-2);color:var(--text-primary);font-weight:650}
|
|
348
360
|
.fold-note{flex:1 0 100%;margin:4px 0 0;color:var(--text-secondary);font-weight:400}
|
|
349
361
|
.task-index-folded{margin-top:8px}
|
|
350
|
-
.task-index-folded>summary{cursor:pointer;padding:6px 0;color:var(--text-secondary);font-weight:600}
|
|
362
|
+
.task-index-folded>summary,.phase-settled>summary{cursor:pointer;padding:6px 0;color:var(--text-secondary);font-weight:600}
|
|
363
|
+
.phase-settled>summary:focus-visible{outline:2px solid var(--text-primary);outline-offset:2px}
|
|
351
364
|
.status-in-progress .node-surface{fill:var(--surface-1);stroke:var(--accent);stroke-width:2}
|
|
352
365
|
.status-in-progress .status-mark{fill:var(--accent)}
|
|
353
366
|
.status-in-progress .status-bar{stroke:var(--accent);stroke-width:2;stroke-linecap:round}
|