openvibers/openvibe.codes Commits
Codes C9b: the conductor's pages join the workspace navigation (#185)
Changes
@@@ -38,7 +38,7 @@.c4-settings{display:grid;gap:12px;font-size:13px}.c4-safety{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-top:16px}.c4-safety-card{display:flex;align-items:flex-start;gap:10px;border:1px solid var(--c4-line);border-radius:10px;padding:14px;cursor:pointer;min-height:90px}.c4-safety-card:has(input:checked){border-color:var(--c4-accent);box-shadow:0 0 0 1px var(--c4-accent)}.c4-safety-card input{margin-top:3px;accent-color:var(--c4-accent)}.c4-safety-card span{display:grid;gap:6px}.c4-safety-card small{color:var(--c4-muted);font-size:12px;line-height:1.4}.c4 a:focus-visible,.c4 button:focus-visible,.c4 input:focus-visible,.c4 textarea:focus-visible,.c4 select:focus-visible{outline:2px solid #188c75;outline-offset:2px}@media(max-width:900px){.c4{padding-left:22px;padding-right:22px}}--@media(max-width:760px){.c4{padding:0 15px 24px}.c4-main{padding-top:18px}.c4-title{margin-bottom:16px}.c4-card{padding:16px;border-radius:11px}.c4-grid{grid-template-columns:1fr;gap:0}.c4-controls{display:grid;grid-template-columns:1fr 1fr}.c4-controls label{min-width:0}.c4-controls select,.c4-controls input{width:100%}.c4-controls .c4-button{grid-column:1/-1}.c4-task-detail{padding:17px}.c4-task-heading{gap:8px}.c4-task-heading>.c4-status{flex:none}.c4-chips{gap:6px}.c4-chip{font-size:11px;padding:5px 8px}.c4-outcome{grid-template-columns:30px minmax(0,1fr);gap:8px}.c4-outcome-actions{grid-column:1/-1;justify-content:flex-start;padding-left:38px}.c4-opill{min-height:44px;padding:0 11px;font-size:12px}.c4-mobile{display:grid;position:fixed;z-index:20;bottom:0;left:0;right:0;grid-template-columns:repeat(6,1fr);height:var(--c4-tabs-h);box-sizing:border-box;padding:0 max(6px,env(safe-area-inset-left)) env(safe-area-inset-bottom,0px);background:var(--c4-surface);border-top:1px solid var(--c4-line)}.c4-mobile a{display:flex;min-height:44px;flex-direction:column;align-items:center;justify-content:center;gap:2px;text-align:center;font-size:10px;padding:4px 2px;border-radius:8px;color:var(--c4-muted);text-decoration:none}.c4-mobile svg{width:19px;height:19px}.c4-search{align-items:stretch;flex-wrap:wrap}.c4-search label{width:100%}.c4-safety{grid-template-columns:1fr}.c4-safety-card{min-height:68px}.c4-progress-toggle{flex-wrap:wrap}.c4-progress-meta{margin-left:0}.c4-task-meta{font-size:10px}}++@media(max-width:760px){.c4{padding:0 15px 24px}.c4-main{padding-top:18px}.c4-title{margin-bottom:16px}.c4-card{padding:16px;border-radius:11px}.c4-grid{grid-template-columns:1fr;gap:0}.c4-controls{display:grid;grid-template-columns:1fr 1fr}.c4-controls label{min-width:0}.c4-controls select,.c4-controls input{width:100%}.c4-controls .c4-button{grid-column:1/-1}.c4-task-detail{padding:17px}.c4-task-heading{gap:8px}.c4-task-heading>.c4-status{flex:none}.c4-chips{gap:6px}.c4-chip{font-size:11px;padding:5px 8px}.c4-outcome{grid-template-columns:30px minmax(0,1fr);gap:8px}.c4-outcome-actions{grid-column:1/-1;justify-content:flex-start;padding-left:38px}.c4-opill{min-height:44px;padding:0 11px;font-size:12px}.c4-mobile{display:grid;position:fixed;z-index:20;bottom:0;left:0;right:0;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);height:var(--c4-tabs-h);box-sizing:border-box;padding:0 max(6px,env(safe-area-inset-left)) env(safe-area-inset-bottom,0px);background:var(--c4-surface);border-top:1px solid var(--c4-line)}.c4-mobile a{display:flex;min-width:0;min-height:44px;flex-direction:column;align-items:center;justify-content:center;gap:2px;text-align:center;font-size:10px;padding:4px 2px;border-radius:8px;color:var(--c4-muted);text-decoration:none}.c4-mobile a span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c4-mobile svg{width:19px;height:19px}.c4-search{align-items:stretch;flex-wrap:wrap}.c4-search label{width:100%}.c4-safety{grid-template-columns:1fr}.c4-safety-card{min-height:68px}.c4-progress-toggle{flex-wrap:wrap}.c4-progress-meta{margin-left:0}.c4-task-meta{font-size:10px}}:root[data-theme-mode="dark"] .c4{--c4-bg:#101518;--c4-surface:#171f23;--c4-ink:#eaf0f1;--c4-muted:#a3b0b4;--c4-line:#2d393d;--c4-accent:#75d0ba;--c4-dot:#5b6870;--c4-dot-ok:#afd39c;--c4-dot-bad:#f0b18c;--c4-dot-skip:#5b6870;--c4-dot-open:#75d0ba;--c4-ok-bg:#243423;--c4-ok-ink:#afd39c;--c4-bad-bg:#39291f;--c4-bad-ink:#f0b18c;--c4-bad-line:#5a4034;--c4-skip-bg:#263034;--c4-skip-ink:#cad4d6;--c4-open-bg:#1d3831;--c4-open-ink:#75d0ba;--c4-quiet-bg:#20292d;--c4-quiet-ink:#cad4d6;--c4-quiet:#20292d;--c4-ghost:#11181b}:root[data-theme-mode="dark"] .c4-composer{background:linear-gradient(140deg,#171f23,#182722);border-color:#315148}:root[data-theme-mode="dark"] .c4 textarea,:root[data-theme-mode="dark"] .c4 select,:root[data-theme-mode="dark"] .c4 input{background:#11181b;color:var(--c4-ink)}:root[data-theme-mode="dark"] .c4-mobile a[aria-current]{background:#1d3831}:root[data-theme-mode="dark"] .c4-log,:root[data-theme-mode="dark"] .c4-code{background:#11181b;color:#d3dfdf}:root[data-theme-mode="dark"] .c4-button-light{background:#20292d;color:var(--c4-ink)}:root[data-theme-mode="dark"] .c4-obadge{background:#39291f;color:#f0b18c}:root[data-theme-mode="dark"] .c4-progress-toggle{background:#1d3831;color:var(--c4-ink)}@@@ -38,6 +38,7 @@ const NAV = [const WORKSPACE_NAV = [{ label: 'Home', href: '/', icon: 'fa-house' },{ label: 'Tasks', href: '/tasks', icon: 'fa-list' },++ { label: 'Conductor', href: '/conductor', icon: 'fa-chart-simple' },{ label: 'Agents', href: '/agents', icon: 'fa-robot' },{ label: 'Machines', href: '/machines', icon: 'fa-display' },{ label: 'Usage', href: '/usage', icon: 'fa-chart-line' },@@@ -70,7 +71,7 @@ function renderPage(o) {const pathNow = o.path || '/';// The workspace pages share the compact Frame: no second app bar under the Frame's own (a query must not change it).const pathOnly = pathNow.split('?')[0];-- const c4Workspace = pathOnly === '/' || /^\/(tasks|agents|machines|usage|settings)(\/|$)/.test(pathOnly);++ const c4Workspace = pathOnly === '/' || /^\/(tasks|conductor|approvals|agents|machines|usage|settings)(\/|$)/.test(pathOnly);const loginNext = encodeURIComponent(pathNow);const canonical = `${o.config.baseUrl}${pathNow.split('?')[0]}`;// One navigation per page. On the workspace pages a signed-in person's navbar carries the workspace sections, with@@@ -35,7 +35,7 @@ const split = (links) => ({assert.strictEqual(page.status, 200);const links = navbarOf(page.text).links;const { top, more } = split(links);-- assert.deepStrictEqual(top, ['Home', 'Tasks', 'Agents', 'Machines', 'Usage', 'Settings'], 'the sections are the navbar');++ assert.deepStrictEqual(top, ['Home', 'Tasks', 'Conductor', 'Agents', 'Machines', 'Usage', 'Settings'], 'the sections are the navbar');assert.ok(more.includes('Get started') && more.includes('Run on your machine'), 'the product’s places fold into More');assert.ok(!top.includes('Agents') || top.filter((l) => l === 'Agents').length === 1, 'Agents is in one place only');const tasks = links.find((l) => l.href === '/tasks');
@@ -38,7 +38,7 @@
@@ -38,7 +38,7 @@
.c4-settings{display:grid;gap:12px;font-size:13px}.c4-safety{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-top:16px}.c4-safety-card{display:flex;align-items:flex-start;gap:10px;border:1px solid var(--c4-line);border-radius:10px;padding:14px;cursor:pointer;min-height:90px}.c4-safety-card:has(input:checked){border-color:var(--c4-accent);box-shadow:0 0 0 1px var(--c4-accent)}.c4-safety-card input{margin-top:3px;accent-color:var(--c4-accent)}.c4-safety-card span{display:grid;gap:6px}.c4-safety-card small{color:var(--c4-muted);font-size:12px;line-height:1.4}
.c4-settings{display:grid;gap:12px;font-size:13px}.c4-safety{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-top:16px}.c4-safety-card{display:flex;align-items:flex-start;gap:10px;border:1px solid var(--c4-line);border-radius:10px;padding:14px;cursor:pointer;min-height:90px}.c4-safety-card:has(input:checked){border-color:var(--c4-accent);box-shadow:0 0 0 1px var(--c4-accent)}.c4-safety-card input{margin-top:3px;accent-color:var(--c4-accent)}.c4-safety-card span{display:grid;gap:6px}.c4-safety-card small{color:var(--c4-muted);font-size:12px;line-height:1.4}
.c4 a:focus-visible,.c4 button:focus-visible,.c4 input:focus-visible,.c4 textarea:focus-visible,.c4 select:focus-visible{outline:2px solid #188c75;outline-offset:2px}
.c4 a:focus-visible,.c4 button:focus-visible,.c4 input:focus-visible,.c4 textarea:focus-visible,.c4 select:focus-visible{outline:2px solid #188c75;outline-offset:2px}
@media(max-width:900px){.c4{padding-left:22px;padding-right:22px}}
@media(max-width:900px){.c4{padding-left:22px;padding-right:22px}}
-@media(max-width:760px){.c4{padding:0 15px 24px}.c4-main{padding-top:18px}.c4-title{margin-bottom:16px}.c4-card{padding:16px;border-radius:11px}.c4-grid{grid-template-columns:1fr;gap:0}.c4-controls{display:grid;grid-template-columns:1fr 1fr}.c4-controls label{min-width:0}.c4-controls select,.c4-controls input{width:100%}.c4-controls .c4-button{grid-column:1/-1}.c4-task-detail{padding:17px}.c4-task-heading{gap:8px}.c4-task-heading>.c4-status{flex:none}.c4-chips{gap:6px}.c4-chip{font-size:11px;padding:5px 8px}.c4-outcome{grid-template-columns:30px minmax(0,1fr);gap:8px}.c4-outcome-actions{grid-column:1/-1;justify-content:flex-start;padding-left:38px}.c4-opill{min-height:44px;padding:0 11px;font-size:12px}.c4-mobile{display:grid;position:fixed;z-index:20;bottom:0;left:0;right:0;grid-template-columns:repeat(6,1fr);height:var(--c4-tabs-h);box-sizing:border-box;padding:0 max(6px,env(safe-area-inset-left)) env(safe-area-inset-bottom,0px);background:var(--c4-surface);border-top:1px solid var(--c4-line)}.c4-mobile a{display:flex;min-height:44px;flex-direction:column;align-items:center;justify-content:center;gap:2px;text-align:center;font-size:10px;padding:4px 2px;border-radius:8px;color:var(--c4-muted);text-decoration:none}.c4-mobile svg{width:19px;height:19px}.c4-search{align-items:stretch;flex-wrap:wrap}.c4-search label{width:100%}.c4-safety{grid-template-columns:1fr}.c4-safety-card{min-height:68px}.c4-progress-toggle{flex-wrap:wrap}.c4-progress-meta{margin-left:0}.c4-task-meta{font-size:10px}}
+@media(max-width:760px){.c4{padding:0 15px 24px}.c4-main{padding-top:18px}.c4-title{margin-bottom:16px}.c4-card{padding:16px;border-radius:11px}.c4-grid{grid-template-columns:1fr;gap:0}.c4-controls{display:grid;grid-template-columns:1fr 1fr}.c4-controls label{min-width:0}.c4-controls select,.c4-controls input{width:100%}.c4-controls .c4-button{grid-column:1/-1}.c4-task-detail{padding:17px}.c4-task-heading{gap:8px}.c4-task-heading>.c4-status{flex:none}.c4-chips{gap:6px}.c4-chip{font-size:11px;padding:5px 8px}.c4-outcome{grid-template-columns:30px minmax(0,1fr);gap:8px}.c4-outcome-actions{grid-column:1/-1;justify-content:flex-start;padding-left:38px}.c4-opill{min-height:44px;padding:0 11px;font-size:12px}.c4-mobile{display:grid;position:fixed;z-index:20;bottom:0;left:0;right:0;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);height:var(--c4-tabs-h);box-sizing:border-box;padding:0 max(6px,env(safe-area-inset-left)) env(safe-area-inset-bottom,0px);background:var(--c4-surface);border-top:1px solid var(--c4-line)}.c4-mobile a{display:flex;min-width:0;min-height:44px;flex-direction:column;align-items:center;justify-content:center;gap:2px;text-align:center;font-size:10px;padding:4px 2px;border-radius:8px;color:var(--c4-muted);text-decoration:none}.c4-mobile a span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c4-mobile svg{width:19px;height:19px}.c4-search{align-items:stretch;flex-wrap:wrap}.c4-search label{width:100%}.c4-safety{grid-template-columns:1fr}.c4-safety-card{min-height:68px}.c4-progress-toggle{flex-wrap:wrap}.c4-progress-meta{margin-left:0}.c4-task-meta{font-size:10px}}
:root[data-theme-mode="dark"] .c4{--c4-bg:#101518;--c4-surface:#171f23;--c4-ink:#eaf0f1;--c4-muted:#a3b0b4;--c4-line:#2d393d;--c4-accent:#75d0ba;--c4-dot:#5b6870;--c4-dot-ok:#afd39c;--c4-dot-bad:#f0b18c;--c4-dot-skip:#5b6870;--c4-dot-open:#75d0ba;--c4-ok-bg:#243423;--c4-ok-ink:#afd39c;--c4-bad-bg:#39291f;--c4-bad-ink:#f0b18c;--c4-bad-line:#5a4034;--c4-skip-bg:#263034;--c4-skip-ink:#cad4d6;--c4-open-bg:#1d3831;--c4-open-ink:#75d0ba;--c4-quiet-bg:#20292d;--c4-quiet-ink:#cad4d6;--c4-quiet:#20292d;--c4-ghost:#11181b}
:root[data-theme-mode="dark"] .c4{--c4-bg:#101518;--c4-surface:#171f23;--c4-ink:#eaf0f1;--c4-muted:#a3b0b4;--c4-line:#2d393d;--c4-accent:#75d0ba;--c4-dot:#5b6870;--c4-dot-ok:#afd39c;--c4-dot-bad:#f0b18c;--c4-dot-skip:#5b6870;--c4-dot-open:#75d0ba;--c4-ok-bg:#243423;--c4-ok-ink:#afd39c;--c4-bad-bg:#39291f;--c4-bad-ink:#f0b18c;--c4-bad-line:#5a4034;--c4-skip-bg:#263034;--c4-skip-ink:#cad4d6;--c4-open-bg:#1d3831;--c4-open-ink:#75d0ba;--c4-quiet-bg:#20292d;--c4-quiet-ink:#cad4d6;--c4-quiet:#20292d;--c4-ghost:#11181b}
:root[data-theme-mode="dark"] .c4-composer{background:linear-gradient(140deg,#171f23,#182722);border-color:#315148}:root[data-theme-mode="dark"] .c4 textarea,:root[data-theme-mode="dark"] .c4 select,:root[data-theme-mode="dark"] .c4 input{background:#11181b;color:var(--c4-ink)}
:root[data-theme-mode="dark"] .c4-composer{background:linear-gradient(140deg,#171f23,#182722);border-color:#315148}:root[data-theme-mode="dark"] .c4 textarea,:root[data-theme-mode="dark"] .c4 select,:root[data-theme-mode="dark"] .c4 input{background:#11181b;color:var(--c4-ink)}
:root[data-theme-mode="dark"] .c4-mobile a[aria-current]{background:#1d3831}:root[data-theme-mode="dark"] .c4-log,:root[data-theme-mode="dark"] .c4-code{background:#11181b;color:#d3dfdf}:root[data-theme-mode="dark"] .c4-button-light{background:#20292d;color:var(--c4-ink)}:root[data-theme-mode="dark"] .c4-obadge{background:#39291f;color:#f0b18c}:root[data-theme-mode="dark"] .c4-progress-toggle{background:#1d3831;color:var(--c4-ink)}
:root[data-theme-mode="dark"] .c4-mobile a[aria-current]{background:#1d3831}:root[data-theme-mode="dark"] .c4-log,:root[data-theme-mode="dark"] .c4-code{background:#11181b;color:#d3dfdf}:root[data-theme-mode="dark"] .c4-button-light{background:#20292d;color:var(--c4-ink)}:root[data-theme-mode="dark"] .c4-obadge{background:#39291f;color:#f0b18c}:root[data-theme-mode="dark"] .c4-progress-toggle{background:#1d3831;color:var(--c4-ink)}
@@ -38,6 +38,7 @@ const NAV = [
@@ -38,6 +38,7 @@ const NAV = [
const WORKSPACE_NAV = [
const WORKSPACE_NAV = [
{ label: 'Home', href: '/', icon: 'fa-house' },
{ label: 'Home', href: '/', icon: 'fa-house' },
{ label: 'Tasks', href: '/tasks', icon: 'fa-list' },
{ label: 'Tasks', href: '/tasks', icon: 'fa-list' },
+ { label: 'Conductor', href: '/conductor', icon: 'fa-chart-simple' },
{ label: 'Agents', href: '/agents', icon: 'fa-robot' },
{ label: 'Agents', href: '/agents', icon: 'fa-robot' },
{ label: 'Machines', href: '/machines', icon: 'fa-display' },
{ label: 'Machines', href: '/machines', icon: 'fa-display' },
{ label: 'Usage', href: '/usage', icon: 'fa-chart-line' },
{ label: 'Usage', href: '/usage', icon: 'fa-chart-line' },
@@ -70,7 +71,7 @@ function renderPage(o) {
@@ -70,7 +71,7 @@ function renderPage(o) {
const pathNow = o.path || '/';
const pathNow = o.path || '/';
// The workspace pages share the compact Frame: no second app bar under the Frame's own (a query must not change it).
// The workspace pages share the compact Frame: no second app bar under the Frame's own (a query must not change it).
const pathOnly = pathNow.split('?')[0];
const pathOnly = pathNow.split('?')[0];
- const c4Workspace = pathOnly === '/' || /^\/(tasks|agents|machines|usage|settings)(\/|$)/.test(pathOnly);
+ const c4Workspace = pathOnly === '/' || /^\/(tasks|conductor|approvals|agents|machines|usage|settings)(\/|$)/.test(pathOnly);
const loginNext = encodeURIComponent(pathNow);
const loginNext = encodeURIComponent(pathNow);
const canonical = `${o.config.baseUrl}${pathNow.split('?')[0]}`;
const canonical = `${o.config.baseUrl}${pathNow.split('?')[0]}`;
// One navigation per page. On the workspace pages a signed-in person's navbar carries the workspace sections, with
// One navigation per page. On the workspace pages a signed-in person's navbar carries the workspace sections, with
@@ -35,7 +35,7 @@ const split = (links) => ({
@@ -35,7 +35,7 @@ const split = (links) => ({
assert.strictEqual(page.status, 200);
assert.strictEqual(page.status, 200);
const links = navbarOf(page.text).links;
const links = navbarOf(page.text).links;
const { top, more } = split(links);
const { top, more } = split(links);
- assert.deepStrictEqual(top, ['Home', 'Tasks', 'Agents', 'Machines', 'Usage', 'Settings'], 'the sections are the navbar');
+ assert.deepStrictEqual(top, ['Home', 'Tasks', 'Conductor', 'Agents', 'Machines', 'Usage', 'Settings'], 'the sections are the navbar');
assert.ok(more.includes('Get started') && more.includes('Run on your machine'), 'the product’s places fold into More');
assert.ok(more.includes('Get started') && more.includes('Run on your machine'), 'the product’s places fold into More');
assert.ok(!top.includes('Agents') || top.filter((l) => l === 'Agents').length === 1, 'Agents is in one place only');
assert.ok(!top.includes('Agents') || top.filter((l) => l === 'Agents').length === 1, 'Agents is in one place only');
const tasks = links.find((l) => l.href === '/tasks');
const tasks = links.find((l) => l.href === '/tasks');