@growthub/cli 0.9.8 → 0.9.9

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.
Files changed (17) hide show
  1. package/README.md +23 -5
  2. package/assets/worker-kits/growthub-custom-workspace-starter-v1/SKILL.md +8 -2
  3. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/.env.example +8 -8
  4. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/README.md +9 -7
  5. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/settings/integrations/route.js +2 -2
  6. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/route.js +4 -4
  7. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +554 -19
  8. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/integrations/page.jsx +111 -77
  9. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-builder.jsx +485 -77
  10. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/growthub.config.json +8 -3
  11. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/env.js +9 -7
  12. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/index.js +10 -10
  13. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/domain/integrations.js +2 -2
  14. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-config.js +62 -7
  15. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-schema.js +38 -0
  16. package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +3 -0
  17. package/package.json +1 -1
@@ -1,105 +1,139 @@
1
+ import Link from "next/link";
1
2
  import { readAdapterConfig } from "@/lib/adapters/env";
2
- import { describeIntegrationAdapter, listAgencyPortalIntegrations } from "@/lib/adapters/integrations";
3
+ import { describeIntegrationAdapter, listGovernedWorkspaceIntegrations } from "@/lib/adapters/integrations";
3
4
  import { groupIntegrationsByLane } from "@/lib/domain/integrations";
4
- import { buildPortalWorkspace } from "@/lib/domain/portal";
5
- import { describeAuthAdapter } from "@/lib/adapters/auth";
6
- import { describePaymentAdapter } from "@/lib/adapters/payments";
7
- import { describePersistenceAdapter } from "@/lib/adapters/persistence";
8
- import Link from "next/link";
5
+
6
+ function countConnected(rows) {
7
+ return rows.filter((item) => item.isConnected || item.status === "connected").length;
8
+ }
9
+
10
+ function integrationKey(item, lane, index) {
11
+ return [
12
+ lane,
13
+ item.provider,
14
+ item.id,
15
+ item.accountId,
16
+ item.connectionId,
17
+ index
18
+ ].filter(Boolean).join(":");
19
+ }
20
+
21
+ function IntegrationRow({ item }) {
22
+ return <article className="workspace-integration-row">
23
+ <div className="workspace-provider-mark">{item.icon || item.label.slice(0, 1)}</div>
24
+ <div className="workspace-integration-main">
25
+ <strong>{item.label}</strong>
26
+ <p>{item.description}</p>
27
+ <div className="workspace-integration-meta">
28
+ <span>{item.provider}</span>
29
+ <span>{item.objectType}</span>
30
+ <span>{item.authPath}</span>
31
+ <span>{item.setupMode}</span>
32
+ <span>{item.authType}</span>
33
+ {item.secretEnvName ? <span>{item.secretEnvName}</span> : null}
34
+ </div>
35
+ </div>
36
+ <span className={`workspace-integration-status ${item.status}`}>{item.status}</span>
37
+ </article>;
38
+ }
39
+
9
40
  async function IntegrationsSettingsPage() {
10
41
  const config = readAdapterConfig();
11
42
  const adapter = describeIntegrationAdapter();
12
- const grouped = groupIntegrationsByLane(await listAgencyPortalIntegrations());
13
- const workspace = buildPortalWorkspace({
14
- config,
15
- integrations: grouped,
16
- adapters: {
17
- persistence: describePersistenceAdapter(),
18
- auth: describeAuthAdapter(),
19
- payments: describePaymentAdapter(),
20
- integrations: adapter
21
- }
22
- });
23
- const rows = [
24
- ...grouped.dataSources.map((item) => ({ ...item, primitiveGroup: "data-source" })),
25
- ...grouped.workspaceIntegrations.map((item) => ({ ...item, primitiveGroup: "workspace-integration" }))
26
- ];
27
- return <main className="shell">
28
- <aside className="sidebar">
29
- <div className="brand">
30
- <span className="brand-mark">{workspace.identity.mark}</span>
31
- <span>{workspace.identity.label}</span>
43
+ const grouped = groupIntegrationsByLane(await listGovernedWorkspaceIntegrations());
44
+ const allRows = [...grouped.dataSources, ...grouped.workspaceIntegrations];
45
+
46
+ return <main className="workspace-builder workspace-settings-page">
47
+ <aside className="workspace-rail" aria-label="Workspace navigation">
48
+ <div className="workspace-brand">
49
+ <span className="workspace-mark">G</span>
50
+ <span>Growthub Workspace</span>
32
51
  </div>
33
- <nav className="nav">
34
- {workspace.navigation.map((item) => <Link className={item.href === "/settings/integrations" ? "active" : ""} key={item.href} href={item.href.startsWith("#") ? `/${item.href}` : item.href}>
35
- {item.label}
36
- </Link>)}
52
+ <nav className="workspace-nav">
53
+ <Link href="/">Dashboards</Link>
54
+ <Link className="active" href="/settings/integrations">Integrations</Link>
55
+ <span className="workspace-nav-static">Workspace Settings</span>
56
+ <span className="workspace-nav-static">Management</span>
37
57
  </nav>
38
- <div className="sidebar-footer">
58
+ <div className="workspace-rail-status">
39
59
  <span className="status-dot" />
40
60
  {adapter.authority}
41
61
  </div>
42
62
  </aside>
43
- <section className="main">
44
- <div className="utility-bar">
63
+
64
+ <section className="workspace-surface">
65
+ <header className="workspace-toolbar">
45
66
  <div>
46
- <strong>{adapter.label}</strong>
47
- <span>{workspace.identity.primitiveContract}</span>
67
+ <p>Workspace settings</p>
68
+ <h1>Integrations</h1>
48
69
  </div>
49
- <div className="utility-actions">
50
- <span className="pill">{adapter.id}</span>
51
- <span className="pill">{adapter.authority}</span>
70
+ <div className="workspace-toolbar-actions">
71
+ <Link href="/api/settings/integrations">API contract</Link>
72
+ <span>{adapter.id}</span>
73
+ <span>{adapter.authority}</span>
52
74
  </div>
53
- </div>
54
- <section className="primitive-grid summary" aria-label="Integration adapter primitives">
55
- <article className="primitive-card">
56
- <div className="primitive-card-top">
57
- <p className="card-label">Authority</p>
58
- <span className="status runtime-derived">{adapter.authority}</span>
59
- </div>
60
- <strong>{adapter.id}</strong>
61
- <div className="primitive-meta">
62
- {adapter.requiredEnv.map((key) => <code key={key}>{key}</code>)}
75
+ </header>
76
+
77
+ <section className="workspace-integration-summary" aria-label="Integration adapter summary">
78
+ <article>
79
+ <span>Adapter</span>
80
+ <strong>{adapter.label}</strong>
81
+ <div>
82
+ {adapter.requiredEnv.length
83
+ ? adapter.requiredEnv.map((key) => <code key={key}>{key}</code>)
84
+ : <code>local catalog</code>}
63
85
  </div>
64
86
  </article>
65
- <article className="primitive-card">
66
- <div className="primitive-card-top">
67
- <p className="card-label">Data-source primitives</p>
68
- <span className="status runtime-derived">{grouped.dataSources.length}</span>
69
- </div>
70
- <strong>{grouped.dataSources.filter((item) => item.isConnected).length}/{grouped.dataSources.length}</strong>
71
- <div className="primitive-meta"><span>{config.reportingAdapter || "reporting-adapter"}</span></div>
87
+ <article>
88
+ <span>Data sources</span>
89
+ <strong>{countConnected(grouped.dataSources)}/{grouped.dataSources.length}</strong>
90
+ <div><code>{config.reportingAdapter || "reporting-adapter"}</code></div>
72
91
  </article>
73
- <article className="primitive-card">
74
- <div className="primitive-card-top">
75
- <p className="card-label">Workspace primitives</p>
76
- <span className="status runtime-derived">{grouped.workspaceIntegrations.length}</span>
77
- </div>
78
- <strong>{grouped.workspaceIntegrations.filter((item) => item.isConnected).length}/{grouped.workspaceIntegrations.length}</strong>
79
- <div className="primitive-meta"><span>{config.integrationAdapter}</span></div>
92
+ <article>
93
+ <span>Workspace tools</span>
94
+ <strong>{countConnected(grouped.workspaceIntegrations)}/{grouped.workspaceIntegrations.length}</strong>
95
+ <div><code>{config.integrationAdapter}</code></div>
80
96
  </article>
81
97
  </section>
82
- <section className="integration-board">
83
- {rows.map((item) => <article className="integration-card" key={item.id}>
84
- <div className="integration-card-top">
85
- <div className="provider-mark">{item.icon || item.label.slice(0, 1)}</div>
86
- <div>
87
- <strong>{item.label}</strong>
88
- <p>{item.provider} / {item.objectType} / {item.primitiveGroup}</p>
89
- </div>
90
- <span className={`status ${item.status}`}>{item.status}</span>
98
+
99
+ <section className="workspace-integration-toolbar">
100
+ <div>
101
+ <strong>Connection catalog</strong>
102
+ <p>{countConnected(allRows)}/{allRows.length} connected. Setup state is resolved from the selected adapter without storing provider tokens in the app.</p>
103
+ </div>
104
+ </section>
105
+
106
+ <section className="workspace-integration-board">
107
+ <section className="workspace-integration-section">
108
+ <div className="workspace-integration-section-heading">
109
+ <div>
110
+ <h2>Data Sources</h2>
111
+ <p>Reporting and blended-data providers available to dashboard widgets.</p>
91
112
  </div>
92
- <div className="integration-card-meta">
93
- <span>{item.authPath}</span>
94
- <span>{item.setupMode}</span>
95
- <span>{item.authType}</span>
96
- {item.secretEnvName ? <span>{item.secretEnvName}</span> : null}
113
+ <span>{countConnected(grouped.dataSources)}/{grouped.dataSources.length}</span>
114
+ </div>
115
+ <div className="workspace-integration-list">
116
+ {grouped.dataSources.map((item, index) => <IntegrationRow item={item} key={integrationKey(item, "data-source", index)} />)}
117
+ </div>
118
+ </section>
119
+
120
+ <section className="workspace-integration-section">
121
+ <div className="workspace-integration-section-heading">
122
+ <div>
123
+ <h2>Workspace Tools</h2>
124
+ <p>Account-level tool connections available to governed workspace workflows.</p>
97
125
  </div>
98
- </article>)}
126
+ <span>{countConnected(grouped.workspaceIntegrations)}/{grouped.workspaceIntegrations.length}</span>
127
+ </div>
128
+ <div className="workspace-integration-list">
129
+ {grouped.workspaceIntegrations.map((item, index) => <IntegrationRow item={item} key={integrationKey(item, "workspace-integration", index)} />)}
130
+ </div>
131
+ </section>
99
132
  </section>
100
133
  </section>
101
134
  </main>;
102
135
  }
136
+
103
137
  export {
104
138
  IntegrationsSettingsPage as default
105
139
  };