@rulebricks/cli 2.1.6 → 2.1.7
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/README.md +26 -0
- package/cluster-setup/aws/README.md +74 -0
- package/cluster-setup/aws/check-aws-access.sh +78 -0
- package/cluster-setup/aws/cluster.yaml +33 -0
- package/cluster-setup/azure/README.md +93 -0
- package/cluster-setup/azure/check-aks-prereqs.sh +96 -0
- package/cluster-setup/azure/main.bicep +282 -0
- package/cluster-setup/azure/main.parameters.json +21 -0
- package/cluster-setup/gcp/README.md +172 -0
- package/cluster-setup/gcp/check-gke-prereqs.sh +98 -0
- package/dist/commands/init.js +9 -2
- package/dist/components/Wizard/WizardContext.d.ts +27 -3
- package/dist/components/Wizard/WizardContext.js +95 -2
- package/dist/components/Wizard/steps/CloudProviderStep.js +7 -2
- package/dist/components/Wizard/steps/FeatureConfigStep.js +407 -10
- package/dist/components/Wizard/steps/ReviewStep.js +7 -2
- package/dist/lib/helmValues.js +227 -22
- package/dist/lib/kubernetes.d.ts +7 -1
- package/dist/lib/kubernetes.js +59 -0
- package/dist/types/index.d.ts +367 -6
- package/dist/types/index.js +46 -1
- package/package.json +2 -1
|
@@ -54,9 +54,27 @@ function BucketSelector({ loggingSink, loggingRegion, availableBuckets, isRefres
|
|
|
54
54
|
const hasBuckets = availableBuckets.length > 0;
|
|
55
55
|
return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsxs(Text, { bold: true, children: [loggingSink === "s3" && "Select S3 Bucket", loggingSink === "azure-blob" && "Select Azure Storage Account", loggingSink === "gcs" && "Select GCS Bucket"] }), _jsxs(Text, { color: "gray", dimColor: true, children: ["Select an existing bucket in ", loggingRegion] }), isRefreshing ? (_jsx(Box, { marginTop: 1, children: _jsx(Spinner, { label: "Refreshing bucket list..." }) })) : hasBuckets ? (_jsx(Box, { marginTop: 1, height: 10, flexDirection: "column", overflowY: "hidden", children: _jsx(SelectInput, { items: bucketItems, onSelect: onSelect, limit: 8, indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) }) })) : (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { color: "yellow", children: ["No buckets found in ", loggingRegion, "."] }), _jsx(Text, { color: "gray", dimColor: true, children: "Create a bucket in your cloud console, then press R to refresh." })] })), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" ", "Sink: ", LOGGING_SINK_INFO[loggingSink]?.name] })] }), _jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Region: ", loggingRegion] })] })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "R to refresh list \u2022 \u2191/\u2193 to navigate \u2022 Enter to select" }) })] }));
|
|
56
56
|
}
|
|
57
|
-
const
|
|
58
|
-
{ label: "
|
|
59
|
-
{ label: "
|
|
57
|
+
const MONITORING_DESTINATIONS = [
|
|
58
|
+
{ label: "Local Grafana (bundled)", value: "local-grafana" },
|
|
59
|
+
{ label: "AWS Managed Prometheus (AMP)", value: "aws-amp" },
|
|
60
|
+
{ label: "Azure Monitor managed Prometheus", value: "azure-monitor" },
|
|
61
|
+
{ label: "Grafana Cloud", value: "grafana-cloud" },
|
|
62
|
+
{ label: "Generic Prometheus remote_write", value: "generic" },
|
|
63
|
+
];
|
|
64
|
+
const REMOTE_WRITE_DESTINATIONS = MONITORING_DESTINATIONS.filter((destination) => destination.value !== "local-grafana");
|
|
65
|
+
const AZURE_REMOTE_WRITE_AUTH = [
|
|
66
|
+
{ label: "Workload identity", value: "workload-identity" },
|
|
67
|
+
{ label: "Managed identity", value: "managed-identity" },
|
|
68
|
+
{ label: "OAuth client secret", value: "oauth" },
|
|
69
|
+
];
|
|
70
|
+
const AZURE_LOGGING_AUTH = [
|
|
71
|
+
{ label: "Workload identity", value: "workload-identity" },
|
|
72
|
+
{ label: "Connection string Secret (fallback)", value: "secret" },
|
|
73
|
+
];
|
|
74
|
+
const GENERIC_REMOTE_WRITE_AUTH = [
|
|
75
|
+
{ label: "No additional auth", value: "none" },
|
|
76
|
+
{ label: "Basic auth from Kubernetes Secret", value: "basic" },
|
|
77
|
+
{ label: "Bearer token from Kubernetes Secret", value: "bearer" },
|
|
60
78
|
];
|
|
61
79
|
export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
62
80
|
const { state, dispatch } = useWizard();
|
|
@@ -88,9 +106,27 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
88
106
|
const [ssoClientId, setSsoClientId] = useState(state.ssoClientId || "");
|
|
89
107
|
const [ssoClientSecret, setSsoClientSecret] = useState(state.ssoClientSecret || "");
|
|
90
108
|
const [remoteWriteUrl, setRemoteWriteUrl] = useState(state.prometheusRemoteWriteUrl || "");
|
|
109
|
+
const [remoteWriteDestination, setRemoteWriteDestination] = useState(state.prometheusRemoteWriteDestination);
|
|
110
|
+
const [remoteWriteAuthType, setRemoteWriteAuthType] = useState(state.prometheusRemoteWriteAuthType);
|
|
111
|
+
const [remoteWriteAwsRegion, setRemoteWriteAwsRegion] = useState(state.prometheusRemoteWriteAwsRegion || state.region || "us-east-1");
|
|
112
|
+
const [remoteWriteAwsRoleArn, setRemoteWriteAwsRoleArn] = useState(state.prometheusRemoteWriteAwsRoleArn || "");
|
|
113
|
+
const [remoteWriteAzureCloud] = useState(state.prometheusRemoteWriteAzureCloud || "AzurePublic");
|
|
114
|
+
const [remoteWriteClientId, setRemoteWriteClientId] = useState(state.prometheusRemoteWriteClientId || "");
|
|
115
|
+
const [remoteWriteTenantId, setRemoteWriteTenantId] = useState(state.prometheusRemoteWriteTenantId || "");
|
|
116
|
+
const [remoteWriteSecretRef, setRemoteWriteSecretRef] = useState(state.prometheusRemoteWriteSecretRef || "");
|
|
117
|
+
const [remoteWriteUsernameSecretRef, setRemoteWriteUsernameSecretRef] = useState(state.prometheusRemoteWriteUsernameSecretRef || "");
|
|
118
|
+
const [remoteWritePasswordSecretRef, setRemoteWritePasswordSecretRef] = useState(state.prometheusRemoteWritePasswordSecretRef || "");
|
|
119
|
+
const [remoteWriteBearerSecretRef, setRemoteWriteBearerSecretRef] = useState(state.prometheusRemoteWriteBearerTokenSecretRef || "");
|
|
91
120
|
const [loggingSink, setLoggingSink] = useState(state.loggingSink);
|
|
92
121
|
const [loggingBucket, setLoggingBucket] = useState(state.loggingBucket || "");
|
|
93
122
|
const [loggingRegion, setLoggingRegion] = useState(state.loggingRegion || "");
|
|
123
|
+
const [loggingCloudAuthMode, setLoggingCloudAuthMode] = useState(state.loggingCloudAuthMode || "workload-identity");
|
|
124
|
+
const [s3RoleArn, setS3RoleArn] = useState(state.loggingAwsIamRoleArn || "");
|
|
125
|
+
const [azureBlobContainer, setAzureBlobContainer] = useState(state.loggingAzureBlobContainer || "rulebricks-logs");
|
|
126
|
+
const [azureBlobClientId, setAzureBlobClientId] = useState(state.loggingAzureBlobClientId || "");
|
|
127
|
+
const [azureBlobTenantId, setAzureBlobTenantId] = useState(state.loggingAzureBlobTenantId || "");
|
|
128
|
+
const [azureBlobConnectionStringSecretRef, setAzureBlobConnectionStringSecretRef,] = useState(state.loggingAzureBlobConnectionStringSecretRef || "");
|
|
129
|
+
const [gcpServiceAccountEmail, setGcpServiceAccountEmail] = useState(state.loggingGcpServiceAccountEmail || "");
|
|
94
130
|
const [loggingCategory, setLoggingCategory] = useState(null);
|
|
95
131
|
const [error, setError] = useState(null);
|
|
96
132
|
// Logging platform config
|
|
@@ -167,9 +203,49 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
167
203
|
else
|
|
168
204
|
onBack();
|
|
169
205
|
break;
|
|
170
|
-
case "monitoring-remote-write-
|
|
206
|
+
case "monitoring-remote-write-destination":
|
|
171
207
|
setSubStep("monitoring-remote-write-ask");
|
|
172
208
|
break;
|
|
209
|
+
case "monitoring-remote-write-url":
|
|
210
|
+
setSubStep("monitoring-remote-write-destination");
|
|
211
|
+
break;
|
|
212
|
+
case "monitoring-aws-region":
|
|
213
|
+
setSubStep("monitoring-remote-write-url");
|
|
214
|
+
break;
|
|
215
|
+
case "monitoring-aws-role-arn":
|
|
216
|
+
setSubStep("monitoring-aws-region");
|
|
217
|
+
break;
|
|
218
|
+
case "monitoring-remote-write-azure-auth":
|
|
219
|
+
case "monitoring-remote-write-generic-auth":
|
|
220
|
+
setSubStep("monitoring-remote-write-url");
|
|
221
|
+
break;
|
|
222
|
+
case "monitoring-remote-write-client-id":
|
|
223
|
+
if (remoteWriteDestination === "azure-monitor") {
|
|
224
|
+
setSubStep("monitoring-remote-write-azure-auth");
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
setSubStep("monitoring-remote-write-url");
|
|
228
|
+
}
|
|
229
|
+
break;
|
|
230
|
+
case "monitoring-remote-write-tenant-id":
|
|
231
|
+
setSubStep("monitoring-remote-write-client-id");
|
|
232
|
+
break;
|
|
233
|
+
case "monitoring-remote-write-secret-ref":
|
|
234
|
+
setSubStep(remoteWriteDestination === "azure-monitor"
|
|
235
|
+
? "monitoring-remote-write-tenant-id"
|
|
236
|
+
: "monitoring-remote-write-url");
|
|
237
|
+
break;
|
|
238
|
+
case "monitoring-remote-write-username-secret-ref":
|
|
239
|
+
setSubStep(remoteWriteDestination === "grafana-cloud"
|
|
240
|
+
? "monitoring-remote-write-url"
|
|
241
|
+
: "monitoring-remote-write-generic-auth");
|
|
242
|
+
break;
|
|
243
|
+
case "monitoring-remote-write-password-secret-ref":
|
|
244
|
+
setSubStep("monitoring-remote-write-username-secret-ref");
|
|
245
|
+
break;
|
|
246
|
+
case "monitoring-remote-write-bearer-secret-ref":
|
|
247
|
+
setSubStep("monitoring-remote-write-generic-auth");
|
|
248
|
+
break;
|
|
173
249
|
case "logging-category":
|
|
174
250
|
if (needsMonitoring)
|
|
175
251
|
setSubStep("monitoring-remote-write-ask");
|
|
@@ -191,6 +267,27 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
191
267
|
case "logging-bucket-loading":
|
|
192
268
|
setSubStep("logging-region");
|
|
193
269
|
break;
|
|
270
|
+
case "logging-s3-role-arn":
|
|
271
|
+
setSubStep("logging-bucket");
|
|
272
|
+
break;
|
|
273
|
+
case "logging-azure-container":
|
|
274
|
+
setSubStep("logging-bucket");
|
|
275
|
+
break;
|
|
276
|
+
case "logging-azure-auth":
|
|
277
|
+
setSubStep("logging-azure-container");
|
|
278
|
+
break;
|
|
279
|
+
case "logging-azure-client-id":
|
|
280
|
+
setSubStep("logging-azure-auth");
|
|
281
|
+
break;
|
|
282
|
+
case "logging-azure-tenant-id":
|
|
283
|
+
setSubStep("logging-azure-client-id");
|
|
284
|
+
break;
|
|
285
|
+
case "logging-azure-connection-string-secret":
|
|
286
|
+
setSubStep("logging-azure-auth");
|
|
287
|
+
break;
|
|
288
|
+
case "logging-gcp-service-account":
|
|
289
|
+
setSubStep("logging-bucket");
|
|
290
|
+
break;
|
|
194
291
|
// Logging platform config steps
|
|
195
292
|
case "logging-datadog-config":
|
|
196
293
|
case "logging-splunk-config":
|
|
@@ -261,7 +358,18 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
261
358
|
onComplete();
|
|
262
359
|
break;
|
|
263
360
|
case "monitoring-remote-write-ask":
|
|
361
|
+
case "monitoring-remote-write-destination":
|
|
264
362
|
case "monitoring-remote-write-url":
|
|
363
|
+
case "monitoring-aws-region":
|
|
364
|
+
case "monitoring-aws-role-arn":
|
|
365
|
+
case "monitoring-remote-write-azure-auth":
|
|
366
|
+
case "monitoring-remote-write-generic-auth":
|
|
367
|
+
case "monitoring-remote-write-client-id":
|
|
368
|
+
case "monitoring-remote-write-tenant-id":
|
|
369
|
+
case "monitoring-remote-write-secret-ref":
|
|
370
|
+
case "monitoring-remote-write-username-secret-ref":
|
|
371
|
+
case "monitoring-remote-write-password-secret-ref":
|
|
372
|
+
case "monitoring-remote-write-bearer-secret-ref":
|
|
265
373
|
if (needsLogging)
|
|
266
374
|
setSubStep("logging-category");
|
|
267
375
|
else if (needsCustomEmails)
|
|
@@ -270,6 +378,10 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
270
378
|
onComplete();
|
|
271
379
|
break;
|
|
272
380
|
case "logging-bucket":
|
|
381
|
+
case "logging-s3-role-arn":
|
|
382
|
+
case "logging-azure-tenant-id":
|
|
383
|
+
case "logging-azure-connection-string-secret":
|
|
384
|
+
case "logging-gcp-service-account":
|
|
273
385
|
// Cloud storage config complete, check for custom emails
|
|
274
386
|
if (needsCustomEmails)
|
|
275
387
|
setSubStep("email-subject-invite");
|
|
@@ -362,13 +474,35 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
362
474
|
};
|
|
363
475
|
// === Monitoring Configuration ===
|
|
364
476
|
const handleRemoteWriteAsk = (item) => {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
else {
|
|
477
|
+
const destination = item.value;
|
|
478
|
+
if (destination === "local-grafana") {
|
|
479
|
+
setRemoteWriteDestination(null);
|
|
369
480
|
dispatch({ type: "SET_PROMETHEUS_REMOTE_WRITE", url: "" });
|
|
481
|
+
dispatch({
|
|
482
|
+
type: "SET_PROMETHEUS_REMOTE_WRITE_CONFIG",
|
|
483
|
+
config: {
|
|
484
|
+
prometheusMonitoringDestination: "local-grafana",
|
|
485
|
+
prometheusRemoteWriteDestination: null,
|
|
486
|
+
prometheusRemoteWriteAuthType: null,
|
|
487
|
+
},
|
|
488
|
+
});
|
|
370
489
|
advanceToNext("monitoring-remote-write-ask");
|
|
490
|
+
return;
|
|
371
491
|
}
|
|
492
|
+
handleRemoteWriteDestinationSelect({ value: destination });
|
|
493
|
+
};
|
|
494
|
+
const handleRemoteWriteDestinationSelect = (item) => {
|
|
495
|
+
const destination = item.value;
|
|
496
|
+
setRemoteWriteDestination(destination);
|
|
497
|
+
setError(null);
|
|
498
|
+
dispatch({
|
|
499
|
+
type: "SET_PROMETHEUS_REMOTE_WRITE_CONFIG",
|
|
500
|
+
config: {
|
|
501
|
+
prometheusMonitoringDestination: destination,
|
|
502
|
+
prometheusRemoteWriteDestination: destination,
|
|
503
|
+
},
|
|
504
|
+
});
|
|
505
|
+
setSubStep("monitoring-remote-write-url");
|
|
372
506
|
};
|
|
373
507
|
const handleRemoteWriteUrlSubmit = () => {
|
|
374
508
|
if (remoteWriteUrl) {
|
|
@@ -382,8 +516,165 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
382
516
|
}
|
|
383
517
|
setError(null);
|
|
384
518
|
dispatch({ type: "SET_PROMETHEUS_REMOTE_WRITE", url: remoteWriteUrl });
|
|
519
|
+
if (remoteWriteDestination === "aws-amp") {
|
|
520
|
+
setSubStep("monitoring-aws-region");
|
|
521
|
+
}
|
|
522
|
+
else if (remoteWriteDestination === "azure-monitor") {
|
|
523
|
+
setSubStep("monitoring-remote-write-azure-auth");
|
|
524
|
+
}
|
|
525
|
+
else if (remoteWriteDestination === "grafana-cloud") {
|
|
526
|
+
setRemoteWriteAuthType("basic");
|
|
527
|
+
dispatch({
|
|
528
|
+
type: "SET_PROMETHEUS_REMOTE_WRITE_CONFIG",
|
|
529
|
+
config: { prometheusRemoteWriteAuthType: "basic" },
|
|
530
|
+
});
|
|
531
|
+
setSubStep("monitoring-remote-write-username-secret-ref");
|
|
532
|
+
}
|
|
533
|
+
else if (remoteWriteDestination === "generic") {
|
|
534
|
+
setSubStep("monitoring-remote-write-generic-auth");
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
setError("Select a remote_write destination first");
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
const handleAwsRemoteWriteRegionSubmit = () => {
|
|
541
|
+
if (!remoteWriteAwsRegion) {
|
|
542
|
+
setError("AWS region is required");
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
setError(null);
|
|
546
|
+
setSubStep("monitoring-aws-role-arn");
|
|
547
|
+
};
|
|
548
|
+
const handleAwsRemoteWriteRoleArnSubmit = () => {
|
|
549
|
+
if (remoteWriteAwsRoleArn && !remoteWriteAwsRoleArn.startsWith("arn:")) {
|
|
550
|
+
setError("Enter a valid IAM role ARN or leave blank");
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
dispatch({
|
|
554
|
+
type: "SET_PROMETHEUS_REMOTE_WRITE_CONFIG",
|
|
555
|
+
config: {
|
|
556
|
+
prometheusRemoteWriteDestination: "aws-amp",
|
|
557
|
+
prometheusMonitoringDestination: "aws-amp",
|
|
558
|
+
prometheusRemoteWriteAuthType: "none",
|
|
559
|
+
prometheusRemoteWriteAwsRegion: remoteWriteAwsRegion,
|
|
560
|
+
prometheusRemoteWriteAwsRoleArn: remoteWriteAwsRoleArn,
|
|
561
|
+
},
|
|
562
|
+
});
|
|
563
|
+
setError(null);
|
|
564
|
+
advanceToNext("monitoring-aws-role-arn");
|
|
565
|
+
};
|
|
566
|
+
const saveRemoteWriteConfig = (authType, overrides = {}) => {
|
|
567
|
+
if (!remoteWriteDestination || !remoteWriteUrl) {
|
|
568
|
+
setError("Remote write destination and URL are required");
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
dispatch({
|
|
572
|
+
type: "SET_PROMETHEUS_REMOTE_WRITE_CONFIG",
|
|
573
|
+
config: {
|
|
574
|
+
prometheusRemoteWriteDestination: remoteWriteDestination,
|
|
575
|
+
prometheusMonitoringDestination: remoteWriteDestination,
|
|
576
|
+
prometheusRemoteWriteAuthType: authType,
|
|
577
|
+
prometheusRemoteWriteAzureCloud: remoteWriteAzureCloud,
|
|
578
|
+
prometheusRemoteWriteClientId: overrides.clientId ?? remoteWriteClientId,
|
|
579
|
+
prometheusRemoteWriteTenantId: overrides.tenantId ?? remoteWriteTenantId,
|
|
580
|
+
prometheusRemoteWriteSecretRef: overrides.secretRef ?? remoteWriteSecretRef,
|
|
581
|
+
prometheusRemoteWriteUsernameSecretRef: overrides.usernameSecretRef ?? remoteWriteUsernameSecretRef,
|
|
582
|
+
prometheusRemoteWritePasswordSecretRef: overrides.passwordSecretRef ?? remoteWritePasswordSecretRef,
|
|
583
|
+
prometheusRemoteWriteBearerTokenSecretRef: overrides.bearerTokenSecretRef ?? remoteWriteBearerSecretRef,
|
|
584
|
+
},
|
|
585
|
+
});
|
|
586
|
+
setError(null);
|
|
385
587
|
advanceToNext("monitoring-remote-write-url");
|
|
386
588
|
};
|
|
589
|
+
const handleAzureRemoteWriteAuthSelect = (item) => {
|
|
590
|
+
const authType = item.value;
|
|
591
|
+
setRemoteWriteAuthType(authType);
|
|
592
|
+
dispatch({
|
|
593
|
+
type: "SET_PROMETHEUS_REMOTE_WRITE_CONFIG",
|
|
594
|
+
config: { prometheusRemoteWriteAuthType: authType },
|
|
595
|
+
});
|
|
596
|
+
setSubStep("monitoring-remote-write-client-id");
|
|
597
|
+
};
|
|
598
|
+
const handleGenericRemoteWriteAuthSelect = (item) => {
|
|
599
|
+
const authType = item.value;
|
|
600
|
+
setRemoteWriteAuthType(authType);
|
|
601
|
+
if (authType === "none") {
|
|
602
|
+
saveRemoteWriteConfig("none");
|
|
603
|
+
}
|
|
604
|
+
else if (authType === "basic") {
|
|
605
|
+
setSubStep("monitoring-remote-write-username-secret-ref");
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
setSubStep("monitoring-remote-write-bearer-secret-ref");
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
const handleRemoteWriteClientIdSubmit = () => {
|
|
612
|
+
if (!remoteWriteClientId) {
|
|
613
|
+
setError("Client ID is required");
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
if (remoteWriteAuthType === "managed-identity") {
|
|
617
|
+
saveRemoteWriteConfig("managed-identity", {
|
|
618
|
+
clientId: remoteWriteClientId,
|
|
619
|
+
});
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
setError(null);
|
|
623
|
+
setSubStep("monitoring-remote-write-tenant-id");
|
|
624
|
+
};
|
|
625
|
+
const handleRemoteWriteTenantIdSubmit = () => {
|
|
626
|
+
if (!remoteWriteTenantId) {
|
|
627
|
+
setError("Tenant ID is required");
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
if (remoteWriteAuthType === "workload-identity") {
|
|
631
|
+
saveRemoteWriteConfig("workload-identity", {
|
|
632
|
+
clientId: remoteWriteClientId,
|
|
633
|
+
tenantId: remoteWriteTenantId,
|
|
634
|
+
});
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
setError(null);
|
|
638
|
+
setSubStep("monitoring-remote-write-secret-ref");
|
|
639
|
+
};
|
|
640
|
+
const handleRemoteWriteSecretRefSubmit = () => {
|
|
641
|
+
if (!remoteWriteSecretRef.includes(":")) {
|
|
642
|
+
setError("Use secret-name:key format");
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
saveRemoteWriteConfig(remoteWriteAuthType || "oauth", {
|
|
646
|
+
clientId: remoteWriteClientId,
|
|
647
|
+
tenantId: remoteWriteTenantId,
|
|
648
|
+
secretRef: remoteWriteSecretRef,
|
|
649
|
+
});
|
|
650
|
+
};
|
|
651
|
+
const handleRemoteWriteUsernameSecretRefSubmit = () => {
|
|
652
|
+
if (!remoteWriteUsernameSecretRef.includes(":")) {
|
|
653
|
+
setError("Use secret-name:key format");
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
setError(null);
|
|
657
|
+
setSubStep("monitoring-remote-write-password-secret-ref");
|
|
658
|
+
};
|
|
659
|
+
const handleRemoteWritePasswordSecretRefSubmit = () => {
|
|
660
|
+
if (!remoteWritePasswordSecretRef.includes(":")) {
|
|
661
|
+
setError("Use secret-name:key format");
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
saveRemoteWriteConfig("basic", {
|
|
665
|
+
usernameSecretRef: remoteWriteUsernameSecretRef,
|
|
666
|
+
passwordSecretRef: remoteWritePasswordSecretRef,
|
|
667
|
+
});
|
|
668
|
+
};
|
|
669
|
+
const handleRemoteWriteBearerSecretRefSubmit = () => {
|
|
670
|
+
if (!remoteWriteBearerSecretRef.includes(":")) {
|
|
671
|
+
setError("Use secret-name:key format");
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
saveRemoteWriteConfig("bearer", {
|
|
675
|
+
bearerTokenSecretRef: remoteWriteBearerSecretRef,
|
|
676
|
+
});
|
|
677
|
+
};
|
|
387
678
|
// === Logging Configuration ===
|
|
388
679
|
// Map logging sink to cloud provider
|
|
389
680
|
const sinkToProvider = (sink) => {
|
|
@@ -505,8 +796,114 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
505
796
|
type: "SET_LOGGING_CONFIG",
|
|
506
797
|
config: { loggingBucket: item.value },
|
|
507
798
|
});
|
|
799
|
+
if (loggingSink === "s3") {
|
|
800
|
+
setSubStep("logging-s3-role-arn");
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
if (loggingSink === "azure-blob") {
|
|
804
|
+
setSubStep("logging-azure-container");
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
if (loggingSink === "gcs") {
|
|
808
|
+
setSubStep("logging-gcp-service-account");
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
508
811
|
advanceToNext("logging-bucket");
|
|
509
812
|
};
|
|
813
|
+
const handleS3RoleArnSubmit = () => {
|
|
814
|
+
if (!s3RoleArn.startsWith("arn:")) {
|
|
815
|
+
setError("IAM role ARN is required for S3 IRSA");
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
setError(null);
|
|
819
|
+
dispatch({
|
|
820
|
+
type: "SET_LOGGING_CONFIG",
|
|
821
|
+
config: {
|
|
822
|
+
loggingCloudAuthMode: "workload-identity",
|
|
823
|
+
loggingAwsIamRoleArn: s3RoleArn,
|
|
824
|
+
},
|
|
825
|
+
});
|
|
826
|
+
advanceToNext("logging-s3-role-arn");
|
|
827
|
+
};
|
|
828
|
+
const handleAzureBlobContainerSubmit = () => {
|
|
829
|
+
if (!azureBlobContainer) {
|
|
830
|
+
setError("Azure Blob container name is required");
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
setError(null);
|
|
834
|
+
dispatch({
|
|
835
|
+
type: "SET_LOGGING_CONFIG",
|
|
836
|
+
config: { loggingAzureBlobContainer: azureBlobContainer },
|
|
837
|
+
});
|
|
838
|
+
setSubStep("logging-azure-auth");
|
|
839
|
+
};
|
|
840
|
+
const handleAzureBlobAuthSelect = (item) => {
|
|
841
|
+
const authMode = item.value;
|
|
842
|
+
setLoggingCloudAuthMode(authMode);
|
|
843
|
+
dispatch({
|
|
844
|
+
type: "SET_LOGGING_CONFIG",
|
|
845
|
+
config: { loggingCloudAuthMode: authMode },
|
|
846
|
+
});
|
|
847
|
+
setSubStep(authMode === "workload-identity"
|
|
848
|
+
? "logging-azure-client-id"
|
|
849
|
+
: "logging-azure-connection-string-secret");
|
|
850
|
+
};
|
|
851
|
+
const handleAzureBlobClientIdSubmit = () => {
|
|
852
|
+
if (!azureBlobClientId) {
|
|
853
|
+
setError("Managed identity client ID is required");
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
setError(null);
|
|
857
|
+
setSubStep("logging-azure-tenant-id");
|
|
858
|
+
};
|
|
859
|
+
const handleAzureBlobTenantIdSubmit = () => {
|
|
860
|
+
if (!azureBlobTenantId) {
|
|
861
|
+
setError("Azure tenant ID is required");
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
setError(null);
|
|
865
|
+
dispatch({
|
|
866
|
+
type: "SET_LOGGING_CONFIG",
|
|
867
|
+
config: {
|
|
868
|
+
loggingCloudAuthMode: "workload-identity",
|
|
869
|
+
loggingAzureBlobContainer: azureBlobContainer,
|
|
870
|
+
loggingAzureBlobClientId: azureBlobClientId,
|
|
871
|
+
loggingAzureBlobTenantId: azureBlobTenantId,
|
|
872
|
+
},
|
|
873
|
+
});
|
|
874
|
+
advanceToNext("logging-azure-tenant-id");
|
|
875
|
+
};
|
|
876
|
+
const handleAzureBlobConnectionStringSecretSubmit = () => {
|
|
877
|
+
if (!azureBlobConnectionStringSecretRef.includes(":")) {
|
|
878
|
+
setError("Use secret-name:key format");
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
setError(null);
|
|
882
|
+
dispatch({
|
|
883
|
+
type: "SET_LOGGING_CONFIG",
|
|
884
|
+
config: {
|
|
885
|
+
loggingAzureBlobContainer: azureBlobContainer,
|
|
886
|
+
loggingCloudAuthMode: "secret",
|
|
887
|
+
loggingAzureBlobConnectionStringSecretRef: azureBlobConnectionStringSecretRef,
|
|
888
|
+
},
|
|
889
|
+
});
|
|
890
|
+
advanceToNext("logging-azure-connection-string-secret");
|
|
891
|
+
};
|
|
892
|
+
const handleGcpServiceAccountSubmit = () => {
|
|
893
|
+
if (!gcpServiceAccountEmail.includes("@")) {
|
|
894
|
+
setError("Google service account email is required");
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
setError(null);
|
|
898
|
+
dispatch({
|
|
899
|
+
type: "SET_LOGGING_CONFIG",
|
|
900
|
+
config: {
|
|
901
|
+
loggingCloudAuthMode: "workload-identity",
|
|
902
|
+
loggingGcpServiceAccountEmail: gcpServiceAccountEmail,
|
|
903
|
+
},
|
|
904
|
+
});
|
|
905
|
+
advanceToNext("logging-gcp-service-account");
|
|
906
|
+
};
|
|
510
907
|
// === Logging Platform Config Handlers ===
|
|
511
908
|
const handleDatadogConfigSubmit = () => {
|
|
512
909
|
if (!datadogApiKey) {
|
|
@@ -752,14 +1149,14 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
752
1149
|
return (_jsxs(BorderBox, { title: "Feature Configuration", children: [subStep === "openai-key" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "OpenAI API Key" }), _jsx(Text, { color: "gray", dimColor: true, children: "Required for AI-powered rule generation features" }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: openaiKey, onChange: setOpenaiKey, onSubmit: handleOpenAIKeySubmit, placeholder: "sk-...", mask: "*" }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "Get your API key at: https://platform.openai.com/api-keys" }) })] })), subStep === "sso-provider" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "SSO Provider" }), _jsx(Text, { color: "gray", dimColor: true, children: "Select your identity provider" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: SSO_PROVIDERS, onSelect: handleSsoProviderSelect, itemComponent: ({ isSelected, label }) => (_jsx(Text, { color: isSelected ? colors.accent : undefined, children: label })) }) }), _jsx(ProgressSummary, {})] })), subStep === "sso-url" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsxs(Text, { bold: true, children: [ssoProvider?.toUpperCase(), " Provider URL"] }), _jsxs(Text, { color: "gray", dimColor: true, children: [ssoProvider === "azure" &&
|
|
753
1150
|
"e.g., https://login.microsoftonline.com/your-tenant-id", ssoProvider === "okta" && "e.g., https://your-org.okta.com", ssoProvider === "keycloak" &&
|
|
754
1151
|
"e.g., https://keycloak.example.com/realms/your-realm", ssoProvider === "ory" &&
|
|
755
|
-
"e.g., https://your-project.projects.oryapis.com", ssoProvider === "other" && "The base URL of your OIDC provider"] }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: ssoUrl, onChange: setSsoUrl, onSubmit: handleSsoUrlSubmit, placeholder: "https://..." }) }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Provider: ", ssoProvider] })] })] })), subStep === "sso-client-id" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "OAuth Client ID" }), _jsx(Text, { color: "gray", dimColor: true, children: "The client/application ID from your identity provider" }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: ssoClientId, onChange: setSsoClientId, onSubmit: handleSsoClientIdSubmit, placeholder: "your-client-id" }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Provider: ", ssoProvider] })] }), ssoUrl && (_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" URL: ", ssoUrl] })] }))] })] })), subStep === "sso-client-secret" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "OAuth Client Secret" }), _jsx(Text, { color: "gray", dimColor: true, children: "The client secret from your identity provider" }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: ssoClientSecret, onChange: setSsoClientSecret, onSubmit: handleSsoClientSecretSubmit, placeholder: "your-client-secret", mask: "*" }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Provider: ", ssoProvider] })] }), _jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsx(Text, { color: "gray", children: " Client ID configured" })] })] })] })), subStep === "monitoring-remote-write-ask" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Prometheus Remote Write" }), _jsx(Text, { color: "gray", dimColor: true, children: "Do you want to send metrics to an external monitoring system?" }), _jsx(Text, { color: "gray", dimColor: true, children: "(e.g., Datadog, Grafana Cloud, Chronosphere)" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: YES_NO_OPTIONS, onSelect: handleRemoteWriteAsk, itemComponent: ({ isSelected, label }) => (_jsx(Text, { color: isSelected ? colors.accent : undefined, children: label })) }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-url" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Remote Write URL" }), _jsx(Text, { color: "gray", dimColor: true, children: "Prometheus remote_write endpoint URL" }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: remoteWriteUrl, onChange: setRemoteWriteUrl, onSubmit: handleRemoteWriteUrlSubmit, placeholder: "https://metrics.example.com/api/v1/write" }) }), _jsx(ProgressSummary, {})] })), subStep === "logging-category" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "External Logging Destination" }), _jsx(Text, { color: "gray", dimColor: true, children: "Choose how you want to store decision logs (Console logging is always included)" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: LOGGING_CATEGORIES, onSelect: handleLoggingCategorySelect, indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) }) }), _jsx(ProgressSummary, {})] })), subStep === "logging-sink" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: loggingCategory === "cloud-storage"
|
|
1152
|
+
"e.g., https://your-project.projects.oryapis.com", ssoProvider === "other" && "The base URL of your OIDC provider"] }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: ssoUrl, onChange: setSsoUrl, onSubmit: handleSsoUrlSubmit, placeholder: "https://..." }) }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Provider: ", ssoProvider] })] })] })), subStep === "sso-client-id" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "OAuth Client ID" }), _jsx(Text, { color: "gray", dimColor: true, children: "The client/application ID from your identity provider" }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: ssoClientId, onChange: setSsoClientId, onSubmit: handleSsoClientIdSubmit, placeholder: "your-client-id" }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Provider: ", ssoProvider] })] }), ssoUrl && (_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" URL: ", ssoUrl] })] }))] })] })), subStep === "sso-client-secret" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "OAuth Client Secret" }), _jsx(Text, { color: "gray", dimColor: true, children: "The client secret from your identity provider" }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: ssoClientSecret, onChange: setSsoClientSecret, onSubmit: handleSsoClientSecretSubmit, placeholder: "your-client-secret", mask: "*" }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Provider: ", ssoProvider] })] }), _jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsx(Text, { color: "gray", children: " Client ID configured" })] })] })] })), subStep === "monitoring-remote-write-ask" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Monitoring Destination" }), _jsx(Text, { color: "gray", dimColor: true, children: "Choose where Prometheus metrics should be viewed or sent." }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: MONITORING_DESTINATIONS, onSelect: handleRemoteWriteAsk, indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-url" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Remote Write URL" }), _jsx(Text, { color: "gray", dimColor: true, children: "Prometheus remote_write endpoint URL" }), remoteWriteDestination === "azure-monitor" && (_jsx(Text, { color: "gray", dimColor: true, children: "Use the ingestion URL from your Azure Monitor workspace/Data Collection Rule." })), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: remoteWriteUrl, onChange: setRemoteWriteUrl, onSubmit: handleRemoteWriteUrlSubmit, placeholder: "https://metrics.example.com/api/v1/write" }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-aws-region" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "AWS Managed Prometheus Region" }), _jsx(Text, { color: "gray", dimColor: true, children: "Region used for SigV4 signing." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: remoteWriteAwsRegion, onChange: setRemoteWriteAwsRegion, onSubmit: handleAwsRemoteWriteRegionSubmit, placeholder: "us-east-1" }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-aws-role-arn" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Prometheus IRSA Role ARN" }), _jsx(Text, { color: "gray", dimColor: true, children: "Optional. If provided, the Prometheus service account will be annotated with this role." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: remoteWriteAwsRoleArn, onChange: setRemoteWriteAwsRoleArn, onSubmit: handleAwsRemoteWriteRoleArnSubmit, placeholder: "arn:aws:iam::123456789012:role/rulebricks-prometheus" }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-destination" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Remote Write Destination" }), _jsx(Text, { color: "gray", dimColor: true, children: "Select the monitoring backend so required auth fields can be collected." }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: REMOTE_WRITE_DESTINATIONS, onSelect: handleRemoteWriteDestinationSelect, indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-azure-auth" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Azure Monitor Authentication" }), _jsx(Text, { color: "gray", dimColor: true, children: "Azure Monitor managed Prometheus requires Azure AD authentication." }), _jsxs(Text, { color: "gray", dimColor: true, children: ["Cloud: ", remoteWriteAzureCloud] }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: AZURE_REMOTE_WRITE_AUTH, onSelect: handleAzureRemoteWriteAuthSelect, indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-generic-auth" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Generic Remote Write Authentication" }), _jsx(Text, { color: "gray", dimColor: true, children: "Choose the auth method required by the remote_write endpoint." }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: GENERIC_REMOTE_WRITE_AUTH, onSelect: handleGenericRemoteWriteAuthSelect, indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-client-id" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Azure Client ID" }), _jsx(Text, { color: "gray", dimColor: true, children: "Use the managed identity, workload identity, or app registration client ID." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: remoteWriteClientId, onChange: setRemoteWriteClientId, onSubmit: handleRemoteWriteClientIdSubmit, placeholder: "00000000-0000-0000-0000-000000000000" }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-tenant-id" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Azure Tenant ID" }), _jsx(Text, { color: "gray", dimColor: true, children: "Required for workload identity and OAuth client-secret auth." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: remoteWriteTenantId, onChange: setRemoteWriteTenantId, onSubmit: handleRemoteWriteTenantIdSubmit, placeholder: "00000000-0000-0000-0000-000000000000" }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-secret-ref" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Client Secret Reference" }), _jsx(Text, { color: "gray", dimColor: true, children: "Existing Kubernetes Secret key in the format name:key." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: remoteWriteSecretRef, onChange: setRemoteWriteSecretRef, onSubmit: handleRemoteWriteSecretRefSubmit, placeholder: "azure-monitor-oauth:client-secret" }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-username-secret-ref" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Basic Auth Username Reference" }), _jsx(Text, { color: "gray", dimColor: true, children: "Existing Kubernetes Secret key in the format name:key. For Grafana Cloud, this is the instance ID." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: remoteWriteUsernameSecretRef, onChange: setRemoteWriteUsernameSecretRef, onSubmit: handleRemoteWriteUsernameSecretRefSubmit, placeholder: "prometheus-remote-write:username" }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-password-secret-ref" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Basic Auth Password Reference" }), _jsx(Text, { color: "gray", dimColor: true, children: "Existing Kubernetes Secret key in the format name:key. For Grafana Cloud, this is an API token." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: remoteWritePasswordSecretRef, onChange: setRemoteWritePasswordSecretRef, onSubmit: handleRemoteWritePasswordSecretRefSubmit, placeholder: "prometheus-remote-write:password" }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-bearer-secret-ref" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Bearer Token Reference" }), _jsx(Text, { color: "gray", dimColor: true, children: "Existing Kubernetes Secret key in the format name:key." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: remoteWriteBearerSecretRef, onChange: setRemoteWriteBearerSecretRef, onSubmit: handleRemoteWriteBearerSecretRefSubmit, placeholder: "prometheus-remote-write:token" }) }), _jsx(ProgressSummary, {})] })), subStep === "logging-category" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "External Logging Destination" }), _jsx(Text, { color: "gray", dimColor: true, children: "Choose how you want to store decision logs (Console logging is always included)" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: LOGGING_CATEGORIES, onSelect: handleLoggingCategorySelect, indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) }) }), _jsx(ProgressSummary, {})] })), subStep === "logging-sink" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: loggingCategory === "cloud-storage"
|
|
756
1153
|
? "Select Cloud Storage"
|
|
757
1154
|
: "Select Logging Platform" }), _jsx(Text, { color: "gray", dimColor: true, children: loggingCategory === "cloud-storage"
|
|
758
1155
|
? "Store logs in cloud object storage"
|
|
759
1156
|
: "Send logs to a centralized logging platform" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: loggingCategory === "cloud-storage"
|
|
760
1157
|
? CLOUD_STORAGE_SINKS
|
|
761
1158
|
: LOGGING_PLATFORM_SINKS, onSelect: handleLoggingSinkSelect, indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) }) }), state.infrastructureMode === "existing" &&
|
|
762
|
-
loggingCategory === "cloud-storage" && (_jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: "yellow", paddingX: 1, children: _jsx(Text, { color: "yellow", children: "Note: Cloud storage requires IRSA/Workload Identity in your cluster." }) })), _jsx(ProgressSummary, {})] })), subStep === "logging-region-loading" && (_jsx(Box, { flexDirection: "column", marginY: 1, children: _jsx(Spinner, { label: "Loading available regions..." }) })), subStep === "logging-region" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsxs(Text, { bold: true, children: [loggingSink === "s3" && "Select AWS Region", loggingSink === "azure-blob" && "Select Azure Region", loggingSink === "gcs" && "Select GCP Region"] }), _jsx(Text, { color: "gray", dimColor: true, children: "Select the region where logs will be stored" }), _jsx(Box, { marginTop: 1, height: 10, flexDirection: "column", overflowY: "hidden", children: _jsx(SelectInput, { items: getLoggingRegions(), onSelect: handleLoggingRegionSelect, limit: 8, indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) }) }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" ", "Sink: ", LOGGING_SINK_INFO[loggingSink]?.name] })] })] })), subStep === "logging-bucket-loading" && (_jsx(Box, { flexDirection: "column", marginY: 1, children: _jsx(Spinner, { label: `Loading buckets in ${loggingRegion}...` }) })), subStep === "logging-bucket" && (_jsx(BucketSelector, { loggingSink: loggingSink, loggingRegion: loggingRegion, availableBuckets: availableBuckets, isRefreshing: isRefreshing, onSelect: handleLoggingBucketSelect, onRefresh: refreshBuckets, colors: colors })), subStep === "logging-datadog-config" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Datadog Configuration" }), _jsx(Text, { color: "gray", dimColor: true, children: "Configure Datadog Logs integration" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "API Key:" }), _jsx(Box, { children: _jsx(TextInput, { value: datadogApiKey, onChange: setDatadogApiKey, placeholder: "your-api-key", mask: "*" }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Datadog Site:" }), _jsx(SelectInput, { items: DATADOG_SITES, initialIndex: DATADOG_SITES.findIndex((s) => s.value === datadogSite), onSelect: (item) => setDatadogSite(item.value), indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "Press Enter after selecting site to continue" }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: datadogApiKey ? colors.accent : colors.muted, bold: !!datadogApiKey, children: datadogApiKey
|
|
1159
|
+
loggingCategory === "cloud-storage" && (_jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: "yellow", paddingX: 1, children: _jsx(Text, { color: "yellow", children: "Note: Cloud storage requires IRSA/Workload Identity in your cluster." }) })), _jsx(ProgressSummary, {})] })), subStep === "logging-region-loading" && (_jsx(Box, { flexDirection: "column", marginY: 1, children: _jsx(Spinner, { label: "Loading available regions..." }) })), subStep === "logging-region" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsxs(Text, { bold: true, children: [loggingSink === "s3" && "Select AWS Region", loggingSink === "azure-blob" && "Select Azure Region", loggingSink === "gcs" && "Select GCP Region"] }), _jsx(Text, { color: "gray", dimColor: true, children: "Select the region where logs will be stored" }), _jsx(Box, { marginTop: 1, height: 10, flexDirection: "column", overflowY: "hidden", children: _jsx(SelectInput, { items: getLoggingRegions(), onSelect: handleLoggingRegionSelect, limit: 8, indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) }) }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" ", "Sink: ", LOGGING_SINK_INFO[loggingSink]?.name] })] })] })), subStep === "logging-bucket-loading" && (_jsx(Box, { flexDirection: "column", marginY: 1, children: _jsx(Spinner, { label: `Loading buckets in ${loggingRegion}...` }) })), subStep === "logging-bucket" && (_jsx(BucketSelector, { loggingSink: loggingSink, loggingRegion: loggingRegion, availableBuckets: availableBuckets, isRefreshing: isRefreshing, onSelect: handleLoggingBucketSelect, onRefresh: refreshBuckets, colors: colors })), subStep === "logging-s3-role-arn" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Vector S3 IRSA Role ARN" }), _jsx(Text, { color: "gray", dimColor: true, children: "IAM role trusted by the Vector Kubernetes service account." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: s3RoleArn, onChange: setS3RoleArn, onSubmit: handleS3RoleArnSubmit, placeholder: "arn:aws:iam::123456789012:role/rulebricks-vector" }) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.success, children: ["\u2713 S3 bucket: ", loggingBucket] }) })] })), subStep === "logging-azure-container" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Azure Blob Container" }), _jsx(Text, { color: "gray", dimColor: true, children: "Enter the container where Rulebricks decision logs should be written." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: azureBlobContainer, onChange: setAzureBlobContainer, onSubmit: handleAzureBlobContainerSubmit, placeholder: "rulebricks-logs" }) }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: _jsxs(Text, { color: colors.success, children: ["\u2713 Storage account: ", loggingBucket] }) })] })), subStep === "logging-azure-auth" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Azure Blob Authentication" }), _jsx(Text, { color: "gray", dimColor: true, children: "Workload identity is recommended. Connection string Secret is a fallback for clusters without Azure Workload Identity." }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: AZURE_LOGGING_AUTH, onSelect: handleAzureBlobAuthSelect, indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) }) })] })), subStep === "logging-azure-client-id" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Azure Managed Identity Client ID" }), _jsx(Text, { color: "gray", dimColor: true, children: "Client ID for the identity federated to Vector's service account." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: azureBlobClientId, onChange: setAzureBlobClientId, onSubmit: handleAzureBlobClientIdSubmit, placeholder: "00000000-0000-0000-0000-000000000000" }) })] })), subStep === "logging-azure-tenant-id" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Azure Tenant ID" }), _jsx(Text, { color: "gray", dimColor: true, children: "Tenant ID used by Azure Workload Identity." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: azureBlobTenantId, onChange: setAzureBlobTenantId, onSubmit: handleAzureBlobTenantIdSubmit, placeholder: "00000000-0000-0000-0000-000000000000" }) })] })), subStep === "logging-azure-connection-string-secret" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Azure Storage Connection String Secret" }), _jsx(Text, { color: "gray", dimColor: true, children: "Enter an existing Kubernetes Secret key in the format name:key." }), _jsx(Text, { color: "gray", dimColor: true, children: "The key should contain the Azure Storage connection string." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: azureBlobConnectionStringSecretRef, onChange: setAzureBlobConnectionStringSecretRef, onSubmit: handleAzureBlobConnectionStringSecretSubmit, placeholder: "azure-blob-logs:connection-string" }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { color: colors.success, children: ["\u2713 Storage account: ", loggingBucket] }), _jsxs(Text, { color: colors.success, children: ["\u2713 Container: ", azureBlobContainer] })] })] })), subStep === "logging-gcp-service-account" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Google Service Account Email" }), _jsx(Text, { color: "gray", dimColor: true, children: "GSA bound to the Vector Kubernetes service account through GKE Workload Identity." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: gcpServiceAccountEmail, onChange: setGcpServiceAccountEmail, onSubmit: handleGcpServiceAccountSubmit, placeholder: "rulebricks-vector@project.iam.gserviceaccount.com" }) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.success, children: ["\u2713 GCS bucket: ", loggingBucket] }) })] })), subStep === "logging-datadog-config" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Datadog Configuration" }), _jsx(Text, { color: "gray", dimColor: true, children: "Configure Datadog Logs integration" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "API Key:" }), _jsx(Box, { children: _jsx(TextInput, { value: datadogApiKey, onChange: setDatadogApiKey, placeholder: "your-api-key", mask: "*" }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Datadog Site:" }), _jsx(SelectInput, { items: DATADOG_SITES, initialIndex: DATADOG_SITES.findIndex((s) => s.value === datadogSite), onSelect: (item) => setDatadogSite(item.value), indicatorComponent: () => null, itemComponent: ({ isSelected, label }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] })) })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "Press Enter after selecting site to continue" }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: datadogApiKey ? colors.accent : colors.muted, bold: !!datadogApiKey, children: datadogApiKey
|
|
763
1160
|
? "→ Press Enter to continue"
|
|
764
1161
|
: "Enter API key to continue" }) }), datadogApiKey && (_jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: "", onChange: () => { }, onSubmit: handleDatadogConfigSubmit, placeholder: "" }) }))] })), subStep === "logging-splunk-config" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Splunk HEC Configuration" }), _jsx(Text, { color: "gray", dimColor: true, children: "Configure Splunk HTTP Event Collector" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "HEC URL:" }), _jsx(Box, { children: _jsx(TextInput, { value: splunkUrl, onChange: setSplunkUrl, placeholder: "https://splunk.example.com:8088" }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "HEC Token:" }), _jsx(Box, { children: _jsx(TextInput, { value: splunkHecToken, onChange: setSplunkHecToken, onSubmit: handleSplunkConfigSubmit, placeholder: "your-hec-token", mask: "*" }) })] })] })), subStep === "logging-elasticsearch-config" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Elasticsearch Configuration" }), _jsx(Text, { color: "gray", dimColor: true, children: "Configure Elasticsearch logging destination" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Elasticsearch URL:" }), _jsx(Box, { children: _jsx(TextInput, { value: elasticsearchUrl, onChange: setElasticsearchUrl, placeholder: "https://elasticsearch.example.com:9200" }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Username (optional):" }), _jsx(Box, { children: _jsx(TextInput, { value: elasticsearchUser, onChange: setElasticsearchUser, placeholder: "elastic" }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Password (optional):" }), _jsx(Box, { children: _jsx(TextInput, { value: elasticsearchPass, onChange: setElasticsearchPass, placeholder: "", mask: "*" }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Index name:" }), _jsx(Box, { children: _jsx(TextInput, { value: elasticsearchIndex, onChange: setElasticsearchIndex, onSubmit: handleElasticsearchConfigSubmit, placeholder: "rulebricks-logs" }) })] })] })), subStep === "logging-loki-config" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Grafana Loki Configuration" }), _jsx(Text, { color: "gray", dimColor: true, children: "Configure Loki logging destination" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Loki URL:" }), _jsx(Text, { color: "gray", dimColor: true, children: "Include /loki/api/v1/push endpoint" }), _jsx(Box, { children: _jsx(TextInput, { value: lokiUrl, onChange: setLokiUrl, onSubmit: handleLokiConfigSubmit, placeholder: "https://loki.example.com/loki/api/v1/push" }) })] })] })), subStep === "logging-newrelic-config" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "New Relic Configuration" }), _jsx(Text, { color: "gray", dimColor: true, children: "Configure New Relic Logs integration" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "License Key:" }), _jsx(Box, { children: _jsx(TextInput, { value: newrelicLicenseKey, onChange: setNewrelicLicenseKey, placeholder: "your-license-key", mask: "*" }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Account ID:" }), _jsx(Box, { children: _jsx(TextInput, { value: newrelicAccountId, onChange: setNewrelicAccountId, onSubmit: handleNewrelicConfigSubmit, placeholder: "1234567" }) })] })] })), subStep === "logging-axiom-config" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Axiom Configuration" }), _jsx(Text, { color: "gray", dimColor: true, children: "Configure Axiom logging destination" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "API Token:" }), _jsx(Box, { children: _jsx(TextInput, { value: axiomApiToken, onChange: setAxiomApiToken, placeholder: "xaat-...", mask: "*" }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Dataset:" }), _jsx(Box, { children: _jsx(TextInput, { value: axiomDataset, onChange: setAxiomDataset, onSubmit: handleAxiomConfigSubmit, placeholder: "rulebricks" }) })] })] })), subStep === "email-subject-invite" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Custom Email Templates" }), _jsx(Text, { color: "gray", dimColor: true, children: "Customize Supabase auth email subjects and templates." }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "First, let's customize the subject lines. Press Enter to use defaults." }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Invite Email Subject:" }), _jsxs(Text, { color: "gray", dimColor: true, children: ["Default: \"", DEFAULT_EMAIL_SUBJECTS.invite, "\""] }), _jsx(Box, { children: _jsx(TextInput, { value: emailSubjectInvite, onChange: setEmailSubjectInvite, onSubmit: handleEmailSubjectInviteSubmit, placeholder: DEFAULT_EMAIL_SUBJECTS.invite }) })] })] })), subStep === "email-subject-confirm" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Custom Email Templates - Subject Lines" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Confirmation Email Subject:" }), _jsxs(Text, { color: "gray", dimColor: true, children: ["Default: \"", DEFAULT_EMAIL_SUBJECTS.confirmation, "\""] }), _jsx(Box, { children: _jsx(TextInput, { value: emailSubjectConfirm, onChange: setEmailSubjectConfirm, onSubmit: handleEmailSubjectConfirmSubmit, placeholder: DEFAULT_EMAIL_SUBJECTS.confirmation }) })] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Invite: ", emailSubjectInvite] })] })] })), subStep === "email-subject-recovery" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Custom Email Templates - Subject Lines" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Password Recovery Email Subject:" }), _jsxs(Text, { color: "gray", dimColor: true, children: ["Default: \"", DEFAULT_EMAIL_SUBJECTS.recovery, "\""] }), _jsx(Box, { children: _jsx(TextInput, { value: emailSubjectRecovery, onChange: setEmailSubjectRecovery, onSubmit: handleEmailSubjectRecoverySubmit, placeholder: DEFAULT_EMAIL_SUBJECTS.recovery }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Invite: ", emailSubjectInvite] })] }), _jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Confirmation: ", emailSubjectConfirm] })] })] })] })), subStep === "email-subject-change" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Custom Email Templates - Subject Lines" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Email Change Subject:" }), _jsxs(Text, { color: "gray", dimColor: true, children: ["Default: \"", DEFAULT_EMAIL_SUBJECTS.emailChange, "\""] }), _jsx(Box, { children: _jsx(TextInput, { value: emailSubjectChange, onChange: setEmailSubjectChange, onSubmit: handleEmailSubjectChangeSubmit, placeholder: DEFAULT_EMAIL_SUBJECTS.emailChange }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Invite: ", emailSubjectInvite] })] }), _jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Confirmation: ", emailSubjectConfirm] })] }), _jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Recovery: ", emailSubjectRecovery] })] })] })] })), subStep === "email-template-invite" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Custom Email Templates - Template URLs" }), _jsx(Text, { color: "gray", dimColor: true, children: "Provide URLs to your custom HTML email templates." }), _jsx(Text, { color: "gray", dimColor: true, children: "Templates must be publicly accessible (S3, GCS, or any HTTPS URL)." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Invite Template URL:" }), _jsx(Box, { children: _jsx(TextInput, { value: emailTemplateInvite, onChange: setEmailTemplateInvite, onSubmit: handleEmailTemplateInviteSubmit, placeholder: "https://bucket.s3.amazonaws.com/templates/invite.html" }) })] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsx(Text, { color: "gray", children: " All subject lines configured" })] })] })), subStep === "email-template-confirm" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Custom Email Templates - Template URLs" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Confirmation Template URL:" }), _jsx(Box, { children: _jsx(TextInput, { value: emailTemplateConfirm, onChange: setEmailTemplateConfirm, onSubmit: handleEmailTemplateConfirmSubmit, placeholder: "https://bucket.s3.amazonaws.com/templates/verify.html" }) })] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Invite: ", emailTemplateInvite] })] })] })), subStep === "email-template-recovery" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Custom Email Templates - Template URLs" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Recovery Template URL:" }), _jsx(Box, { children: _jsx(TextInput, { value: emailTemplateRecovery, onChange: setEmailTemplateRecovery, onSubmit: handleEmailTemplateRecoverySubmit, placeholder: "https://bucket.s3.amazonaws.com/templates/password_change.html" }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Invite: ", emailTemplateInvite] })] }), _jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Confirmation: ", emailTemplateConfirm] })] })] })] })), subStep === "email-template-change" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Custom Email Templates - Template URLs" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Email Change Template URL:" }), _jsx(Box, { children: _jsx(TextInput, { value: emailTemplateChange, onChange: setEmailTemplateChange, onSubmit: handleEmailTemplateChangeSubmit, placeholder: "https://bucket.s3.amazonaws.com/templates/email_change.html" }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Invite: ", emailTemplateInvite] })] }), _jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Confirmation: ", emailTemplateConfirm] })] }), _jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" Recovery: ", emailTemplateRecovery] })] })] })] })), error && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["\u2717 ", error] }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "Esc to go back \u2022 Enter to continue" }) })] }));
|
|
765
1162
|
}
|
|
@@ -43,7 +43,12 @@ export function ReviewStep({ onComplete, onBack }) {
|
|
|
43
43
|
dispatch({ type: 'SET_NAME', name });
|
|
44
44
|
setEditingName(false);
|
|
45
45
|
};
|
|
46
|
-
const tierConfig = state.tier ? TIER_CONFIGS[state.tier] : null;
|
|
46
|
+
const tierConfig = state.infrastructureMode !== 'existing' && state.tier ? TIER_CONFIGS[state.tier] : null;
|
|
47
|
+
const tierLabel = state.infrastructureMode === 'existing'
|
|
48
|
+
? 'Inferred from cluster'
|
|
49
|
+
: state.tier
|
|
50
|
+
? `${state.tier.charAt(0).toUpperCase()}${state.tier.slice(1)}`
|
|
51
|
+
: 'Not selected';
|
|
47
52
|
const externalDnsEnabled = state.dnsAutoManage && isSupportedDnsProvider(state.dnsProvider);
|
|
48
53
|
if (editingName) {
|
|
49
54
|
return (_jsx(BorderBox, { title: "Deployment Name", children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { children: "Enter a name for this deployment:" }), _jsx(Text, { color: "gray", dimColor: true, children: "Lowercase letters, numbers, and hyphens only" }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: name, onChange: setName, onSubmit: handleNameSubmit, placeholder: "my-deployment" }) }), error && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["\u2717 ", error] }) }))] }) }));
|
|
@@ -52,5 +57,5 @@ export function ReviewStep({ onComplete, onBack }) {
|
|
|
52
57
|
const ConfigRow = ({ label, value, valueColor }) => (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { color: colors.muted, children: label }) }), _jsx(Text, { color: valueColor || colors.accent, children: value })] }));
|
|
53
58
|
// Helper to render a section header
|
|
54
59
|
const SectionHeader = ({ title }) => (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { bold: true, color: colors.accent, children: ["\u2500\u2500 ", title, " \u2500\u2500"] }) }));
|
|
55
|
-
return (_jsxs(BorderBox, { title: "Review Configuration", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(SectionHeader, { title: "Deployment" }), _jsx(ConfigRow, { label: "Name", value: state.name }), state.appVersion && (_jsx(ConfigRow, { label: "App Version", value: state.appVersion })), _jsx(SectionHeader, { title: "Infrastructure" }), _jsx(ConfigRow, { label: "Mode", value: state.infrastructureMode === 'provision' ? 'Provision new cluster' : 'Use existing cluster' }), state.provider && (_jsx(ConfigRow, { label: "Provider", value: state.provider.toUpperCase() })), state.region && (_jsx(ConfigRow, { label: "Region", value: state.region })), _jsx(SectionHeader, { title: "Domain & DNS" }), _jsx(ConfigRow, { label: "Domain", value: state.domain }), _jsx(ConfigRow, { label: "Admin Email", value: state.adminEmail }), _jsx(ConfigRow, { label: "TLS Email", value: state.tlsEmail }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { color: colors.muted, children: "DNS" }) }), _jsx(Text, { color: colors.accent, children: DNS_PROVIDER_NAMES[state.dnsProvider] }), externalDnsEnabled && _jsx(Text, { color: colors.success, children: " (auto)" })] }), _jsx(SectionHeader, { title: "SMTP" }), _jsx(ConfigRow, { label: "Host", value: `${state.smtpHost}:${state.smtpPort}` }), _jsx(ConfigRow, { label: "From", value: `${state.smtpFromName} <${state.smtpFrom}>` }), _jsx(SectionHeader, { title: "Database" }), _jsx(ConfigRow, { label: "Type", value: state.databaseType === 'supabase-cloud' ? 'Supabase Cloud' : 'Self-hosted' }), _jsx(SectionHeader, { title: "Performance" }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { color: colors.muted, children: "Tier" }) }),
|
|
60
|
+
return (_jsxs(BorderBox, { title: "Review Configuration", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(SectionHeader, { title: "Deployment" }), _jsx(ConfigRow, { label: "Name", value: state.name }), state.appVersion && (_jsx(ConfigRow, { label: "App Version", value: state.appVersion })), _jsx(SectionHeader, { title: "Infrastructure" }), _jsx(ConfigRow, { label: "Mode", value: state.infrastructureMode === 'provision' ? 'Provision new cluster' : 'Use existing cluster' }), state.provider && (_jsx(ConfigRow, { label: "Provider", value: state.provider.toUpperCase() })), state.region && (_jsx(ConfigRow, { label: "Region", value: state.region })), _jsx(SectionHeader, { title: "Domain & DNS" }), _jsx(ConfigRow, { label: "Domain", value: state.domain }), _jsx(ConfigRow, { label: "Admin Email", value: state.adminEmail }), _jsx(ConfigRow, { label: "TLS Email", value: state.tlsEmail }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { color: colors.muted, children: "DNS" }) }), _jsx(Text, { color: colors.accent, children: DNS_PROVIDER_NAMES[state.dnsProvider] }), externalDnsEnabled && _jsx(Text, { color: colors.success, children: " (auto)" })] }), _jsx(SectionHeader, { title: "SMTP" }), _jsx(ConfigRow, { label: "Host", value: `${state.smtpHost}:${state.smtpPort}` }), _jsx(ConfigRow, { label: "From", value: `${state.smtpFromName} <${state.smtpFrom}>` }), _jsx(SectionHeader, { title: "Database" }), _jsx(ConfigRow, { label: "Type", value: state.databaseType === 'supabase-cloud' ? 'Supabase Cloud' : 'Self-hosted' }), _jsx(SectionHeader, { title: "Performance" }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { color: colors.muted, children: "Tier" }) }), _jsx(Text, { color: colors.accent, bold: true, children: tierLabel }), tierConfig && _jsxs(Text, { color: colors.muted, children: [" (", tierConfig.throughput, ")"] }), state.infrastructureMode === 'existing' && (_jsx(Text, { color: colors.muted, children: " (used for app sizing)" }))] }), _jsx(SectionHeader, { title: "Features" }), _jsxs(Box, { children: [_jsxs(Text, { color: state.aiEnabled ? colors.success : colors.muted, children: [state.aiEnabled ? '✓' : '○', " AI"] }), _jsx(Text, { children: " " }), _jsxs(Text, { color: state.ssoEnabled ? colors.success : colors.muted, children: [state.ssoEnabled ? '✓' : '○', " SSO"] }), _jsx(Text, { children: " " }), _jsxs(Text, { color: state.monitoringEnabled ? colors.success : colors.muted, children: [state.monitoringEnabled ? '✓' : '○', " Monitoring"] }), _jsx(Text, { children: " " }), _jsxs(Text, { color: state.loggingSink !== 'console' ? colors.success : colors.muted, children: [state.loggingSink !== 'console' ? '✓' : '○', " Logging"] })] }), _jsx(SectionHeader, { title: "License" }), _jsx(ConfigRow, { label: "Key", value: `${state.licenseKey?.substring(0, 12)}...` })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.success, bold: true, children: "Press Enter to save this configuration" }), _jsx(Text, { color: colors.muted, dimColor: true, children: "e to edit name \u2022 Esc to go back" })] })] }));
|
|
56
61
|
}
|