',
===== function renderCenterCategory( =====
00507: function selectedCategoryObject() {
00508: if (!state.selectedCategory) return null;
00509: const cats = (state.hubIndex && Array.isArray(state.hubIndex.categories)) ? state.hubIndex.categories : [];
00510: return cats.find(function (c) {
00511: return String(c.id || "") === String(state.selectedCategory);
00512: }) || null;
00513: }
00514:
00515: function renderCenterCategory(ph, cat) {
00516: if (!els.selectedStageName) return;
00517: if (els.selectedStageName) els.selectedStageName.textContent = cat.title || ph.name || "Category";
00518: if (els.selectedStageDesc) els.selectedStageDesc.textContent = cat.sub || "Category view from canonical hub index.";
00519: if (els.selectedStageTotal) els.selectedStageTotal.innerHTML = ((cat.docs || []).length) + ' docs
in category';
00520: if (els.selectedStageDonut) els.selectedStageDonut.innerHTML = donutMarkup(0, "category");
00521: if (els.selectedPipelineSteps) {
00522: const docs = Array.isArray(cat.docs) ? cat.docs : [];
00523: els.selectedPipelineSteps.innerHTML = docs.length ? docs.map(function (doc) {
00524: return '
' + (doc.title || doc.label || doc.id || "item") + '' + (doc.type || "doc") + '';
00525: }).join("") : '
No documents registeredMISSING';
00526: }
00527: }
00528:
00529: function renderCenterBucket(ph, cat, bucket) {
00530: if (els.selectedStageName) els.selectedStageName.textContent = (cat.title || ph.name || "Category") + " / " + titleize(bucket);
00531: if (els.selectedStageDesc) els.selectedStageDesc.textContent = "Bucket detail from canonical category documents.";
00532: const docs = Array.isArray(cat.docs) ? cat.docs : [];
00533: if (els.selectedStageTotal) els.selectedStageTotal.innerHTML = docs.length + ' docs
in bucket view';
00534: if (els.selectedStageDonut) els.selectedStageDonut.innerHTML = donutMarkup(0, titleize(bucket));
00535: if (els.selectedPipelineSteps) {
00536: els.selectedPipelineSteps.innerHTML = docs.length ? docs.map(function (doc) {
00537: return [
00538: '
',
00539: '' + (doc.title || doc.label || doc.id || "item") + '',
00540: '' + (doc.type || "doc") + '',
00541: ''
00542: ].join("");
00543: }).join("") : '
No documents registeredMISSING';
00544: }
00545: }
00546:
00547: function renderCanonicalSelection() {
00548: const ph = selectedPhaseObject();
00549: const cat = selectedCategoryObject();
00550:
00551: if (!ph) return;
00552:
00553: if (cat && state.selectedBucket) {
00554: renderCenterBucket(ph, cat, state.selectedBucket);
00555: return;
00556: }
00557:
00558: if (cat) {
00559: renderCenterCategory(ph, cat);
00560: return;
00561: }
00562: }
00563:
00564:
00565: function selectStage(stageKey) {
00566: state.selectedStage = normStageKey(stageKey);
00567: const items = ((state.contentIndex && state.contentIndex.content_index) || []);
00568: const navItem = items.find(function (item) {
00569: return normStageKey(item.stage_key) === state.selectedStage;
00570: }) || null;
00571: const rollup = stageRollup(state.selectedStage);
00572: const pct = rollup && typeof rollup.progress_pct === "number" ? Math.round(rollup.progress_pct) : 0;
00573: const totalSteps = rollup && Array.isArray(rollup.step_statuses) ? rollup.step_statuses.length : 0;
00574:
00575: if (els.heroTitle) els.heroTitle.textContent = navItem ? navItem.label : titleize(state.selectedStage);
00576: if (els.heroSubtitle) {
00577: els.heroSubtitle.textContent = "Runtime-backed stage view. Contract and runtime data are rendered from panel exports only.";
00578: }
00579: if (els.stageOrderBadge) {
00580: els.stageOrderBadge.textContent = navItem ? ("ORDER " + navItem.deployment_order) : "—";
00581: }
00582: if (els.selectedStageName) {
00583: els.selectedStageName.textContent = navItem ? navItem.label : titleize(state.selectedStage);
00584: }
00585: if (els.selectedStageDesc) {
00586: els.selectedStageDesc.textContent = "Stage completion is read from runtime_status stage_rollup.progress_pct.";
00587: }
00588: if (els.selectedStageTotal) {
00589: els.selectedStageTotal.innerHTML = totalSteps
00590: ? (totalSteps + ' required steps
in contract')
00591: : 'MISSING stage rollup
in runtime';
00592: }
00593: if (els.selectedStageDonut) {
00594: els.selectedStageDonut.innerHTML = donutMarkup(pct, "stage completion");
00595: }
00596: if (els.selectedRuntimeBadge) {
00597: setBadge(els.selectedRuntimeBadge, rollup ? runtimeStatusOf(rollup) : "MISSING", rollup ? runtimeStatusOf(rollup) : "MISSING");
00598: }
00599:
00600: renderSelectedPipeline(state.selectedStage, rollup);
00601: renderCanonicalSelection();
00602:
00603: document.querySelectorAll(".stage-btn").forEach(function (btn) {
00604: btn.classList.toggle("active", btn.dataset.stageKey === state.selectedStage);
00605: });
00606: }
00607:
00608: function wireButtons() {
00609: [
00610: ["Manifest", els.btnOpenManifest, state.manifest],
00611: ["Project Progress", els.btnOpenContract, state.projectProgress],
00612: ["Host Runtime", els.btnOpenHost, state.hostRuntime],
00613: ["Docker Runtime", els.btnOpenDocker, state.dockerRuntime],
00614: ["Runtime Status", els.btnOpenRuntime, state.runtimeStatus]
00615: ].forEach(function (entry) {
00616: const label = entry[0];
00617: const btn = entry[1];
00618: const payload = entry[2];
00619: if (!btn) return;
00620: btn.onclick = function () {
00621: openJson(label, payload || { status: "MISSING" });
00622: };
00623: });
00624: }
00625:
00626: async function boot() {
00627: try {
00628: const core = await Promise.all([
00629: getJsonOptional("panel_manifest.json"),
00630: getJsonOptional("hub_index.json"),
00631: getJsonOptional("panel_content_index.json"),
00632: getJsonOptional("panel_navigation_spec.json"),
00633: getJsonOptional("subcategory_pipelines.json"),
00634: getJsonOptional("project_progress.json"),
00635: getJsonOptional("host_runtime.json"),
00636: getJsonOptional("docker_runtime.json"),
00637: getJsonOptional("runtime_status.json")
00638: ]);
00639:
00640: state.manifest = core[0];
00641: state.hubIndex = core[1];
00642: state.contentIndex = core[2];
00643: state.navigationSpec = core[3];
00644: state.pipelines = core[4];
00645: state.projectProgress = core[5];
00646: state.hostRuntime = core[6];
00647: state.dockerRuntime = core[7];
00648: state.runtimeStatus = core[8];
00649:
00650: renderGlobal();
00651: renderCanonicalNav();
00652: renderHostRuntime();
00653: renderDockerRuntime();
00654: renderPipelineBoard();
===== function renderCenterBucket( =====
00521: if (els.selectedPipelineSteps) {
00522: const docs = Array.isArray(cat.docs) ? cat.docs : [];
00523: els.selectedPipelineSteps.innerHTML = docs.length ? docs.map(function (doc) {
00524: return '
' + (doc.title || doc.label || doc.id || "item") + '' + (doc.type || "doc") + '';
00525: }).join("") : '
No documents registeredMISSING';
00526: }
00527: }
00528:
00529: function renderCenterBucket(ph, cat, bucket) {
00530: if (els.selectedStageName) els.selectedStageName.textContent = (cat.title || ph.name || "Category") + " / " + titleize(bucket);
00531: if (els.selectedStageDesc) els.selectedStageDesc.textContent = "Bucket detail from canonical category documents.";
00532: const docs = Array.isArray(cat.docs) ? cat.docs : [];
00533: if (els.selectedStageTotal) els.selectedStageTotal.innerHTML = docs.length + ' docs
in bucket view';
00534: if (els.selectedStageDonut) els.selectedStageDonut.innerHTML = donutMarkup(0, titleize(bucket));
00535: if (els.selectedPipelineSteps) {
00536: els.selectedPipelineSteps.innerHTML = docs.length ? docs.map(function (doc) {
00537: return [
00538: '
',
00539: '' + (doc.title || doc.label || doc.id || "item") + '',
00540: '' + (doc.type || "doc") + '',
00541: ''
00542: ].join("");
00543: }).join("") : '
No documents registeredMISSING';
00544: }
00545: }
00546:
00547: function renderCanonicalSelection() {
00548: const ph = selectedPhaseObject();
00549: const cat = selectedCategoryObject();
00550:
00551: if (!ph) return;
00552:
00553: if (cat && state.selectedBucket) {
00554: renderCenterBucket(ph, cat, state.selectedBucket);
00555: return;
00556: }
00557:
00558: if (cat) {
00559: renderCenterCategory(ph, cat);
00560: return;
00561: }
00562: }
00563:
00564:
00565: function selectStage(stageKey) {
00566: state.selectedStage = normStageKey(stageKey);
00567: const items = ((state.contentIndex && state.contentIndex.content_index) || []);
00568: const navItem = items.find(function (item) {
00569: return normStageKey(item.stage_key) === state.selectedStage;
00570: }) || null;
00571: const rollup = stageRollup(state.selectedStage);
00572: const pct = rollup && typeof rollup.progress_pct === "number" ? Math.round(rollup.progress_pct) : 0;
00573: const totalSteps = rollup && Array.isArray(rollup.step_statuses) ? rollup.step_statuses.length : 0;
00574:
00575: if (els.heroTitle) els.heroTitle.textContent = navItem ? navItem.label : titleize(state.selectedStage);
00576: if (els.heroSubtitle) {
00577: els.heroSubtitle.textContent = "Runtime-backed stage view. Contract and runtime data are rendered from panel exports only.";
00578: }
00579: if (els.stageOrderBadge) {
00580: els.stageOrderBadge.textContent = navItem ? ("ORDER " + navItem.deployment_order) : "—";
00581: }
00582: if (els.selectedStageName) {
00583: els.selectedStageName.textContent = navItem ? navItem.label : titleize(state.selectedStage);
00584: }
00585: if (els.selectedStageDesc) {
00586: els.selectedStageDesc.textContent = "Stage completion is read from runtime_status stage_rollup.progress_pct.";
00587: }
00588: if (els.selectedStageTotal) {
00589: els.selectedStageTotal.innerHTML = totalSteps
00590: ? (totalSteps + ' required steps
in contract')
00591: : 'MISSING stage rollup
in runtime';
00592: }
00593: if (els.selectedStageDonut) {
00594: els.selectedStageDonut.innerHTML = donutMarkup(pct, "stage completion");
00595: }
00596: if (els.selectedRuntimeBadge) {
00597: setBadge(els.selectedRuntimeBadge, rollup ? runtimeStatusOf(rollup) : "MISSING", rollup ? runtimeStatusOf(rollup) : "MISSING");
00598: }
00599:
00600: renderSelectedPipeline(state.selectedStage, rollup);
00601: renderCanonicalSelection();
00602:
00603: document.querySelectorAll(".stage-btn").forEach(function (btn) {
00604: btn.classList.toggle("active", btn.dataset.stageKey === state.selectedStage);
00605: });
00606: }
00607:
00608: function wireButtons() {
00609: [
00610: ["Manifest", els.btnOpenManifest, state.manifest],
00611: ["Project Progress", els.btnOpenContract, state.projectProgress],
00612: ["Host Runtime", els.btnOpenHost, state.hostRuntime],
00613: ["Docker Runtime", els.btnOpenDocker, state.dockerRuntime],
00614: ["Runtime Status", els.btnOpenRuntime, state.runtimeStatus]
00615: ].forEach(function (entry) {
00616: const label = entry[0];
00617: const btn = entry[1];
00618: const payload = entry[2];
00619: if (!btn) return;
00620: btn.onclick = function () {
00621: openJson(label, payload || { status: "MISSING" });
00622: };
00623: });
00624: }
00625:
00626: async function boot() {
00627: try {
00628: const core = await Promise.all([
00629: getJsonOptional("panel_manifest.json"),
00630: getJsonOptional("hub_index.json"),
00631: getJsonOptional("panel_content_index.json"),
00632: getJsonOptional("panel_navigation_spec.json"),
00633: getJsonOptional("subcategory_pipelines.json"),
00634: getJsonOptional("project_progress.json"),
00635: getJsonOptional("host_runtime.json"),
00636: getJsonOptional("docker_runtime.json"),
00637: getJsonOptional("runtime_status.json")
00638: ]);
00639:
00640: state.manifest = core[0];
00641: state.hubIndex = core[1];
00642: state.contentIndex = core[2];
00643: state.navigationSpec = core[3];
00644: state.pipelines = core[4];
00645: state.projectProgress = core[5];
00646: state.hostRuntime = core[6];
00647: state.dockerRuntime = core[7];
00648: state.runtimeStatus = core[8];
00649:
00650: renderGlobal();
00651: renderCanonicalNav();
00652: renderHostRuntime();
00653: renderDockerRuntime();
00654: renderPipelineBoard();
00655:
00656: const firstPhase = ((state.hubIndex && state.hubIndex.phases) || [])[0] || null;
00657:
00658: if (firstPhase) {
00659: const firstPhaseKey = normStageKey(firstPhase.id || firstPhase.stage_key || "");
00660: state.openPhases = new Set([firstPhaseKey]);
00661: state.selectedStage = firstPhaseKey;
00662: renderCanonicalNav();
00663: selectStage(firstPhaseKey);
00664: }
00665:
00666: wireButtons();
00667:
00668: window.__devonPanelDebug = {
===== function selectStage( =====
00557:
00558: if (cat) {
00559: renderCenterCategory(ph, cat);
00560: return;
00561: }
00562: }
00563:
00564:
00565: function selectStage(stageKey) {
00566: state.selectedStage = normStageKey(stageKey);
00567: const items = ((state.contentIndex && state.contentIndex.content_index) || []);
00568: const navItem = items.find(function (item) {
00569: return normStageKey(item.stage_key) === state.selectedStage;
00570: }) || null;
00571: const rollup = stageRollup(state.selectedStage);
00572: const pct = rollup && typeof rollup.progress_pct === "number" ? Math.round(rollup.progress_pct) : 0;
00573: const totalSteps = rollup && Array.isArray(rollup.step_statuses) ? rollup.step_statuses.length : 0;
00574:
00575: if (els.heroTitle) els.heroTitle.textContent = navItem ? navItem.label : titleize(state.selectedStage);
00576: if (els.heroSubtitle) {
00577: els.heroSubtitle.textContent = "Runtime-backed stage view. Contract and runtime data are rendered from panel exports only.";
00578: }
00579: if (els.stageOrderBadge) {
00580: els.stageOrderBadge.textContent = navItem ? ("ORDER " + navItem.deployment_order) : "—";
00581: }
00582: if (els.selectedStageName) {
00583: els.selectedStageName.textContent = navItem ? navItem.label : titleize(state.selectedStage);
00584: }
00585: if (els.selectedStageDesc) {
00586: els.selectedStageDesc.textContent = "Stage completion is read from runtime_status stage_rollup.progress_pct.";
00587: }
00588: if (els.selectedStageTotal) {
00589: els.selectedStageTotal.innerHTML = totalSteps
00590: ? (totalSteps + ' required steps
in contract')
00591: : 'MISSING stage rollup
in runtime';
00592: }
00593: if (els.selectedStageDonut) {
00594: els.selectedStageDonut.innerHTML = donutMarkup(pct, "stage completion");
00595: }
00596: if (els.selectedRuntimeBadge) {
00597: setBadge(els.selectedRuntimeBadge, rollup ? runtimeStatusOf(rollup) : "MISSING", rollup ? runtimeStatusOf(rollup) : "MISSING");
00598: }
00599:
00600: renderSelectedPipeline(state.selectedStage, rollup);
00601: renderCanonicalSelection();
00602:
00603: document.querySelectorAll(".stage-btn").forEach(function (btn) {
00604: btn.classList.toggle("active", btn.dataset.stageKey === state.selectedStage);
00605: });
00606: }
00607:
00608: function wireButtons() {
00609: [
00610: ["Manifest", els.btnOpenManifest, state.manifest],
00611: ["Project Progress", els.btnOpenContract, state.projectProgress],
00612: ["Host Runtime", els.btnOpenHost, state.hostRuntime],
00613: ["Docker Runtime", els.btnOpenDocker, state.dockerRuntime],
00614: ["Runtime Status", els.btnOpenRuntime, state.runtimeStatus]
00615: ].forEach(function (entry) {
00616: const label = entry[0];
00617: const btn = entry[1];
00618: const payload = entry[2];
00619: if (!btn) return;
00620: btn.onclick = function () {
00621: openJson(label, payload || { status: "MISSING" });
00622: };
00623: });
00624: }
00625:
00626: async function boot() {
00627: try {
00628: const core = await Promise.all([
00629: getJsonOptional("panel_manifest.json"),
00630: getJsonOptional("hub_index.json"),
00631: getJsonOptional("panel_content_index.json"),
00632: getJsonOptional("panel_navigation_spec.json"),
00633: getJsonOptional("subcategory_pipelines.json"),
00634: getJsonOptional("project_progress.json"),
00635: getJsonOptional("host_runtime.json"),
00636: getJsonOptional("docker_runtime.json"),
00637: getJsonOptional("runtime_status.json")
00638: ]);
00639:
00640: state.manifest = core[0];
00641: state.hubIndex = core[1];
00642: state.contentIndex = core[2];
00643: state.navigationSpec = core[3];
00644: state.pipelines = core[4];
00645: state.projectProgress = core[5];
00646: state.hostRuntime = core[6];
00647: state.dockerRuntime = core[7];
00648: state.runtimeStatus = core[8];
00649:
00650: renderGlobal();
00651: renderCanonicalNav();
00652: renderHostRuntime();
00653: renderDockerRuntime();
00654: renderPipelineBoard();
00655:
00656: const firstPhase = ((state.hubIndex && state.hubIndex.phases) || [])[0] || null;
00657:
00658: if (firstPhase) {
00659: const firstPhaseKey = normStageKey(firstPhase.id || firstPhase.stage_key || "");
00660: state.openPhases = new Set([firstPhaseKey]);
00661: state.selectedStage = firstPhaseKey;
00662: renderCanonicalNav();
00663: selectStage(firstPhaseKey);
00664: }
00665:
00666: wireButtons();
00667:
00668: window.__devonPanelDebug = {
00669: state: state,
00670: selectStage: selectStage
00671: };
00672: } catch (err) {
00673: if (els.heroTitle) els.heroTitle.textContent = "Panel bootstrap failed";
00674: if (els.heroSubtitle) els.heroSubtitle.textContent = String(err && (err.message || err) || err);
00675: if (els.jsonViewer) els.jsonViewer.textContent = String(err && (err.stack || err.message) || err);
00676: console.error("[DEVON_PANEL_BOOT]", err);
00677: }
00678: }
00679:
00680: boot();
00681: })();
00682:
00683:
00684: document.getElementById('btn-monitor')?.addEventListener('click', () => {
00685: window.open('../monitor/', '_blank');
00686: });
===== function stageRollup( =====
00362:
00363: function stageRows(stageKey) {
00364: const snapshot = ((state.runtimeStatus && state.runtimeStatus.runtime_snapshot) || []);
00365: return snapshot.filter(function (row) {
00366: return normStageKey(row.deployment_stage) === normStageKey(stageKey);
00367: });
00368: }
00369:
00370: function stageRollup(stageKey) {
00371: return stageRows(stageKey).find(function (row) {
00372: return String(row.row_kind || "") === "stage_rollup";
00373: }) || null;
00374: }
00375:
00376: function renderGlobal() {
00377: const snapshot = ((state.runtimeStatus && state.runtimeStatus.runtime_snapshot) || []);
00378: const counts = snapshot.reduce(function (acc, row) {
00379: const s = runtimeStatusOf(row);
00380: acc[s] = (acc[s] || 0) + 1;
00381: return acc;
00382: }, { PASS: 0, FAIL: 0, MISSING: 0, RUNNING: 0, PENDING: 0 });
00383:
00384: if (els.globalPills) {
00385: els.globalPills.innerHTML = [
00386: '
PASS ' + (counts.PASS || 0) + '',
00387: '
FAIL ' + (counts.FAIL || 0) + '',
00388: '
MISSING ' + (counts.MISSING || 0) + '',
00389: '
RUNNING ' + (counts.RUNNING || 0) + '',
00390: '
PENDING ' + (counts.PENDING || 0) + ''
00391: ].join("");
00392: }
00393:
00394: const gp = state.projectProgress && state.projectProgress.global_project_progress;
00395: if (els.projectDonut) {
00396: if (gp && typeof gp.progress_pct === "number") {
00397: els.projectDonut.innerHTML = donutMarkup(Math.round(gp.progress_pct), "project completion");
00398: } else {
00399: els.projectDonut.innerHTML = missingDonutMarkup("project completion");
00400: }
00401: }
00402: }
00403:
00404: function renderNav() {
00405: renderCanonicalNav();
00406: }
00407:
00408: function renderHostRuntime() {
00409: const host = (state.hostRuntime && state.hostRuntime.host_snapshot) || {};
00410: setBadge(els.hostStatusBadge, host.overall_status || "MISSING", safeUpper(host.overall_status || "MISSING"));
00411:
00412: const cpu = host.cpu || {};
00413: const memory = host.memory || {};
00414: const disk = host.disk || {};
00415: const load = host.load || {};
00416:
00417: if (els.hostRuntimeGrid) {
00418: els.hostRuntimeGrid.innerHTML = [
00419: metricBox("CPU", valueOrDash(cpu.usage_pct, "%"), "cores: " + valueOrDash(cpu.core_count, "")),
00420: metricBox("Memory", valueOrDash(memory.usage_pct, "%"), valueOrDash(memory.used_mb, " MB") + " / " + valueOrDash(memory.total_mb, " MB")),
00421: metricBox("Disk", valueOrDash(disk.usage_pct, "%"), valueOrDash(disk.used_gb, " GB") + " / " + valueOrDash(disk.total_gb, " GB")),
00422: metricBox("Load 1m", valueOrDash(load.load_1m, ""), "5m: " + valueOrDash(load.load_5m, "") + " | 15m: " + valueOrDash(load.load_15m, ""))
00423: ].join("");
00424: }
00425: }
00426:
00427: function renderDockerRuntime() {
00428: const runtime = (state.dockerRuntime && state.dockerRuntime.runtime_snapshot) || {};
00429: setBadge(els.dockerStatusBadge, runtime.overall_status || "MISSING", safeUpper(runtime.overall_status || "MISSING"));
00430:
00431: const engine = runtime.docker_engine || {};
00432: const compose = runtime.compose || {};
00433: const images = runtime.images || {};
00434: const volumes = runtime.volumes || {};
00435: const networks = runtime.networks || {};
00436: const containers = Array.isArray(runtime.containers) ? runtime.containers : [];
00437:
00438: if (els.dockerRuntimeGrid) {
00439: els.dockerRuntimeGrid.innerHTML = [
00440: metricBox("Engine", engine.installed === true ? "installed" : (engine.installed === false ? "not installed" : "MISSING"), "version: " + valueOrDash(engine.version, "")),
00441: metricBox("Compose", compose.installed === true ? "installed" : (compose.installed === false ? "not installed" : "MISSING"), "version: " + valueOrDash(compose.version, "")),
00442: metricBox("Containers", String(containers.length), "observable list"),
00443: metricBox("Images", valueOrDash(images.total, ""), "Volumes: " + valueOrDash(volumes.total, "") + " | Networks: " + valueOrDash(networks.total, ""))
00444: ].join("");
00445: }
00446: }
00447:
00448: function renderPipelineBoard() {
00449: const items = ((state.runtimeStatus && state.runtimeStatus.runtime_snapshot) || []);
00450: if (els.pipelineRuntimeCount) {
00451: els.pipelineRuntimeCount.textContent = items.length + " runtime rows";
00452: }
00453: if (!els.pipelineRuntimeBoard) return;
00454: if (!items.length) {
00455: els.pipelineRuntimeBoard.innerHTML = '
No runtime rows
Status is MISSING.
';
00456: return;
00457: }
00458: els.pipelineRuntimeBoard.innerHTML = items.slice(0, 24).map(function (item) {
00459: const status = runtimeStatusOf(item);
00460: return [
00461: '
',
00462: '
' + titleize(item.deployment_stage || "runtime") + ' / ' + titleize(item.technology || item.subcategory || "item") + '
',
00463: '
Kind: ' + titleize(item.row_kind || "runtime_row") + '
',
00464: '
',
00465: '' + status + '',
00466: '' + valueOrDash(item.progress_pct, "%") + '',
00467: '
',
00468: '
'
00469: ].join("");
00470: }).join("");
00471: }
00472:
00473: function renderSelectedPipeline(stageKey, rollup) {
00474: if (!els.selectedPipelineSteps) return;
00475: const pipelines = (state.pipelines && state.pipelines.pipelines) || {};
00476: const contract = pipelines[stageKey] || {};
00477: const seq = Array.isArray(contract.sequence) ? contract.sequence : [];
00478: const stepStatuses = rollup && Array.isArray(rollup.step_statuses) ? rollup.step_statuses : [];
00479:
00480: if (!seq.length) {
00481: els.selectedPipelineSteps.innerHTML = '
No pipeline contract foundmissing';
00482: return;
00483: }
00484:
00485: els.selectedPipelineSteps.innerHTML = seq.map(function (step) {
00486: const observed = stepStatuses.find(function (x) {
00487: return normStageKey(x.step || x.name) === normStageKey(step);
00488: });
00489: const status = observed ? safeUpper(observed.status) : "MISSING";
00490: return [
00491: '
',
00492: '' + titleize(step) + '',
00493: '' + status + '',
00494: ''
00495: ].join("");
00496: }).join("");
00497: }
00498:
00499:
00500: function selectedPhaseObject() {
00501: const phases = (state.hubIndex && Array.isArray(state.hubIndex.phases)) ? state.hubIndex.phases : [];
00502: return phases.find(function (p) {
00503: return normStageKey(p.id || p.stage_key || "") === normStageKey(state.selectedStage);
00504: }) || null;
00505: }
00506:
00507: function selectedCategoryObject() {
00508: if (!state.selectedCategory) return null;
00509: const cats = (state.hubIndex && Array.isArray(state.hubIndex.categories)) ? state.hubIndex.categories : [];