);
}
// ── Org ───────────────────────────────────────────────────────────────────
// The org chart is a DATA PRODUCT in the worksheet shell, exactly like the
// Tools DPs (Calendar/Lists): the Data face is the department roster grid, the
// Artifact face is the traditional org chart drawn from it, plus Control/Context.
// One source array (WS_ORG) drives both faces — the chart is of DEPARTMENTS;
// each department's head resolves back to a real person in WS_TEAM by id.
const IconOrg = (p) => (
);
// parent is a department id (null at the top). head is an EMP id from WS_TEAM.
// hub names the associated Proxa hub (if the department has one built) — this is
// what the chart badge and the Data-face "Hub" column denote.
const WS_ORG = [
{ id: 'DEP-01', dept: 'Executive Office', parent: null, head: 'EMP-1001', focus: 'Leadership & strategy', hc: 4 },
{ id: 'DEP-02', dept: 'Finance', parent: 'DEP-01', head: 'EMP-1002', focus: 'Accounting, FP&A, treasury', hc: 8, hub: 'Finance' },
{ id: 'DEP-03', dept: 'Controllership', parent: 'DEP-02', head: 'EMP-1004', focus: 'Close, controls, reporting', hc: 5 },
{ id: 'DEP-04', dept: 'Operations', parent: 'DEP-01', head: 'EMP-1003', focus: 'Manufacturing & fulfillment', hc: 210 },
{ id: 'DEP-05', dept: 'Supply Chain', parent: 'DEP-04', head: 'EMP-1008', focus: 'Procurement & logistics', hc: 18 },
{ id: 'DEP-06', dept: 'Portland Plant · OR', parent: 'DEP-04', head: 'EMP-1009', focus: 'Co-packing — 5 lines', hc: 95 },
{ id: 'DEP-07', dept: 'Lebanon Plant · TN', parent: 'DEP-04', head: 'EMP-1010', focus: 'Co-packing — 4 lines', hc: 88 },
{ id: 'DEP-08', dept: 'Sales', parent: 'DEP-01', head: 'EMP-1015', focus: 'Accounts & pipeline', hc: 12 },
{ id: 'DEP-09', dept: 'Customer', parent: 'DEP-01', head: 'EMP-1016', focus: 'Contracts, CRM & success', hc: 7, hub: 'Customer' },
{ id: 'DEP-10', dept: 'People', parent: 'DEP-01', head: 'EMP-1005', focus: 'Talent, payroll, safety', hc: 6 },
{ id: 'DEP-11', dept: 'R&D', parent: 'DEP-01', head: 'EMP-1013', focus: 'Product & process development', hc: 9 },
];
// ── Which workspace's content to render ───────────────────────────────────
// The arrays above are Cascade Ridge's. A domain pack with a `built` section
// (see domains.jsx — the HLA lab) supplies its own in the same row shapes, so
// every component below works unchanged. WorkspacePage sets this at the top of
// its render; only one workspace is on screen at a time.
let WS_DOMAIN = null;
function wsBuilt() {
const p = WS_DOMAIN && window.proxaDomain ? window.proxaDomain(WS_DOMAIN) : null;
return (p && p.built) || null;
}
function wsHubs() { const b = wsBuilt(); return b ? b.hubs : WS_HUBS; }
function wsTeam() { const b = wsBuilt(); return b ? b.team : WS_TEAM; }
function wsOrg() { const b = wsBuilt(); return b ? b.org : WS_ORG; }
function wsEmailDomain() { const b = wsBuilt(); return (b && b.emailDomain) || 'cascaderidgefoods.com'; }
// Each workspace's own identity mark (domains.jsx). Falls back to Cascade
// Ridge's so an un-domained workspace still renders something.
function wsMark(key) { return (window.proxaMark ? window.proxaMark(key) : null) || 'assets/crf-mark.svg?v=3'; }
const wsTeamById = (id) => wsTeam().find((m) => m.id === id) || {};
// Worksheet columns + rows (the Data face / data container behind the chart).
const WS_ORG_COLS = ['Department', 'Parent', 'Head', 'Focus', 'Headcount', 'Hub'];
function wsOrgRows() {
const deptById = Object.fromEntries(wsOrg().map((d) => [d.id, d.dept]));
return wsOrg().map((d) => [
d.dept,
d.parent ? deptById[d.parent] : '—',
wsTeamById(d.head).name || d.head,
d.focus,
String(d.hc),
d.hub || '—',
]);
}
// Assemble the department tree from the flat WS_ORG list.
function wsOrgTree() {
const nodes = {};
wsOrg().forEach((d) => {
const h = wsTeamById(d.head);
nodes[d.id] = { ...d, head: h.name || d.head, headTitle: h.title || '', kids: [] };
});
let root = null;
wsOrg().forEach((d) => {
if (d.parent && nodes[d.parent]) nodes[d.parent].kids.push(nodes[d.id]);
else if (!d.parent) root = nodes[d.id];
});
return root;
}
function WsOrgNode({ n }) {
return (
);
}
// The Artifact face: a traditional top-down org chart of departments.
function WsOrgChart() {
const root = React.useMemo(wsOrgTree, []);
if (!root) return null;
return (
);
}
// Same worksheet DP shell as the Tools DPs, but chart-first (Artifact face).
function WsOrg() {
return (
);
}
// Badge label/class per tier (shared by the card and list views).
function wsHubBadge(tier) {
if (tier === 'planned') return { label: 'Planned', cls: 'planned' };
if (tier === 'template') return { label: 'Template', cls: 'template' };
return { label: 'Ready', cls: 'live' };
}
// Hub columns for the shared OutputsList (reuses the Dashboard's .lib table).
const WS_HUB_COLUMNS = [
{ header: 'Hub', render: (h) => (
);
}
// Rich empty-state used for every workspace section: a hatched panel with an
// icon, title, one-line prompt and an "Add …" CTA (opens the assistant).
function WsSectionEmpty({ Icon, title, sub, ctaLabel, onCta, children }) {
return (
{title}
{sub}
{ctaLabel && (
)}
{children}
);
}
// Fallback icon for a draft hub whose name doesn't match a template (a cube).
const WS_DRAFT_ICON = '';
// First-time-user Hubs surface for a brand-new (empty) workspace: the shared
// empty-state hero plus the generic Templates to start from. Clicking a
// template BUILDS it — a draft hub lands in the rail and the template flow
// opens (Model → Context). Built drafts render as live cards above Templates.
// Step 0 of an empty workspace: what are you modelling? The answer swaps the
// template set, the starting documents and the data products — the flow itself
// is identical either way (see domains.jsx).
function WsDomainPick({ onPick }) {
const order = window.PROXA_DOMAIN_ORDER || ['company'];
const packs = window.PROXA_DOMAINS || {};
return (
What are you modelling?
Claude needs to know the shape of the work before it can propose anything.
{order.map((key) => {
const p = packs[key];
if (!p) return null;
return (
);
})}
);
}
function WsHubsEmpty({ draftHubs = [], onOpenHub, onBuildFromTemplate, onGuide, domain, onPickDomain }) {
const Card = window.NHTemplateCard;
// No domain yet → ask what we're modelling before showing any template.
if (!domain && onPickDomain) return ;
const pack = window.proxaDomain ? window.proxaDomain(domain) : null;
// Templates come from the domain pack; WS_HUBS is the company fallback.
const templates = pack
? pack.groups.flatMap((g) => g.items).map((t) => ({ ...t, live: false }))
: wsHubs().filter((h) => h.tier === 'template');
const templateSection = (
Templates{templates.length}Generic starting points — pick one and Claude builds it.