diff --git a/apps/gittensory-ui/src/components/site/app-panels/owner-panel.tsx b/apps/gittensory-ui/src/components/site/app-panels/owner-panel.tsx index f293dc090f..73a3318b6e 100644 --- a/apps/gittensory-ui/src/components/site/app-panels/owner-panel.tsx +++ b/apps/gittensory-ui/src/components/site/app-panels/owner-panel.tsx @@ -12,6 +12,7 @@ import { useApiResource } from "@/lib/api/use-api-resource"; import { buildRegistrationWorkspaceView, splitRepoFullName, + type OwnerWorkflowState, type GittensorConfigRecommendationPayload, type RegistrationReadinessPayload, type RegistrationWorkspaceView, @@ -32,6 +33,12 @@ const FRESHNESS_STATUS_MAP: Record = { + accepted: "ready", + needs_cleanup: "warn", + not_ready: "blocked", +}; + export function OwnerPanel() { const [repo, setRepo] = useState("entrius/gittensor"); const parts = splitRepoFullName(repo.trim()); @@ -119,7 +126,7 @@ export function OwnerPanel() { ); } -function RegistrationWorkspace({ +export function RegistrationWorkspace({ workspace, generatedLabel, }: { @@ -136,6 +143,9 @@ function RegistrationWorkspace({ {workspace.summary.ready ? "Ready" : "Not ready"} + + {formatWorkflowState(workspace.workflow.overallState)} + {workspace.freshness.status} @@ -163,11 +173,50 @@ function RegistrationWorkspace({ -
- - - - +
+
+
+

Guided owner workflow

+

+ {workspace.workflow.overallHeadline} +

+
+ + {formatWorkflowState(workspace.workflow.overallState)} + +
+ + {workspace.workflow.nextSteps.length > 0 ? ( +
+

Next owner actions

+
    + {workspace.workflow.nextSteps.map((step) => ( +
  • {step}
  • + ))} +
+
+ ) : null} + +
+ {workspace.workflow.buckets.map((bucket) => ( + + ))} +
+
+ +
+
+

Supporting readiness signals

+

+ Detailed lane tradeoffs and operational signals behind the guided workflow. +

+
+
+ + + + +
@@ -252,6 +301,50 @@ function WorkspaceSectionCard({ ); } +function OwnerWorkflowBucketCard({ + bucket, +}: { + bucket: RegistrationWorkspaceView["workflow"]["buckets"][number]; +}) { + return ( +
+
+
+

{bucket.title}

+

{bucket.summary}

+
+ + {formatWorkflowState(bucket.state)} + +
+ + {bucket.items.length > 0 ? ( +
    + {bucket.items.map((item) => ( +
  • +
    + {item.title} + + {formatWorkflowState(item.state)} + +
    +

    {item.summary}

    +

    + + {item.remediationKind === "manual" ? "Manual follow-up" : "Action"} + {" "} + {item.remediation} +

    +
  • + ))} +
+ ) : ( +

No follow-up needed.

+ )} +
+ ); +} + function Metric({ label, value }: { label: string; value: string }) { return (
@@ -268,3 +361,7 @@ function formatGeneratedAt(value: string) { if (!Number.isFinite(parsed)) return value; return new Date(parsed).toLocaleString(); } + +function formatWorkflowState(state: OwnerWorkflowState) { + return state.replace(/_/g, " "); +} diff --git a/apps/gittensory-ui/src/lib/registration-workspace.ts b/apps/gittensory-ui/src/lib/registration-workspace.ts index 044a303ba1..6bc7db145b 100644 --- a/apps/gittensory-ui/src/lib/registration-workspace.ts +++ b/apps/gittensory-ui/src/lib/registration-workspace.ts @@ -457,7 +457,7 @@ export function buildRegistrationOwnerWorkflow( docsItems.push({ id: "docs-crawl", title: "Onboarding docs", - state: "needs_cleanup", + state: "accepted", summary: docs.note, remediation: "Manually verify CONTRIBUTING.md, README onboarding steps, and issue templates in GitHub; remote doc crawling is not enabled in this signal yet.", diff --git a/apps/gittensory-ui/src/routes/app.owner.tsx b/apps/gittensory-ui/src/routes/app.owner.tsx index 04f4ed4955..a9a1d2b971 100644 --- a/apps/gittensory-ui/src/routes/app.owner.tsx +++ b/apps/gittensory-ui/src/routes/app.owner.tsx @@ -13,7 +13,7 @@ function OwnerRoute() {
diff --git a/test/unit/mcp-cli.test.ts b/test/unit/mcp-cli.test.ts index c1a2a2e64a..651544a7d9 100644 --- a/test/unit/mcp-cli.test.ts +++ b/test/unit/mcp-cli.test.ts @@ -916,7 +916,7 @@ describe("gittensory-mcp CLI", () => { ), ).rejects.toThrow("Refusing to print unsafe public packet markdown from the server."); } - }, 10000); + }, 30000); it("sends bounded structured validation summaries without local logs", async () => { tempDir = mkdtempSync(join(tmpdir(), "gittensory-cli-")); diff --git a/test/unit/owner-panel-source.test.ts b/test/unit/owner-panel-source.test.ts new file mode 100644 index 0000000000..10521cc7de --- /dev/null +++ b/test/unit/owner-panel-source.test.ts @@ -0,0 +1,22 @@ +import { readFileSync } from "node:fs"; + +import { describe, expect, it } from "vitest"; + +const ownerPanelSource = readFileSync( + "apps/gittensory-ui/src/components/site/app-panels/owner-panel.tsx", + "utf8", +); + +describe("owner panel workflow surface", () => { + it("renders the guided owner workflow as the primary section", () => { + expect(ownerPanelSource).toContain("Guided owner workflow"); + expect(ownerPanelSource).toContain("Next owner actions"); + expect(ownerPanelSource).toContain("Supporting readiness signals"); + }); + + it("shows workflow bucket state pills and remediation labels", () => { + expect(ownerPanelSource).toContain("formatWorkflowState"); + expect(ownerPanelSource).toContain("Manual follow-up"); + expect(ownerPanelSource).toContain('item.remediationKind === "manual" ? "Manual follow-up" : "Action"'); + }); +}); diff --git a/test/unit/registration-workspace-ui.test.ts b/test/unit/registration-workspace-ui.test.ts index 2f39cdc323..ef51d91515 100644 --- a/test/unit/registration-workspace-ui.test.ts +++ b/test/unit/registration-workspace-ui.test.ts @@ -164,10 +164,10 @@ describe("registration workspace UI helpers", () => { "maintainer_capacity", ]); const docs = workflow.buckets.find((bucket) => bucket.id === "docs_onboarding"); - expect(docs?.state).toBe("needs_cleanup"); + expect(docs?.state).toBe("accepted"); expect(docs?.items[0]?.remediationKind).toBe("manual"); - expect(workflow.overallState).toBe("needs_cleanup"); - expect(workflow.nextSteps.length).toBeGreaterThan(0); + expect(workflow.overallState).toBe("accepted"); + expect(workflow.nextSteps).toEqual([]); }); it("blocked readiness maps workflow to not ready with concrete blocker remediation", () => {