@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.
@@ -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 YES_NO_OPTIONS = [
58
- { label: "No, just collect metrics locally", value: false },
59
- { label: "Yes, send metrics to external system", value: true },
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-url":
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
- if (item.value) {
366
- setSubStep("monitoring-remote-write-url");
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" }) }), _jsxs(Text, { color: colors.accent, bold: true, children: [state.tier?.charAt(0).toUpperCase(), state.tier?.slice(1)] }), tierConfig && _jsxs(Text, { color: colors.muted, children: [" (", tierConfig.throughput, ")"] })] }), _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" })] })] }));
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
  }