@growthub/cli 0.9.3 → 0.9.4
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.
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/growthub.config.json +112 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/package.json +1 -1
- package/assets/worker-kits/growthub-agency-portal-starter-v1/bundles/growthub-agency-portal-starter-v1.json +1 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/kit.json +2 -0
- package/assets/worker-kits/growthub-creative-video-pipeline-v1/apps/creative-video-pipeline/package.json +1 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/SKILL.md +35 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/.env.example +41 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/README.md +38 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/settings/integrations/route.js +13 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/route.js +31 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +717 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/layout.jsx +14 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/page.jsx +117 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/integrations/page.jsx +105 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/growthub.config.json +53 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/jsconfig.json +8 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/auth/index.js +21 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/env.js +28 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/growthub-connection-normalizer.js +95 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/index.js +198 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/payments/index.js +13 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/persistence/index.js +13 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/persistence/postgres.js +16 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/persistence/provider-managed.js +16 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/persistence/qstash-kv.js +16 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/domain/integrations.js +185 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/domain/portal.js +150 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/next.config.js +10 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/package-lock.json +976 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/package.json +17 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/postcss.config.mjs +3 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/vercel.json +5 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/bundles/growthub-custom-workspace-starter-v1.json +13 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/docs/adapter-contracts.md +86 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/docs/vercel-serverless-deployment.md +46 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/growthub.config.json +49 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/helpers/check-self-improving-health.sh +60 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/helpers/promote-capability.mjs +37 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/helpers/propose-capability.mjs +38 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +45 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/templates/deployment-handoff.md +61 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/templates/supabase-setup-plan.md +26 -0
- package/dist/index.js +2903 -1597
- package/package.json +2 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function describeProviderManagedAdapter() {
|
|
2
|
+
return {
|
|
3
|
+
id: "provider-managed",
|
|
4
|
+
label: "Provider Managed",
|
|
5
|
+
requiredEnv: [],
|
|
6
|
+
mode: "external",
|
|
7
|
+
notes: [
|
|
8
|
+
"Use when a deployment provider owns persistence.",
|
|
9
|
+
"Document provider-specific environment variables in the fork journal.",
|
|
10
|
+
"Do not promote provider-specific names into the worker-kit manifest."
|
|
11
|
+
]
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
describeProviderManagedAdapter
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function describeQstashKvAdapter() {
|
|
2
|
+
return {
|
|
3
|
+
id: "qstash-kv",
|
|
4
|
+
label: "Qstash KV",
|
|
5
|
+
requiredEnv: ["QSTASH_KV_REST_URL", "QSTASH_KV_REST_TOKEN"],
|
|
6
|
+
mode: "kv",
|
|
7
|
+
notes: [
|
|
8
|
+
"Use HTTP-first KV for serverless-friendly deployments.",
|
|
9
|
+
"Model relational portal records as namespaced documents and secondary indexes.",
|
|
10
|
+
"Keep queue and storage concerns separated from the domain capability map."
|
|
11
|
+
]
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
describeQstashKvAdapter
|
|
16
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
const dataSources = [
|
|
2
|
+
{
|
|
3
|
+
id: "windsor-ai",
|
|
4
|
+
label: "Windsor AI",
|
|
5
|
+
name: "Windsor AI",
|
|
6
|
+
icon: "W",
|
|
7
|
+
provider: "windsor-ai",
|
|
8
|
+
description: "Primary blended marketing data source for cross-channel reporting.",
|
|
9
|
+
category: "mcp_connector",
|
|
10
|
+
authType: "oauth_first_party",
|
|
11
|
+
isConnected: false,
|
|
12
|
+
isActive: false,
|
|
13
|
+
lane: "data-source",
|
|
14
|
+
objectType: "data-pipeline",
|
|
15
|
+
status: "needs-connection",
|
|
16
|
+
authPath: "growthub-mcp-bridge",
|
|
17
|
+
setupMode: "hosted-authority"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "google-sheets-blended-data",
|
|
21
|
+
label: "Google Sheets blended data",
|
|
22
|
+
name: "Google Sheets blended data",
|
|
23
|
+
icon: "G",
|
|
24
|
+
provider: "google-sheets",
|
|
25
|
+
description: "Windsor AI blended data destination for spreadsheet-backed reporting workflows.",
|
|
26
|
+
category: "mcp_connector",
|
|
27
|
+
authType: "oauth_first_party",
|
|
28
|
+
isConnected: false,
|
|
29
|
+
isActive: false,
|
|
30
|
+
lane: "data-source",
|
|
31
|
+
objectType: "data-pipeline",
|
|
32
|
+
status: "needs-connection",
|
|
33
|
+
authPath: "growthub-mcp-bridge",
|
|
34
|
+
setupMode: "hosted-authority"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: "google-analytics",
|
|
38
|
+
label: "Google Analytics",
|
|
39
|
+
name: "Google Analytics",
|
|
40
|
+
icon: "G",
|
|
41
|
+
provider: "google-analytics",
|
|
42
|
+
description: "First-party Growthub connection for analytics properties and account metrics.",
|
|
43
|
+
category: "mcp_connector",
|
|
44
|
+
authType: "oauth_first_party",
|
|
45
|
+
isConnected: false,
|
|
46
|
+
isActive: false,
|
|
47
|
+
lane: "data-source",
|
|
48
|
+
objectType: "data-pipeline",
|
|
49
|
+
status: "needs-connection",
|
|
50
|
+
authPath: "growthub-mcp-bridge",
|
|
51
|
+
setupMode: "hosted-authority"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "shopify",
|
|
55
|
+
label: "Shopify",
|
|
56
|
+
name: "Shopify",
|
|
57
|
+
icon: "S",
|
|
58
|
+
provider: "shopify",
|
|
59
|
+
description: "Commerce data source resolved through the Growthub MCP connection store.",
|
|
60
|
+
category: "mcp_connector",
|
|
61
|
+
authType: "oauth_first_party",
|
|
62
|
+
isConnected: false,
|
|
63
|
+
isActive: false,
|
|
64
|
+
lane: "data-source",
|
|
65
|
+
objectType: "data-pipeline",
|
|
66
|
+
status: "needs-connection",
|
|
67
|
+
authPath: "growthub-mcp-bridge",
|
|
68
|
+
setupMode: "hosted-authority"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "meta-ads",
|
|
72
|
+
label: "Meta Facebook and Instagram",
|
|
73
|
+
name: "Meta Facebook and Instagram",
|
|
74
|
+
icon: "M",
|
|
75
|
+
provider: "meta-ads",
|
|
76
|
+
description: "First-party Meta account access for Facebook and Instagram performance data.",
|
|
77
|
+
category: "mcp_connector",
|
|
78
|
+
authType: "oauth_first_party",
|
|
79
|
+
isConnected: false,
|
|
80
|
+
isActive: false,
|
|
81
|
+
lane: "data-source",
|
|
82
|
+
objectType: "data-pipeline",
|
|
83
|
+
status: "needs-connection",
|
|
84
|
+
authPath: "growthub-mcp-bridge",
|
|
85
|
+
setupMode: "hosted-authority"
|
|
86
|
+
}
|
|
87
|
+
];
|
|
88
|
+
const workspaceIntegrations = [
|
|
89
|
+
{
|
|
90
|
+
id: "asana",
|
|
91
|
+
label: "Asana",
|
|
92
|
+
name: "Asana",
|
|
93
|
+
icon: "A",
|
|
94
|
+
provider: "asana",
|
|
95
|
+
description: "Project and task operations available through the connected Growthub account.",
|
|
96
|
+
category: "mcp_connector",
|
|
97
|
+
authType: "oauth_first_party",
|
|
98
|
+
isConnected: false,
|
|
99
|
+
isActive: false,
|
|
100
|
+
lane: "workspace-integration",
|
|
101
|
+
objectType: "mcp-connection",
|
|
102
|
+
status: "needs-connection",
|
|
103
|
+
authPath: "growthub-mcp-bridge",
|
|
104
|
+
setupMode: "hosted-authority"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: "slack",
|
|
108
|
+
label: "Slack",
|
|
109
|
+
name: "Slack",
|
|
110
|
+
icon: "S",
|
|
111
|
+
provider: "slack",
|
|
112
|
+
description: "Team messaging and notification workflows without app-local Slack secrets.",
|
|
113
|
+
category: "mcp_connector",
|
|
114
|
+
authType: "oauth_first_party",
|
|
115
|
+
isConnected: false,
|
|
116
|
+
isActive: false,
|
|
117
|
+
lane: "workspace-integration",
|
|
118
|
+
objectType: "mcp-connection",
|
|
119
|
+
status: "needs-connection",
|
|
120
|
+
authPath: "growthub-mcp-bridge",
|
|
121
|
+
setupMode: "hosted-authority"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: "go-high-level",
|
|
125
|
+
label: "GoHighLevel",
|
|
126
|
+
name: "GoHighLevel",
|
|
127
|
+
icon: "G",
|
|
128
|
+
provider: "go-high-level",
|
|
129
|
+
description: "CRM and social account access delegated through Growthub connection authority.",
|
|
130
|
+
category: "mcp_connector",
|
|
131
|
+
authType: "oauth_first_party",
|
|
132
|
+
isConnected: false,
|
|
133
|
+
isActive: false,
|
|
134
|
+
lane: "workspace-integration",
|
|
135
|
+
objectType: "mcp-connection",
|
|
136
|
+
status: "needs-connection",
|
|
137
|
+
authPath: "growthub-mcp-bridge",
|
|
138
|
+
setupMode: "hosted-authority"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: "google-drive",
|
|
142
|
+
label: "Google Drive",
|
|
143
|
+
name: "Google Drive",
|
|
144
|
+
icon: "G",
|
|
145
|
+
provider: "google-drive",
|
|
146
|
+
description: "Document and knowledge-base access resolved through the user's connected account.",
|
|
147
|
+
category: "mcp_connector",
|
|
148
|
+
authType: "oauth_first_party",
|
|
149
|
+
isConnected: false,
|
|
150
|
+
isActive: false,
|
|
151
|
+
lane: "workspace-integration",
|
|
152
|
+
objectType: "mcp-connection",
|
|
153
|
+
status: "needs-connection",
|
|
154
|
+
authPath: "growthub-mcp-bridge",
|
|
155
|
+
setupMode: "hosted-authority"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
id: "notion",
|
|
159
|
+
label: "Notion",
|
|
160
|
+
name: "Notion",
|
|
161
|
+
icon: "N",
|
|
162
|
+
provider: "notion",
|
|
163
|
+
description: "Workspace knowledge and project content access through the Growthub bridge.",
|
|
164
|
+
category: "mcp_connector",
|
|
165
|
+
authType: "oauth_first_party",
|
|
166
|
+
isConnected: false,
|
|
167
|
+
isActive: false,
|
|
168
|
+
lane: "workspace-integration",
|
|
169
|
+
objectType: "mcp-connection",
|
|
170
|
+
status: "needs-connection",
|
|
171
|
+
authPath: "growthub-mcp-bridge",
|
|
172
|
+
setupMode: "hosted-authority"
|
|
173
|
+
}
|
|
174
|
+
];
|
|
175
|
+
const agencyPortalIntegrationCatalog = [...dataSources, ...workspaceIntegrations];
|
|
176
|
+
function groupIntegrationsByLane(integrations) {
|
|
177
|
+
return {
|
|
178
|
+
dataSources: integrations.filter((item) => item.lane === "data-source"),
|
|
179
|
+
workspaceIntegrations: integrations.filter((item) => item.lane === "workspace-integration")
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
export {
|
|
183
|
+
agencyPortalIntegrationCatalog,
|
|
184
|
+
groupIntegrationsByLane
|
|
185
|
+
};
|
package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/domain/portal.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
const fieldTypes = [
|
|
2
|
+
"text",
|
|
3
|
+
"long_text",
|
|
4
|
+
"number",
|
|
5
|
+
"currency",
|
|
6
|
+
"percentage",
|
|
7
|
+
"date",
|
|
8
|
+
"datetime",
|
|
9
|
+
"select",
|
|
10
|
+
"multi_select",
|
|
11
|
+
"boolean",
|
|
12
|
+
"relation",
|
|
13
|
+
"multi_relation",
|
|
14
|
+
"formula",
|
|
15
|
+
"rollup",
|
|
16
|
+
"url",
|
|
17
|
+
"email",
|
|
18
|
+
"phone",
|
|
19
|
+
"json",
|
|
20
|
+
"file",
|
|
21
|
+
"rating",
|
|
22
|
+
"user"
|
|
23
|
+
];
|
|
24
|
+
const capabilitySpecs = [
|
|
25
|
+
tab("dashboard", "Dashboard", "workspace-summary", ["agencyAccount", "client", "task"], ["pipelineValue", "clientHealth", "openTasks", "reportingReadiness"], ["data", "auth", "integrations"]),
|
|
26
|
+
tab("clients", "Clients", "client-records", ["client", "contact", "clientKpi"], ["activeClients", "retainerValue", "healthScore", "renewalWindow"], ["data", "auth"]),
|
|
27
|
+
tab("pipeline", "Pipeline", "opportunity-flow", ["opportunity", "client", "contact"], ["stageValue", "winRate", "nextFollowUp", "ownerLoad"], ["data", "integrations"]),
|
|
28
|
+
tab("content", "Content", "publishing-workflow", ["contentPlan", "client", "task"], ["scheduledPosts", "channelMix", "approvalQueue", "overdueAssets"], ["data", "integrations"]),
|
|
29
|
+
tab("tasks", "Tasks", "execution-queue", ["task", "client", "workflowRun"], ["openTasks", "slaRisk", "ownerLoad", "recurringTemplates"], ["data", "integrations"]),
|
|
30
|
+
tab("finance", "Finance", "billing-control", ["invoice", "expense", "client"], ["mrr", "outstandingBalance", "margin", "paymentState"], ["data", "payments"]),
|
|
31
|
+
tab("reports", "Reports", "reporting-adapter", ["report", "clientKpi", "dataConnector"], ["reportQueue", "connectedSources", "periodDelta", "deliveryState"], ["reporting", "integrations"]),
|
|
32
|
+
tab("metrics", "Metrics", "agency-health", ["agencyMetric", "clientKpi", "opportunity"], ["mrrTrend", "churnRisk", "pipelineCoverage", "capacity"], ["data", "reporting"]),
|
|
33
|
+
tab("client-results", "Client Results", "client-performance", ["clientKpi", "report", "dataConnector"], ["roas", "cac", "revenue", "sourceFreshness"], ["reporting", "data-sources"]),
|
|
34
|
+
tab("operations", "Operations", "process-memory", ["sop", "workflowRun", "task"], ["sopCoverage", "runHistory", "handoffHealth", "blockedWork"], ["data", "auth"]),
|
|
35
|
+
tab("settings", "Settings", "workspace-control", ["workspaceSetting", "dataConnector", "userPreference"], ["adapterState", "permissionCoverage", "auditTrail", "deploymentState"], ["auth", "payments", "integrations"])
|
|
36
|
+
];
|
|
37
|
+
const objectDefinitions = {
|
|
38
|
+
agencyAccount: object("agencyAccount", "Agency account", [["name", "text"], ["domain", "url"], ["owner", "user"], ["settings", "json"], ["createdAt", "datetime"]]),
|
|
39
|
+
client: object("client", "Client", [["name", "text"], ["retainer", "currency"], ["healthScore", "rating"], ["stage", "select"], ["primaryContact", "relation"], ["renewalDate", "date"], ["monthlyRevenue", "currency"], ["notes", "long_text"]]),
|
|
40
|
+
contact: object("contact", "Contact", [["fullName", "text"], ["email", "email"], ["phone", "phone"], ["client", "relation"], ["role", "select"], ["lastTouchAt", "datetime"]]),
|
|
41
|
+
clientKpi: object("clientKpi", "Client KPI", [["client", "relation"], ["source", "select"], ["period", "date"], ["metric", "text"], ["value", "number"], ["delta", "percentage"], ["formulaValue", "formula"]]),
|
|
42
|
+
opportunity: object("opportunity", "Opportunity", [["client", "relation"], ["name", "text"], ["stage", "select"], ["value", "currency"], ["probability", "percentage"], ["owner", "user"], ["nextFollowUp", "datetime"]]),
|
|
43
|
+
contentPlan: object("contentPlan", "Content plan", [["client", "relation"], ["channel", "multi_select"], ["publishAt", "datetime"], ["asset", "file"], ["status", "select"], ["approvers", "multi_relation"]]),
|
|
44
|
+
task: object("task", "Task", [["title", "text"], ["client", "relation"], ["owner", "user"], ["priority", "select"], ["dueAt", "datetime"], ["done", "boolean"], ["sourcePayload", "json"]]),
|
|
45
|
+
workflowRun: object("workflowRun", "Workflow run", [["name", "text"], ["status", "select"], ["startedAt", "datetime"], ["completedAt", "datetime"], ["relatedTasks", "multi_relation"], ["trace", "json"]]),
|
|
46
|
+
invoice: object("invoice", "Invoice", [["client", "relation"], ["amount", "currency"], ["status", "select"], ["dueDate", "date"], ["paidAt", "datetime"], ["lineItems", "json"]]),
|
|
47
|
+
expense: object("expense", "Expense", [["client", "relation"], ["amount", "currency"], ["category", "select"], ["receipt", "file"], ["billable", "boolean"]]),
|
|
48
|
+
report: object("report", "Report", [["client", "relation"], ["period", "date"], ["status", "select"], ["sourceConnectors", "multi_relation"], ["snapshot", "json"], ["publishedUrl", "url"]]),
|
|
49
|
+
dataConnector: object("dataConnector", "Data connector", [["provider", "text"], ["status", "select"], ["authPath", "text"], ["lastSyncedAt", "datetime"], ["metadata", "json"]]),
|
|
50
|
+
agencyMetric: object("agencyMetric", "Agency metric", [["period", "date"], ["mrr", "currency"], ["churn", "percentage"], ["utilization", "percentage"], ["pipeline", "currency"], ["score", "formula"]]),
|
|
51
|
+
sop: object("sop", "SOP", [["title", "text"], ["area", "select"], ["owner", "user"], ["body", "long_text"], ["relatedObjects", "multi_relation"], ["version", "number"]]),
|
|
52
|
+
workspaceSetting: object("workspaceSetting", "Workspace setting", [["key", "text"], ["value", "json"], ["adapter", "select"], ["permission", "select"], ["updatedAt", "datetime"]]),
|
|
53
|
+
userPreference: object("userPreference", "User preference", [["user", "user"], ["theme", "select"], ["defaultView", "text"], ["notifications", "json"]])
|
|
54
|
+
};
|
|
55
|
+
const portalCapabilities = capabilitySpecs.map(({ id, label, objectType, bindings }) => ({ id, label, objectType, bindings }));
|
|
56
|
+
function tab(id, label, objectType, objects, widgets, bindings) {
|
|
57
|
+
return { id, label, objectType, objects, widgets, bindings };
|
|
58
|
+
}
|
|
59
|
+
function object(id, label, fields) {
|
|
60
|
+
return {
|
|
61
|
+
id,
|
|
62
|
+
label,
|
|
63
|
+
fields: fields.map(([name, type]) => ({ name, type })),
|
|
64
|
+
views: ["table", "kanban", "record", "dashboard"],
|
|
65
|
+
contract: "twenty-sdk/define"
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function buildPortalWorkspace({ config, adapters, integrations }) {
|
|
69
|
+
const integrationRows = [...integrations.dataSources, ...integrations.workspaceIntegrations];
|
|
70
|
+
const connectedRows = integrationRows.filter((item) => item.isConnected);
|
|
71
|
+
const connectedDataSources = integrations.dataSources.filter((item) => item.isConnected);
|
|
72
|
+
const adapterRows = [
|
|
73
|
+
primitive("data", "Data", config.dataAdapter, adapters.persistence.mode, adapters.persistence.requiredEnv),
|
|
74
|
+
primitive("auth", "Auth", config.authAdapter, adapters.auth.id, adapters.auth.requiredEnv),
|
|
75
|
+
primitive("payments", "Payments", config.paymentAdapter, adapters.payments.enabled ? "enabled" : "disabled", adapters.payments.requiredEnv),
|
|
76
|
+
primitive("integrations", "Integrations", config.integrationAdapter, adapters.integrations.authority, adapters.integrations.requiredEnv),
|
|
77
|
+
primitive("reporting", "Reporting", config.reportingAdapter || "not-configured", config.dataSources.hasWindsorApiKey ? "windsor-key-present" : "adapter-selected", []),
|
|
78
|
+
primitive("data-sources", "Data sources", `${connectedDataSources.length}/${integrations.dataSources.length}`, config.dataSources.hasWindsorApiKey ? "windsor-overlay" : "integration-state", [])
|
|
79
|
+
];
|
|
80
|
+
return {
|
|
81
|
+
identity: {
|
|
82
|
+
label: "Growthub Workspace",
|
|
83
|
+
mark: "GH",
|
|
84
|
+
mode: "governed-worker-kit",
|
|
85
|
+
deployTarget: config.deployTarget,
|
|
86
|
+
primitiveContract: "twenty-sdk/define objects, fields, views, dashboards, widgets, permissions, CRUD, API, webhooks, and audit logs",
|
|
87
|
+
fieldTypes
|
|
88
|
+
},
|
|
89
|
+
navigation: [
|
|
90
|
+
...portalCapabilities.map((item) => ({ href: `#${item.id}`, label: item.label })),
|
|
91
|
+
{ href: "/settings/integrations", label: "Integrations" }
|
|
92
|
+
],
|
|
93
|
+
summary: [
|
|
94
|
+
primitive("object-schema", "Object schema", `${Object.keys(objectDefinitions).length} objects`, "twenty-sdk/define", fieldTypes),
|
|
95
|
+
primitive("dashboard-widgets", "Dashboard widgets", `${capabilitySpecs.reduce((total, item) => total + item.widgets.length, 0)} widgets`, "capability dashboards", ["bar", "line", "pie", "number"]),
|
|
96
|
+
primitive("connection-state", "Connection state", `${connectedRows.length}/${integrationRows.length}`, config.integrationAdapter, adapters.integrations.requiredEnv)
|
|
97
|
+
],
|
|
98
|
+
adapters: adapterRows,
|
|
99
|
+
capabilities: capabilitySpecs.map((item) => buildCapabilityPrimitive(item, adapterRows, integrations)),
|
|
100
|
+
actions: capabilitySpecs.slice(0, 5).map((item) => ({ href: `#${item.id}`, label: item.label, objectType: item.objectType })),
|
|
101
|
+
api: [
|
|
102
|
+
{ label: "Workspace contract", href: "/api/workspace", method: "GET" },
|
|
103
|
+
{ label: "Integration contract", href: "/api/settings/integrations", method: "GET" }
|
|
104
|
+
]
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function primitive(id, label, value, source, env) {
|
|
108
|
+
return {
|
|
109
|
+
id,
|
|
110
|
+
label,
|
|
111
|
+
value,
|
|
112
|
+
source,
|
|
113
|
+
env,
|
|
114
|
+
status: env.length ? "configured-by-env" : "runtime-derived"
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function buildCapabilityPrimitive(capability, adapterRows, integrations) {
|
|
118
|
+
const bindings = adapterRows.filter((item) => capability.bindings.includes(item.id));
|
|
119
|
+
const relatedObjects = capability.objects.map((id) => objectDefinitions[id]);
|
|
120
|
+
const fieldCount = relatedObjects.reduce((count, item) => count + item.fields.length, 0);
|
|
121
|
+
const dataSources = integrations.dataSources.filter((item) => capability.bindings.includes("data-sources") || capability.bindings.includes("reporting"));
|
|
122
|
+
const workspaceIntegrations = integrations.workspaceIntegrations.filter((item) => capability.bindings.includes("integrations"));
|
|
123
|
+
return {
|
|
124
|
+
...capability,
|
|
125
|
+
status: bindings.some((item) => item.value === "not-configured") ? "needs-runtime-config" : "runtime-ready",
|
|
126
|
+
fields: fieldCount,
|
|
127
|
+
objects: relatedObjects,
|
|
128
|
+
views: Array.from(new Set(relatedObjects.flatMap((item) => item.views))),
|
|
129
|
+
widgets: capability.widgets.map((id, index) => ({
|
|
130
|
+
id,
|
|
131
|
+
chart: ["number", "bar", "line", "pie"][index % 4],
|
|
132
|
+
sourceObject: relatedObjects[index % relatedObjects.length].id,
|
|
133
|
+
filters: ["client", "period", "owner", "status"].slice(0, 2 + index % 3),
|
|
134
|
+
realtime: true
|
|
135
|
+
})),
|
|
136
|
+
bindings,
|
|
137
|
+
integrations: [...dataSources, ...workspaceIntegrations].map((item) => ({
|
|
138
|
+
id: item.id,
|
|
139
|
+
label: item.label,
|
|
140
|
+
provider: item.provider,
|
|
141
|
+
objectType: item.objectType,
|
|
142
|
+
status: item.status,
|
|
143
|
+
source: item.authPath
|
|
144
|
+
}))
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
export {
|
|
148
|
+
buildPortalWorkspace,
|
|
149
|
+
portalCapabilities
|
|
150
|
+
};
|