@rulebricks/cli 2.1.7 → 2.3.2
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 +51 -16
- package/cluster-setup/aws/README.md +96 -47
- package/cluster-setup/aws/check-aws-access.sh +216 -52
- package/cluster-setup/aws/parameters.json +13 -0
- package/cluster-setup/aws/rulebricks-cluster.cfn.yaml +355 -0
- package/cluster-setup/azure/README.md +103 -55
- package/cluster-setup/azure/check-aks-prereqs.sh +236 -56
- package/cluster-setup/azure/parameters.json +30 -0
- package/cluster-setup/azure/rulebricks-cluster.bicep +546 -0
- package/cluster-setup/gcp/README.md +51 -34
- package/cluster-setup/gcp/check-gke-prereqs.sh +222 -60
- package/dist/commands/backup.d.ts +5 -0
- package/dist/commands/backup.js +104 -0
- package/dist/commands/deploy.d.ts +3 -1
- package/dist/commands/deploy.js +226 -326
- package/dist/commands/destroy.d.ts +1 -1
- package/dist/commands/destroy.js +73 -123
- package/dist/commands/init.d.ts +5 -1
- package/dist/commands/init.js +78 -54
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +74 -0
- package/dist/commands/open.d.ts +1 -1
- package/dist/commands/open.js +4 -12
- package/dist/commands/redeploy.d.ts +6 -0
- package/dist/commands/redeploy.js +310 -0
- package/dist/commands/restore.d.ts +5 -0
- package/dist/commands/restore.js +338 -0
- package/dist/commands/status.js +62 -49
- package/dist/commands/upgrade.js +74 -51
- package/dist/components/DNSWaitScreen.d.ts +5 -1
- package/dist/components/DNSWaitScreen.js +47 -41
- package/dist/components/Wizard/WizardContext.d.ts +157 -36
- package/dist/components/Wizard/WizardContext.js +872 -160
- package/dist/components/Wizard/steps/CloudProviderStep.js +192 -107
- package/dist/components/Wizard/steps/DomainStep.js +5 -24
- package/dist/components/Wizard/steps/ExternalServicesStep.d.ts +6 -0
- package/dist/components/Wizard/steps/ExternalServicesStep.js +645 -0
- package/dist/components/Wizard/steps/FeatureConfigStep.d.ts +2 -1
- package/dist/components/Wizard/steps/FeatureConfigStep.js +739 -425
- package/dist/components/Wizard/steps/FeaturesStep.js +31 -35
- package/dist/components/Wizard/steps/ObservabilityStep.d.ts +6 -0
- package/dist/components/Wizard/steps/ObservabilityStep.js +137 -0
- package/dist/components/Wizard/steps/ReviewStep.d.ts +2 -1
- package/dist/components/Wizard/steps/ReviewStep.js +56 -12
- package/dist/components/Wizard/steps/StorageStep.d.ts +9 -0
- package/dist/components/Wizard/steps/StorageStep.js +592 -0
- package/dist/components/Wizard/steps/SupabaseCredentialsStep.js +20 -21
- package/dist/components/Wizard/steps/VersionStep.js +45 -23
- package/dist/components/Wizard/steps/index.d.ts +3 -3
- package/dist/components/Wizard/steps/index.js +3 -3
- package/dist/components/common/CommandApproval.d.ts +12 -0
- package/dist/components/common/CommandApproval.js +91 -0
- package/dist/components/common/DeploymentPicker.d.ts +14 -0
- package/dist/components/common/DeploymentPicker.js +16 -0
- package/dist/components/common/index.d.ts +2 -0
- package/dist/components/common/index.js +2 -0
- package/dist/index.js +94 -62
- package/dist/lib/cloudCli.d.ts +134 -63
- package/dist/lib/cloudCli.js +512 -220
- package/dist/lib/clusterSetupDefaults.d.ts +30 -0
- package/dist/lib/clusterSetupDefaults.js +64 -0
- package/dist/lib/commandApproval.d.ts +26 -0
- package/dist/lib/commandApproval.js +114 -0
- package/dist/lib/config.d.ts +12 -10
- package/dist/lib/config.js +91 -33
- package/dist/lib/configFixtures.d.ts +5 -0
- package/dist/lib/configFixtures.js +513 -0
- package/dist/lib/deploymentHealth.d.ts +32 -0
- package/dist/lib/deploymentHealth.js +157 -0
- package/dist/lib/dns.d.ts +1 -1
- package/dist/lib/dns.js +19 -1
- package/dist/lib/dns.test.d.ts +1 -0
- package/dist/lib/dns.test.js +27 -0
- package/dist/lib/dockerHub.d.ts +12 -1
- package/dist/lib/dockerHub.js +18 -8
- package/dist/lib/helm.d.ts +4 -0
- package/dist/lib/helm.js +16 -0
- package/dist/lib/helmValues.d.ts +25 -0
- package/dist/lib/helmValues.js +1841 -289
- package/dist/lib/helmValues.test.d.ts +1 -0
- package/dist/lib/helmValues.test.js +1012 -0
- package/dist/lib/htpasswd.d.ts +1 -0
- package/dist/lib/htpasswd.js +15 -0
- package/dist/lib/kubernetes.d.ts +124 -17
- package/dist/lib/kubernetes.js +576 -145
- package/dist/lib/secrets.d.ts +23 -0
- package/dist/lib/secrets.js +158 -0
- package/dist/lib/validateValues.d.ts +31 -0
- package/dist/lib/validateValues.js +253 -0
- package/dist/lib/versions.d.ts +82 -11
- package/dist/lib/versions.js +131 -31
- package/dist/lib/versions.test.d.ts +1 -0
- package/dist/lib/versions.test.js +81 -0
- package/dist/lib/wizardSteps.d.ts +14 -0
- package/dist/lib/wizardSteps.js +23 -0
- package/dist/lib/workloadIdentity.d.ts +26 -0
- package/dist/lib/workloadIdentity.js +323 -0
- package/dist/lib/workloadIdentity.test.d.ts +1 -0
- package/dist/lib/workloadIdentity.test.js +57 -0
- package/dist/types/index.d.ts +1860 -164
- package/dist/types/index.js +518 -295
- package/package.json +9 -4
- package/schema/values.schema.json +1934 -0
- package/cluster-setup/aws/cluster.yaml +0 -33
- package/cluster-setup/azure/main.bicep +0 -282
- package/cluster-setup/azure/main.parameters.json +0 -21
- package/dist/components/Wizard/steps/CredentialsStep.d.ts +0 -6
- package/dist/components/Wizard/steps/CredentialsStep.js +0 -22
- package/dist/components/Wizard/steps/DeploymentModeStep.d.ts +0 -5
- package/dist/components/Wizard/steps/DeploymentModeStep.js +0 -26
- package/dist/components/Wizard/steps/TierStep.d.ts +0 -6
- package/dist/components/Wizard/steps/TierStep.js +0 -29
- package/dist/lib/terraform.d.ts +0 -66
- package/dist/lib/terraform.js +0 -754
- package/terraform/aws/main.tf +0 -355
- package/terraform/azure/main.tf +0 -371
- package/terraform/gcp/main.tf +0 -407
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useEffect } from "react";
|
|
3
|
-
import { Box, Text
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
4
|
import SelectInput from "ink-select-input";
|
|
5
5
|
import TextInput from "ink-text-input";
|
|
6
6
|
import { useWizard } from "../WizardContext.js";
|
|
7
|
-
import { BorderBox, useTheme } from "../../common/index.js";
|
|
7
|
+
import { BorderBox, useGatedInput, useTheme } from "../../common/index.js";
|
|
8
8
|
import { Spinner } from "../../common/Spinner.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { CLOUD_REGIONS, DEFAULT_EMAIL_SUBJECTS, } from "../../../types/index.js";
|
|
10
|
+
import { listRegions, listAzureManagedIdentities, getAzureTenantId, listAzurePrometheusTargets, listAwsPrometheusWorkspaces, } from "../../../lib/cloudCli.js";
|
|
11
|
+
import { findClusterSetupDefaultIndex } from "../../../lib/clusterSetupDefaults.js";
|
|
12
|
+
import { generateHtpasswdLine } from "../../../lib/htpasswd.js";
|
|
13
|
+
import { generateSecureSecret } from "../../../lib/validation.js";
|
|
14
|
+
// Sentinel value used in select lists to drop into manual text entry.
|
|
15
|
+
const MANUAL = "__manual__";
|
|
16
|
+
const REFRESH = "__refresh__";
|
|
11
17
|
const SSO_PROVIDERS = [
|
|
12
18
|
{ label: "Microsoft Azure AD", value: "azure" },
|
|
13
19
|
{ label: "Google Workspace", value: "google" },
|
|
@@ -16,18 +22,9 @@ const SSO_PROVIDERS = [
|
|
|
16
22
|
{ label: "Ory", value: "ory" },
|
|
17
23
|
{ label: "Other OIDC Provider", value: "other" },
|
|
18
24
|
];
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
label: "Logging Platform (Datadog, Splunk, etc.)",
|
|
23
|
-
value: "logging-platform",
|
|
24
|
-
},
|
|
25
|
-
];
|
|
26
|
-
const CLOUD_STORAGE_SINKS = [
|
|
27
|
-
{ label: "AWS S3", value: "s3" },
|
|
28
|
-
{ label: "Azure Blob Storage", value: "azure-blob" },
|
|
29
|
-
{ label: "Google Cloud Storage", value: "gcs" },
|
|
30
|
-
];
|
|
25
|
+
// External logging forwards decision logs to a centralized logging platform.
|
|
26
|
+
// Cloud object storage (S3/Blob/GCS) for decision logs is configured in the
|
|
27
|
+
// dedicated Object Storage step, so it is intentionally not offered here.
|
|
31
28
|
const LOGGING_PLATFORM_SINKS = [
|
|
32
29
|
{ label: "Datadog", value: "datadog" },
|
|
33
30
|
{ label: "Splunk (HEC)", value: "splunk" },
|
|
@@ -44,62 +41,113 @@ const DATADOG_SITES = [
|
|
|
44
41
|
{ label: "EU1 (datadoghq.eu)", value: "datadoghq.eu" },
|
|
45
42
|
{ label: "AP1 (ap1.datadoghq.com)", value: "ap1.datadoghq.com" },
|
|
46
43
|
];
|
|
47
|
-
|
|
48
|
-
useInput((input) => {
|
|
49
|
-
if (input.toLowerCase() === "r") {
|
|
50
|
-
onRefresh();
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
const bucketItems = availableBuckets.map((b) => ({ label: b, value: b }));
|
|
54
|
-
const hasBuckets = availableBuckets.length > 0;
|
|
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
|
-
}
|
|
57
|
-
const MONITORING_DESTINATIONS = [
|
|
58
|
-
{ label: "Local Grafana (bundled)", value: "local-grafana" },
|
|
44
|
+
const REMOTE_WRITE_DESTINATIONS = [
|
|
59
45
|
{ label: "AWS Managed Prometheus (AMP)", value: "aws-amp" },
|
|
60
46
|
{ label: "Azure Monitor managed Prometheus", value: "azure-monitor" },
|
|
61
47
|
{ label: "Grafana Cloud", value: "grafana-cloud" },
|
|
62
48
|
{ label: "Generic Prometheus remote_write", value: "generic" },
|
|
63
49
|
];
|
|
64
|
-
const REMOTE_WRITE_DESTINATIONS = MONITORING_DESTINATIONS.filter((destination) => destination.value !== "local-grafana");
|
|
65
50
|
const AZURE_REMOTE_WRITE_AUTH = [
|
|
66
51
|
{ label: "Workload identity", value: "workload-identity" },
|
|
67
52
|
{ label: "Managed identity", value: "managed-identity" },
|
|
68
53
|
{ label: "OAuth client secret", value: "oauth" },
|
|
69
54
|
];
|
|
70
|
-
const AZURE_LOGGING_AUTH = [
|
|
71
|
-
{ label: "Workload identity", value: "workload-identity" },
|
|
72
|
-
{ label: "Connection string Secret (fallback)", value: "secret" },
|
|
73
|
-
];
|
|
74
55
|
const GENERIC_REMOTE_WRITE_AUTH = [
|
|
75
56
|
{ label: "No additional auth", value: "none" },
|
|
76
57
|
{ label: "Basic auth from Kubernetes Secret", value: "basic" },
|
|
77
58
|
{ label: "Bearer token from Kubernetes Secret", value: "bearer" },
|
|
78
59
|
];
|
|
79
|
-
export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
60
|
+
export function FeatureConfigStep({ onComplete, onBack, entryDirection, }) {
|
|
80
61
|
const { state, dispatch } = useWizard();
|
|
81
62
|
const { colors } = useTheme();
|
|
82
|
-
// Determine what needs to be configured
|
|
83
|
-
|
|
63
|
+
// Determine what needs to be configured. Metrics export (Prometheus
|
|
64
|
+
// remote_write) is opt-in via the Features step; in-cluster Prometheus is
|
|
65
|
+
// always installed and needs no configuration.
|
|
66
|
+
// Show the OpenAI key step whenever AI is enabled, even if a key is already
|
|
67
|
+
// in wizard state (e.g. pre-filled from the saved profile or an existing
|
|
68
|
+
// config on redeploy). The input is seeded with that value so the user can
|
|
69
|
+
// confirm or change it — previously a pre-filled key silently skipped this
|
|
70
|
+
// step entirely, which looked like the wizard never collected the key.
|
|
71
|
+
const needsAI = state.aiEnabled;
|
|
84
72
|
const needsSSO = state.ssoEnabled;
|
|
85
|
-
const needsMonitoring = state.
|
|
73
|
+
const needsMonitoring = !state.clickStackEnabled && state.metricsExportEnabled;
|
|
86
74
|
const needsLogging = state.loggingSink !== "console";
|
|
75
|
+
const needsTracing = !state.clickStackEnabled && state.tracingEnabled;
|
|
76
|
+
const needsAppLogs = !state.clickStackEnabled && state.appLogsEnabled;
|
|
77
|
+
const needsValkeyAdmin = state.valkeyAdminEnabled;
|
|
87
78
|
const needsCustomEmails = state.customEmailsEnabled;
|
|
88
|
-
// Configuration order:
|
|
79
|
+
// Configuration order:
|
|
80
|
+
// AI -> SSO -> Monitoring -> Logging -> Tracing -> AppLogs -> Valkey Admin -> Custom Emails
|
|
89
81
|
const getInitialStep = () => {
|
|
90
82
|
if (needsAI)
|
|
91
83
|
return "openai-key";
|
|
92
84
|
if (needsSSO)
|
|
93
85
|
return "sso-provider";
|
|
94
86
|
if (needsMonitoring)
|
|
95
|
-
return "monitoring-remote-write-
|
|
87
|
+
return "monitoring-remote-write-destination";
|
|
96
88
|
if (needsLogging)
|
|
97
|
-
return "logging-
|
|
89
|
+
return "logging-sink";
|
|
90
|
+
if (needsTracing)
|
|
91
|
+
return "tracing-destination";
|
|
92
|
+
if (needsAppLogs)
|
|
93
|
+
return "applogs-endpoint";
|
|
94
|
+
if (needsValkeyAdmin)
|
|
95
|
+
return "valkey-admin-username";
|
|
98
96
|
if (needsCustomEmails)
|
|
99
97
|
return "email-subject-invite";
|
|
100
98
|
return "done";
|
|
101
99
|
};
|
|
102
|
-
|
|
100
|
+
// Terminal sub-step of the last enabled section. Used when navigating *back*
|
|
101
|
+
// into this step so the user resumes at the end instead of the very start.
|
|
102
|
+
const tracingFinalStep = () => {
|
|
103
|
+
const destination = state.tracingDestination || "elastic";
|
|
104
|
+
if (destination === "otlp") {
|
|
105
|
+
return state.tracingOtlpAuthMode && state.tracingOtlpAuthMode !== "none"
|
|
106
|
+
? "tracing-otlp-cred"
|
|
107
|
+
: "tracing-otlp-auth";
|
|
108
|
+
}
|
|
109
|
+
if (destination === "azure-monitor")
|
|
110
|
+
return "tracing-azure-connection";
|
|
111
|
+
return "tracing-token";
|
|
112
|
+
};
|
|
113
|
+
const loggingFinalStep = () => {
|
|
114
|
+
switch (state.loggingSink) {
|
|
115
|
+
case "datadog":
|
|
116
|
+
return "logging-datadog-config";
|
|
117
|
+
case "splunk":
|
|
118
|
+
return "logging-splunk-config";
|
|
119
|
+
case "elasticsearch":
|
|
120
|
+
return "logging-elasticsearch-config";
|
|
121
|
+
case "loki":
|
|
122
|
+
return "logging-loki-config";
|
|
123
|
+
case "newrelic":
|
|
124
|
+
return "logging-newrelic-config";
|
|
125
|
+
case "axiom":
|
|
126
|
+
return "logging-axiom-config";
|
|
127
|
+
default:
|
|
128
|
+
return "logging-sink";
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const getFinalStep = () => {
|
|
132
|
+
if (needsCustomEmails)
|
|
133
|
+
return "email-template-change";
|
|
134
|
+
if (needsValkeyAdmin)
|
|
135
|
+
return "valkey-admin-allowed-ips";
|
|
136
|
+
if (needsAppLogs)
|
|
137
|
+
return "applogs-index";
|
|
138
|
+
if (needsTracing)
|
|
139
|
+
return tracingFinalStep();
|
|
140
|
+
if (needsLogging)
|
|
141
|
+
return loggingFinalStep();
|
|
142
|
+
if (needsMonitoring)
|
|
143
|
+
return "monitoring-remote-write-destination";
|
|
144
|
+
if (needsSSO)
|
|
145
|
+
return "sso-client-secret";
|
|
146
|
+
if (needsAI)
|
|
147
|
+
return "openai-key";
|
|
148
|
+
return "done";
|
|
149
|
+
};
|
|
150
|
+
const [subStep, setSubStep] = useState(entryDirection === "back" ? getFinalStep : getInitialStep);
|
|
103
151
|
const [openaiKey, setOpenaiKey] = useState(state.openaiApiKey || "");
|
|
104
152
|
const [ssoProvider, setSsoProvider] = useState(state.ssoProvider);
|
|
105
153
|
const [ssoUrl, setSsoUrl] = useState(state.ssoUrl || "");
|
|
@@ -109,7 +157,6 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
109
157
|
const [remoteWriteDestination, setRemoteWriteDestination] = useState(state.prometheusRemoteWriteDestination);
|
|
110
158
|
const [remoteWriteAuthType, setRemoteWriteAuthType] = useState(state.prometheusRemoteWriteAuthType);
|
|
111
159
|
const [remoteWriteAwsRegion, setRemoteWriteAwsRegion] = useState(state.prometheusRemoteWriteAwsRegion || state.region || "us-east-1");
|
|
112
|
-
const [remoteWriteAwsRoleArn, setRemoteWriteAwsRoleArn] = useState(state.prometheusRemoteWriteAwsRoleArn || "");
|
|
113
160
|
const [remoteWriteAzureCloud] = useState(state.prometheusRemoteWriteAzureCloud || "AzurePublic");
|
|
114
161
|
const [remoteWriteClientId, setRemoteWriteClientId] = useState(state.prometheusRemoteWriteClientId || "");
|
|
115
162
|
const [remoteWriteTenantId, setRemoteWriteTenantId] = useState(state.prometheusRemoteWriteTenantId || "");
|
|
@@ -118,16 +165,6 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
118
165
|
const [remoteWritePasswordSecretRef, setRemoteWritePasswordSecretRef] = useState(state.prometheusRemoteWritePasswordSecretRef || "");
|
|
119
166
|
const [remoteWriteBearerSecretRef, setRemoteWriteBearerSecretRef] = useState(state.prometheusRemoteWriteBearerTokenSecretRef || "");
|
|
120
167
|
const [loggingSink, setLoggingSink] = useState(state.loggingSink);
|
|
121
|
-
const [loggingBucket, setLoggingBucket] = useState(state.loggingBucket || "");
|
|
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 || "");
|
|
130
|
-
const [loggingCategory, setLoggingCategory] = useState(null);
|
|
131
168
|
const [error, setError] = useState(null);
|
|
132
169
|
// Logging platform config
|
|
133
170
|
const [datadogApiKey, setDatadogApiKey] = useState("");
|
|
@@ -143,10 +180,46 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
143
180
|
const [newrelicAccountId, setNewrelicAccountId] = useState("");
|
|
144
181
|
const [axiomApiToken, setAxiomApiToken] = useState("");
|
|
145
182
|
const [axiomDataset, setAxiomDataset] = useState("rulebricks");
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const [
|
|
183
|
+
// Distributed tracing. The wizard supports three destinations (Elastic APM,
|
|
184
|
+
// generic OTLP/HTTP, Azure Monitor). For Elastic it collects endpoint + secret
|
|
185
|
+
// token (api-key auth remains available via config file).
|
|
186
|
+
const [tracingDestination, setTracingDestination] = useState(state.tracingDestination || "elastic");
|
|
187
|
+
const [tracingEndpoint, setTracingEndpoint] = useState(state.tracingElasticEndpoint || "");
|
|
188
|
+
const [tracingToken, setTracingToken] = useState(state.tracingElasticSecretToken || "");
|
|
189
|
+
const [tracingOtlpEndpoint, setTracingOtlpEndpoint] = useState(state.tracingOtlpEndpoint || "");
|
|
190
|
+
const [tracingOtlpAuthMode, setTracingOtlpAuthMode] = useState(state.tracingOtlpAuthMode === "bearer" ||
|
|
191
|
+
state.tracingOtlpAuthMode === "api-key"
|
|
192
|
+
? state.tracingOtlpAuthMode
|
|
193
|
+
: "none");
|
|
194
|
+
const [tracingOtlpToken, setTracingOtlpToken] = useState(state.tracingOtlpToken || "");
|
|
195
|
+
const [tracingAzureConnectionString, setTracingAzureConnectionString] = useState(state.tracingAzureConnectionString || "");
|
|
196
|
+
// Application log shipping (BYO Elasticsearch via Vector agent). Basic auth.
|
|
197
|
+
const [appLogsEndpoint, setAppLogsEndpoint] = useState(state.appLogsElasticEndpoint || "");
|
|
198
|
+
const [appLogsUser, setAppLogsUser] = useState(state.appLogsElasticUsername || "");
|
|
199
|
+
const [appLogsPass, setAppLogsPass] = useState(state.appLogsElasticPassword || "");
|
|
200
|
+
const [appLogsIndex, setAppLogsIndex] = useState(state.appLogsElasticIndex || "rulebricks-app-logs");
|
|
201
|
+
const [defaultValkeyAdminPassword] = useState(() => generateSecureSecret(16));
|
|
202
|
+
const [valkeyAdminUsername, setValkeyAdminUsername] = useState(() => {
|
|
203
|
+
const existingUser = state.valkeyAdminBasicAuthUsers[0];
|
|
204
|
+
return existingUser?.split(":")[0] || "admin";
|
|
205
|
+
});
|
|
206
|
+
const [valkeyAdminPassword, setValkeyAdminPassword] = useState("");
|
|
207
|
+
const [valkeyAdminAllowedIPs, setValkeyAdminAllowedIPs] = useState(state.valkeyAdminAllowedIPs.join(", "));
|
|
208
|
+
// Dynamic resource lists for remote-write identity selection.
|
|
209
|
+
const [rwRegions, setRwRegions] = useState([]);
|
|
210
|
+
const [rwIdentities, setRwIdentities] = useState([]);
|
|
211
|
+
const [rwTargets, setRwTargets] = useState([]);
|
|
212
|
+
// Only offer the managed-Prometheus option for the cluster's own cloud (no
|
|
213
|
+
// AWS Managed Prometheus on an Azure cluster, etc.); Grafana Cloud and generic
|
|
214
|
+
// remote_write stay available everywhere.
|
|
215
|
+
const remoteWriteDestinations = REMOTE_WRITE_DESTINATIONS.filter((d) => {
|
|
216
|
+
if (d.value === "aws-amp")
|
|
217
|
+
return state.provider === "aws";
|
|
218
|
+
if (d.value === "azure-monitor")
|
|
219
|
+
return state.provider === "azure";
|
|
220
|
+
return true;
|
|
221
|
+
});
|
|
222
|
+
const [rwTenantAutoDetected, setRwTenantAutoDetected] = useState(false);
|
|
150
223
|
// Custom email templates
|
|
151
224
|
const [emailSubjectInvite, setEmailSubjectInvite] = useState(state.emailSubjects?.invite || DEFAULT_EMAIL_SUBJECTS.invite);
|
|
152
225
|
const [emailSubjectConfirm, setEmailSubjectConfirm] = useState(state.emailSubjects?.confirmation || DEFAULT_EMAIL_SUBJECTS.confirmation);
|
|
@@ -162,11 +235,14 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
162
235
|
!needsSSO &&
|
|
163
236
|
!needsMonitoring &&
|
|
164
237
|
!needsLogging &&
|
|
238
|
+
!needsTracing &&
|
|
239
|
+
!needsAppLogs &&
|
|
240
|
+
!needsValkeyAdmin &&
|
|
165
241
|
!needsCustomEmails) {
|
|
166
242
|
onComplete();
|
|
167
243
|
}
|
|
168
244
|
}, []);
|
|
169
|
-
|
|
245
|
+
useGatedInput((input, key) => {
|
|
170
246
|
if (key.escape) {
|
|
171
247
|
setError(null);
|
|
172
248
|
handleBack();
|
|
@@ -195,7 +271,7 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
195
271
|
case "sso-client-secret":
|
|
196
272
|
setSubStep("sso-client-id");
|
|
197
273
|
break;
|
|
198
|
-
case "monitoring-remote-write-
|
|
274
|
+
case "monitoring-remote-write-destination":
|
|
199
275
|
if (needsSSO)
|
|
200
276
|
setSubStep("sso-client-secret");
|
|
201
277
|
else if (needsAI)
|
|
@@ -203,22 +279,37 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
203
279
|
else
|
|
204
280
|
onBack();
|
|
205
281
|
break;
|
|
206
|
-
case "monitoring-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
case "monitoring-remote-write-url":
|
|
210
|
-
setSubStep("monitoring-remote-write-destination");
|
|
211
|
-
break;
|
|
282
|
+
case "monitoring-azure-target-loading":
|
|
283
|
+
case "monitoring-azure-target":
|
|
284
|
+
case "monitoring-aws-region-loading":
|
|
212
285
|
case "monitoring-aws-region":
|
|
213
|
-
|
|
286
|
+
// Azure target discovery and AWS region both branch directly off the
|
|
287
|
+
// destination choice.
|
|
288
|
+
setSubStep("monitoring-remote-write-destination");
|
|
214
289
|
break;
|
|
215
|
-
case "monitoring-aws-
|
|
290
|
+
case "monitoring-aws-workspace-loading":
|
|
291
|
+
case "monitoring-aws-workspace":
|
|
216
292
|
setSubStep("monitoring-aws-region");
|
|
217
293
|
break;
|
|
294
|
+
case "monitoring-remote-write-url":
|
|
295
|
+
// The manual-URL fallback is reached from the discovery picker.
|
|
296
|
+
if (remoteWriteDestination === "azure-monitor") {
|
|
297
|
+
setSubStep("monitoring-azure-target");
|
|
298
|
+
}
|
|
299
|
+
else if (remoteWriteDestination === "aws-amp") {
|
|
300
|
+
setSubStep("monitoring-aws-workspace");
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
setSubStep("monitoring-remote-write-destination");
|
|
304
|
+
}
|
|
305
|
+
break;
|
|
218
306
|
case "monitoring-remote-write-azure-auth":
|
|
307
|
+
setSubStep("monitoring-azure-target");
|
|
308
|
+
break;
|
|
219
309
|
case "monitoring-remote-write-generic-auth":
|
|
220
310
|
setSubStep("monitoring-remote-write-url");
|
|
221
311
|
break;
|
|
312
|
+
case "monitoring-azure-identity-loading":
|
|
222
313
|
case "monitoring-remote-write-client-id":
|
|
223
314
|
if (remoteWriteDestination === "azure-monitor") {
|
|
224
315
|
setSubStep("monitoring-remote-write-azure-auth");
|
|
@@ -227,6 +318,9 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
227
318
|
setSubStep("monitoring-remote-write-url");
|
|
228
319
|
}
|
|
229
320
|
break;
|
|
321
|
+
case "monitoring-remote-write-client-id-manual":
|
|
322
|
+
setSubStep("monitoring-remote-write-client-id");
|
|
323
|
+
break;
|
|
230
324
|
case "monitoring-remote-write-tenant-id":
|
|
231
325
|
setSubStep("monitoring-remote-write-client-id");
|
|
232
326
|
break;
|
|
@@ -246,9 +340,9 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
246
340
|
case "monitoring-remote-write-bearer-secret-ref":
|
|
247
341
|
setSubStep("monitoring-remote-write-generic-auth");
|
|
248
342
|
break;
|
|
249
|
-
case "logging-
|
|
343
|
+
case "logging-sink":
|
|
250
344
|
if (needsMonitoring)
|
|
251
|
-
setSubStep("monitoring-remote-write-
|
|
345
|
+
setSubStep("monitoring-remote-write-destination");
|
|
252
346
|
else if (needsSSO)
|
|
253
347
|
setSubStep("sso-client-secret");
|
|
254
348
|
else if (needsAI)
|
|
@@ -256,53 +350,102 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
256
350
|
else
|
|
257
351
|
onBack();
|
|
258
352
|
break;
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
case "logging-
|
|
263
|
-
case "logging-
|
|
353
|
+
// Logging platform config steps
|
|
354
|
+
case "logging-datadog-config":
|
|
355
|
+
case "logging-splunk-config":
|
|
356
|
+
case "logging-elasticsearch-config":
|
|
357
|
+
case "logging-loki-config":
|
|
358
|
+
case "logging-newrelic-config":
|
|
359
|
+
case "logging-axiom-config":
|
|
264
360
|
setSubStep("logging-sink");
|
|
265
361
|
break;
|
|
266
|
-
|
|
267
|
-
case "
|
|
268
|
-
|
|
362
|
+
// Distributed tracing steps
|
|
363
|
+
case "tracing-destination":
|
|
364
|
+
if (needsLogging)
|
|
365
|
+
setSubStep("logging-sink");
|
|
366
|
+
else if (needsMonitoring)
|
|
367
|
+
setSubStep("monitoring-remote-write-destination");
|
|
368
|
+
else if (needsSSO)
|
|
369
|
+
setSubStep("sso-client-secret");
|
|
370
|
+
else if (needsAI)
|
|
371
|
+
setSubStep("openai-key");
|
|
372
|
+
else
|
|
373
|
+
onBack();
|
|
269
374
|
break;
|
|
270
|
-
case "
|
|
271
|
-
|
|
375
|
+
case "tracing-endpoint":
|
|
376
|
+
case "tracing-otlp-endpoint":
|
|
377
|
+
case "tracing-azure-connection":
|
|
378
|
+
setSubStep("tracing-destination");
|
|
272
379
|
break;
|
|
273
|
-
case "
|
|
274
|
-
setSubStep("
|
|
380
|
+
case "tracing-token":
|
|
381
|
+
setSubStep("tracing-endpoint");
|
|
275
382
|
break;
|
|
276
|
-
case "
|
|
277
|
-
setSubStep("
|
|
383
|
+
case "tracing-otlp-auth":
|
|
384
|
+
setSubStep("tracing-otlp-endpoint");
|
|
278
385
|
break;
|
|
279
|
-
case "
|
|
280
|
-
setSubStep("
|
|
386
|
+
case "tracing-otlp-cred":
|
|
387
|
+
setSubStep("tracing-otlp-auth");
|
|
281
388
|
break;
|
|
282
|
-
|
|
283
|
-
|
|
389
|
+
// Application log shipping steps
|
|
390
|
+
case "applogs-endpoint":
|
|
391
|
+
if (needsTracing)
|
|
392
|
+
setSubStep(tracingFinalStep());
|
|
393
|
+
else if (needsLogging)
|
|
394
|
+
setSubStep(loggingFinalStep());
|
|
395
|
+
else if (needsMonitoring)
|
|
396
|
+
setSubStep("monitoring-remote-write-destination");
|
|
397
|
+
else if (needsSSO)
|
|
398
|
+
setSubStep("sso-client-secret");
|
|
399
|
+
else if (needsAI)
|
|
400
|
+
setSubStep("openai-key");
|
|
401
|
+
else
|
|
402
|
+
onBack();
|
|
284
403
|
break;
|
|
285
|
-
case "
|
|
286
|
-
setSubStep("
|
|
404
|
+
case "applogs-user":
|
|
405
|
+
setSubStep("applogs-endpoint");
|
|
287
406
|
break;
|
|
288
|
-
case "
|
|
289
|
-
setSubStep("
|
|
407
|
+
case "applogs-pass":
|
|
408
|
+
setSubStep("applogs-user");
|
|
290
409
|
break;
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
case "
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
410
|
+
case "applogs-index":
|
|
411
|
+
setSubStep("applogs-pass");
|
|
412
|
+
break;
|
|
413
|
+
// Valkey Admin steps
|
|
414
|
+
case "valkey-admin-username":
|
|
415
|
+
if (needsAppLogs)
|
|
416
|
+
setSubStep("applogs-index");
|
|
417
|
+
else if (needsTracing)
|
|
418
|
+
setSubStep(tracingFinalStep());
|
|
419
|
+
else if (needsLogging)
|
|
420
|
+
setSubStep(loggingFinalStep());
|
|
421
|
+
else if (needsMonitoring)
|
|
422
|
+
setSubStep("monitoring-remote-write-destination");
|
|
423
|
+
else if (needsSSO)
|
|
424
|
+
setSubStep("sso-client-secret");
|
|
425
|
+
else if (needsAI)
|
|
426
|
+
setSubStep("openai-key");
|
|
427
|
+
else
|
|
428
|
+
onBack();
|
|
429
|
+
break;
|
|
430
|
+
case "valkey-admin-password":
|
|
431
|
+
setSubStep("valkey-admin-username");
|
|
432
|
+
break;
|
|
433
|
+
case "valkey-admin-allowed-ips":
|
|
434
|
+
setSubStep("valkey-admin-password");
|
|
299
435
|
break;
|
|
300
436
|
// Email template steps
|
|
301
437
|
case "email-subject-invite":
|
|
302
|
-
if (
|
|
303
|
-
setSubStep("
|
|
438
|
+
if (needsValkeyAdmin) {
|
|
439
|
+
setSubStep("valkey-admin-allowed-ips");
|
|
440
|
+
}
|
|
441
|
+
else if (needsAppLogs)
|
|
442
|
+
setSubStep("applogs-index");
|
|
443
|
+
else if (needsTracing)
|
|
444
|
+
setSubStep(tracingFinalStep());
|
|
445
|
+
else if (needsLogging)
|
|
446
|
+
setSubStep(loggingFinalStep());
|
|
304
447
|
else if (needsMonitoring)
|
|
305
|
-
setSubStep("monitoring-remote-write-
|
|
448
|
+
setSubStep("monitoring-remote-write-destination");
|
|
306
449
|
else if (needsSSO)
|
|
307
450
|
setSubStep("sso-client-secret");
|
|
308
451
|
else if (needsAI)
|
|
@@ -333,35 +476,59 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
333
476
|
break;
|
|
334
477
|
}
|
|
335
478
|
};
|
|
479
|
+
// Section sequencing helpers. Each "goTo<Section>OrAfter" advances to the next
|
|
480
|
+
// enabled section, so adding a section only required inserting it into this
|
|
481
|
+
// chain (Logging -> Tracing -> AppLogs -> Valkey Admin -> Custom Emails).
|
|
482
|
+
const goToCustomEmailsOrDone = () => {
|
|
483
|
+
if (needsCustomEmails)
|
|
484
|
+
setSubStep("email-subject-invite");
|
|
485
|
+
else
|
|
486
|
+
onComplete();
|
|
487
|
+
};
|
|
488
|
+
const goToValkeyAdminOrAfter = () => {
|
|
489
|
+
if (needsValkeyAdmin)
|
|
490
|
+
setSubStep("valkey-admin-username");
|
|
491
|
+
else
|
|
492
|
+
goToCustomEmailsOrDone();
|
|
493
|
+
};
|
|
494
|
+
const goToAppLogsOrAfter = () => {
|
|
495
|
+
if (needsAppLogs)
|
|
496
|
+
setSubStep("applogs-endpoint");
|
|
497
|
+
else
|
|
498
|
+
goToValkeyAdminOrAfter();
|
|
499
|
+
};
|
|
500
|
+
const goToTracingOrAfter = () => {
|
|
501
|
+
if (needsTracing)
|
|
502
|
+
setSubStep("tracing-destination");
|
|
503
|
+
else
|
|
504
|
+
goToAppLogsOrAfter();
|
|
505
|
+
};
|
|
506
|
+
const goToLoggingOrAfter = () => {
|
|
507
|
+
if (needsLogging)
|
|
508
|
+
setSubStep("logging-sink");
|
|
509
|
+
else
|
|
510
|
+
goToTracingOrAfter();
|
|
511
|
+
};
|
|
512
|
+
const goToMonitoringOrAfter = () => {
|
|
513
|
+
if (needsMonitoring)
|
|
514
|
+
setSubStep("monitoring-remote-write-destination");
|
|
515
|
+
else
|
|
516
|
+
goToLoggingOrAfter();
|
|
517
|
+
};
|
|
336
518
|
const advanceToNext = (from) => {
|
|
337
519
|
switch (from) {
|
|
338
520
|
case "openai-key":
|
|
339
521
|
if (needsSSO)
|
|
340
522
|
setSubStep("sso-provider");
|
|
341
|
-
else if (needsMonitoring)
|
|
342
|
-
setSubStep("monitoring-remote-write-ask");
|
|
343
|
-
else if (needsLogging)
|
|
344
|
-
setSubStep("logging-category");
|
|
345
|
-
else if (needsCustomEmails)
|
|
346
|
-
setSubStep("email-subject-invite");
|
|
347
523
|
else
|
|
348
|
-
|
|
524
|
+
goToMonitoringOrAfter();
|
|
349
525
|
break;
|
|
350
526
|
case "sso-client-secret":
|
|
351
|
-
|
|
352
|
-
setSubStep("monitoring-remote-write-ask");
|
|
353
|
-
else if (needsLogging)
|
|
354
|
-
setSubStep("logging-category");
|
|
355
|
-
else if (needsCustomEmails)
|
|
356
|
-
setSubStep("email-subject-invite");
|
|
357
|
-
else
|
|
358
|
-
onComplete();
|
|
527
|
+
goToMonitoringOrAfter();
|
|
359
528
|
break;
|
|
360
|
-
case "monitoring-remote-write-ask":
|
|
361
529
|
case "monitoring-remote-write-destination":
|
|
362
530
|
case "monitoring-remote-write-url":
|
|
363
531
|
case "monitoring-aws-region":
|
|
364
|
-
case "monitoring-aws-role-arn":
|
|
365
532
|
case "monitoring-remote-write-azure-auth":
|
|
366
533
|
case "monitoring-remote-write-generic-auth":
|
|
367
534
|
case "monitoring-remote-write-client-id":
|
|
@@ -370,23 +537,7 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
370
537
|
case "monitoring-remote-write-username-secret-ref":
|
|
371
538
|
case "monitoring-remote-write-password-secret-ref":
|
|
372
539
|
case "monitoring-remote-write-bearer-secret-ref":
|
|
373
|
-
|
|
374
|
-
setSubStep("logging-category");
|
|
375
|
-
else if (needsCustomEmails)
|
|
376
|
-
setSubStep("email-subject-invite");
|
|
377
|
-
else
|
|
378
|
-
onComplete();
|
|
379
|
-
break;
|
|
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":
|
|
385
|
-
// Cloud storage config complete, check for custom emails
|
|
386
|
-
if (needsCustomEmails)
|
|
387
|
-
setSubStep("email-subject-invite");
|
|
388
|
-
else
|
|
389
|
-
onComplete();
|
|
540
|
+
goToLoggingOrAfter();
|
|
390
541
|
break;
|
|
391
542
|
case "logging-datadog-config":
|
|
392
543
|
case "logging-splunk-config":
|
|
@@ -394,11 +545,19 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
394
545
|
case "logging-loki-config":
|
|
395
546
|
case "logging-newrelic-config":
|
|
396
547
|
case "logging-axiom-config":
|
|
397
|
-
//
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
548
|
+
// Decision-log platform config complete -> tracing/appLogs/emails.
|
|
549
|
+
goToTracingOrAfter();
|
|
550
|
+
break;
|
|
551
|
+
case "tracing-token":
|
|
552
|
+
case "tracing-otlp-cred":
|
|
553
|
+
case "tracing-azure-connection":
|
|
554
|
+
goToAppLogsOrAfter();
|
|
555
|
+
break;
|
|
556
|
+
case "applogs-index":
|
|
557
|
+
goToValkeyAdminOrAfter();
|
|
558
|
+
break;
|
|
559
|
+
case "valkey-admin-allowed-ips":
|
|
560
|
+
goToCustomEmailsOrDone();
|
|
402
561
|
break;
|
|
403
562
|
case "email-template-change":
|
|
404
563
|
// All email config complete
|
|
@@ -473,24 +632,6 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
473
632
|
advanceToNext("sso-client-secret");
|
|
474
633
|
};
|
|
475
634
|
// === Monitoring Configuration ===
|
|
476
|
-
const handleRemoteWriteAsk = (item) => {
|
|
477
|
-
const destination = item.value;
|
|
478
|
-
if (destination === "local-grafana") {
|
|
479
|
-
setRemoteWriteDestination(null);
|
|
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
|
-
});
|
|
489
|
-
advanceToNext("monitoring-remote-write-ask");
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
handleRemoteWriteDestinationSelect({ value: destination });
|
|
493
|
-
};
|
|
494
635
|
const handleRemoteWriteDestinationSelect = (item) => {
|
|
495
636
|
const destination = item.value;
|
|
496
637
|
setRemoteWriteDestination(destination);
|
|
@@ -502,22 +643,100 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
502
643
|
prometheusRemoteWriteDestination: destination,
|
|
503
644
|
},
|
|
504
645
|
});
|
|
505
|
-
|
|
646
|
+
// Auto-discover the remote_write URL where we can, so the user selects an
|
|
647
|
+
// existing target instead of hand-building a URL. Manual entry stays available.
|
|
648
|
+
if (destination === "azure-monitor") {
|
|
649
|
+
loadAzureTargets();
|
|
650
|
+
}
|
|
651
|
+
else if (destination === "aws-amp") {
|
|
652
|
+
loadAwsRegions();
|
|
653
|
+
}
|
|
654
|
+
else {
|
|
655
|
+
setSubStep("monitoring-remote-write-url");
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
// Azure Monitor: discover Data Collection Rules that ingest Prometheus metrics
|
|
659
|
+
// and pre-assemble each remote_write URL.
|
|
660
|
+
const loadAzureTargets = async () => {
|
|
661
|
+
setSubStep("monitoring-azure-target-loading");
|
|
662
|
+
try {
|
|
663
|
+
setRwTargets(await listAzurePrometheusTargets());
|
|
664
|
+
}
|
|
665
|
+
catch {
|
|
666
|
+
setRwTargets([]);
|
|
667
|
+
}
|
|
668
|
+
setSubStep("monitoring-azure-target");
|
|
669
|
+
};
|
|
670
|
+
const handleAzureTargetSelect = (item) => {
|
|
671
|
+
if (item.value === REFRESH) {
|
|
672
|
+
loadAzureTargets();
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
if (item.value === MANUAL) {
|
|
676
|
+
setSubStep("monitoring-remote-write-url");
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
setRemoteWriteUrl(item.value);
|
|
680
|
+
dispatch({ type: "SET_PROMETHEUS_REMOTE_WRITE", url: item.value });
|
|
681
|
+
setError(null);
|
|
682
|
+
setSubStep("monitoring-remote-write-azure-auth");
|
|
683
|
+
};
|
|
684
|
+
// AWS Managed Prometheus: discover workspaces in the chosen region and
|
|
685
|
+
// pre-assemble each remote_write URL.
|
|
686
|
+
const loadAwsWorkspaces = async (region) => {
|
|
687
|
+
setSubStep("monitoring-aws-workspace-loading");
|
|
688
|
+
try {
|
|
689
|
+
setRwTargets(await listAwsPrometheusWorkspaces(region));
|
|
690
|
+
}
|
|
691
|
+
catch {
|
|
692
|
+
setRwTargets([]);
|
|
693
|
+
}
|
|
694
|
+
setSubStep("monitoring-aws-workspace");
|
|
695
|
+
};
|
|
696
|
+
const handleAwsWorkspaceSelect = (item) => {
|
|
697
|
+
if (item.value === REFRESH) {
|
|
698
|
+
loadAwsWorkspaces(remoteWriteAwsRegion);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
if (item.value === MANUAL) {
|
|
702
|
+
setSubStep("monitoring-remote-write-url");
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
setRemoteWriteUrl(item.value);
|
|
706
|
+
dispatch({ type: "SET_PROMETHEUS_REMOTE_WRITE", url: item.value });
|
|
707
|
+
setError(null);
|
|
708
|
+
saveAwsAmpConfig("");
|
|
506
709
|
};
|
|
507
710
|
const handleRemoteWriteUrlSubmit = () => {
|
|
508
|
-
if (remoteWriteUrl) {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
711
|
+
if (!remoteWriteUrl) {
|
|
712
|
+
setError("Remote write URL is required. If you don't have a destination yet, go back and disable Metrics Export.");
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
try {
|
|
716
|
+
new URL(remoteWriteUrl);
|
|
717
|
+
}
|
|
718
|
+
catch {
|
|
719
|
+
setError("Invalid URL format");
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
// Azure Monitor needs the full DCE metrics-ingestion path, not the bare DCE
|
|
723
|
+
// host. Catch it here so the user gets immediate feedback instead of a
|
|
724
|
+
// failure at save time.
|
|
725
|
+
if (remoteWriteDestination === "azure-monitor" &&
|
|
726
|
+
!(remoteWriteUrl.includes("/dataCollectionRules/") &&
|
|
727
|
+
remoteWriteUrl.includes("/streams/") &&
|
|
728
|
+
remoteWriteUrl.includes("/api/v1/write"))) {
|
|
729
|
+
setError("Azure Monitor needs the full ingestion URL, e.g.\n" +
|
|
730
|
+
"https://<dce>.<region>.metrics.ingest.monitor.azure.com/dataCollectionRules/<dcrImmutableId>/streams/Microsoft-PrometheusMetrics/api/v1/write?api-version=2023-04-24\n" +
|
|
731
|
+
"(the data collection endpoint host alone won't work).");
|
|
732
|
+
return;
|
|
516
733
|
}
|
|
517
734
|
setError(null);
|
|
518
735
|
dispatch({ type: "SET_PROMETHEUS_REMOTE_WRITE", url: remoteWriteUrl });
|
|
519
736
|
if (remoteWriteDestination === "aws-amp") {
|
|
520
|
-
|
|
737
|
+
// Region was already chosen before this manual-URL fallback (it's reached
|
|
738
|
+
// from the workspace picker), so save directly.
|
|
739
|
+
saveAwsAmpConfig("");
|
|
521
740
|
}
|
|
522
741
|
else if (remoteWriteDestination === "azure-monitor") {
|
|
523
742
|
setSubStep("monitoring-remote-write-azure-auth");
|
|
@@ -537,19 +756,25 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
537
756
|
setError("Select a remote_write destination first");
|
|
538
757
|
}
|
|
539
758
|
};
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
759
|
+
// AWS Managed Prometheus: pick region then IRSA role from CLI-backed lists.
|
|
760
|
+
const loadAwsRegions = async () => {
|
|
761
|
+
setSubStep("monitoring-aws-region-loading");
|
|
762
|
+
try {
|
|
763
|
+
const regions = await listRegions("aws");
|
|
764
|
+
setRwRegions(regions.length > 0 ? regions : CLOUD_REGIONS.aws);
|
|
544
765
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
};
|
|
548
|
-
const handleAwsRemoteWriteRoleArnSubmit = () => {
|
|
549
|
-
if (remoteWriteAwsRoleArn && !remoteWriteAwsRoleArn.startsWith("arn:")) {
|
|
550
|
-
setError("Enter a valid IAM role ARN or leave blank");
|
|
551
|
-
return;
|
|
766
|
+
catch {
|
|
767
|
+
setRwRegions(CLOUD_REGIONS.aws);
|
|
552
768
|
}
|
|
769
|
+
setSubStep("monitoring-aws-region");
|
|
770
|
+
};
|
|
771
|
+
const handleAwsRegionSelect = (item) => {
|
|
772
|
+
setRemoteWriteAwsRegion(item.value);
|
|
773
|
+
// Discover AMP workspaces in this region; the role is the single Rulebricks
|
|
774
|
+
// role from the Storage step (reused at assembly), so there's no role prompt.
|
|
775
|
+
loadAwsWorkspaces(item.value);
|
|
776
|
+
};
|
|
777
|
+
const saveAwsAmpConfig = (roleArn) => {
|
|
553
778
|
dispatch({
|
|
554
779
|
type: "SET_PROMETHEUS_REMOTE_WRITE_CONFIG",
|
|
555
780
|
config: {
|
|
@@ -557,11 +782,11 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
557
782
|
prometheusMonitoringDestination: "aws-amp",
|
|
558
783
|
prometheusRemoteWriteAuthType: "none",
|
|
559
784
|
prometheusRemoteWriteAwsRegion: remoteWriteAwsRegion,
|
|
560
|
-
prometheusRemoteWriteAwsRoleArn:
|
|
785
|
+
prometheusRemoteWriteAwsRoleArn: roleArn,
|
|
561
786
|
},
|
|
562
787
|
});
|
|
563
788
|
setError(null);
|
|
564
|
-
advanceToNext("monitoring-aws-
|
|
789
|
+
advanceToNext("monitoring-aws-region");
|
|
565
790
|
};
|
|
566
791
|
const saveRemoteWriteConfig = (authType, overrides = {}) => {
|
|
567
792
|
if (!remoteWriteDestination || !remoteWriteUrl) {
|
|
@@ -593,8 +818,55 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
593
818
|
type: "SET_PROMETHEUS_REMOTE_WRITE_CONFIG",
|
|
594
819
|
config: { prometheusRemoteWriteAuthType: authType },
|
|
595
820
|
});
|
|
821
|
+
// Workload/managed identity reuse the single Rulebricks identity chosen in
|
|
822
|
+
// the Storage step (filled in during config assembly), so there's no second
|
|
823
|
+
// identity to pick here. Only OAuth needs its own app-registration credentials.
|
|
824
|
+
if (authType === "workload-identity" || authType === "managed-identity") {
|
|
825
|
+
saveRemoteWriteConfig(authType);
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
loadAzureIdentitiesForRemoteWrite();
|
|
829
|
+
};
|
|
830
|
+
// Azure Monitor: pick the managed/workload identity client ID from a list and
|
|
831
|
+
// auto-fill the tenant ID from the active Azure CLI session.
|
|
832
|
+
const loadAzureIdentitiesForRemoteWrite = async () => {
|
|
833
|
+
setSubStep("monitoring-azure-identity-loading");
|
|
834
|
+
try {
|
|
835
|
+
const [identities, tenant] = await Promise.all([
|
|
836
|
+
listAzureManagedIdentities(),
|
|
837
|
+
remoteWriteTenantId
|
|
838
|
+
? Promise.resolve(null)
|
|
839
|
+
: getAzureTenantId(),
|
|
840
|
+
]);
|
|
841
|
+
setRwIdentities(identities);
|
|
842
|
+
if (tenant) {
|
|
843
|
+
setRemoteWriteTenantId(tenant);
|
|
844
|
+
setRwTenantAutoDetected(true);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
catch {
|
|
848
|
+
setRwIdentities([]);
|
|
849
|
+
}
|
|
596
850
|
setSubStep("monitoring-remote-write-client-id");
|
|
597
851
|
};
|
|
852
|
+
const proceedAfterClientId = () => {
|
|
853
|
+
if (remoteWriteAuthType === "managed-identity") {
|
|
854
|
+
saveRemoteWriteConfig("managed-identity", {
|
|
855
|
+
clientId: remoteWriteClientId,
|
|
856
|
+
});
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
setError(null);
|
|
860
|
+
setSubStep("monitoring-remote-write-tenant-id");
|
|
861
|
+
};
|
|
862
|
+
const handleRemoteWriteClientIdSelect = (item) => {
|
|
863
|
+
if (item.value === MANUAL) {
|
|
864
|
+
setSubStep("monitoring-remote-write-client-id-manual");
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
setRemoteWriteClientId(item.value);
|
|
868
|
+
proceedAfterClientId();
|
|
869
|
+
};
|
|
598
870
|
const handleGenericRemoteWriteAuthSelect = (item) => {
|
|
599
871
|
const authType = item.value;
|
|
600
872
|
setRemoteWriteAuthType(authType);
|
|
@@ -613,14 +885,7 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
613
885
|
setError("Client ID is required");
|
|
614
886
|
return;
|
|
615
887
|
}
|
|
616
|
-
|
|
617
|
-
saveRemoteWriteConfig("managed-identity", {
|
|
618
|
-
clientId: remoteWriteClientId,
|
|
619
|
-
});
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
setError(null);
|
|
623
|
-
setSubStep("monitoring-remote-write-tenant-id");
|
|
888
|
+
proceedAfterClientId();
|
|
624
889
|
};
|
|
625
890
|
const handleRemoteWriteTenantIdSubmit = () => {
|
|
626
891
|
if (!remoteWriteTenantId) {
|
|
@@ -675,304 +940,318 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
675
940
|
bearerTokenSecretRef: remoteWriteBearerSecretRef,
|
|
676
941
|
});
|
|
677
942
|
};
|
|
678
|
-
// === Logging Configuration ===
|
|
679
|
-
|
|
680
|
-
const sinkToProvider = (sink) => {
|
|
681
|
-
if (sink === "s3")
|
|
682
|
-
return "aws";
|
|
683
|
-
if (sink === "azure-blob")
|
|
684
|
-
return "azure";
|
|
685
|
-
if (sink === "gcs")
|
|
686
|
-
return "gcp";
|
|
687
|
-
return null;
|
|
688
|
-
};
|
|
689
|
-
// Is sink a cloud storage type?
|
|
690
|
-
const isCloudStorageSink = (sink) => {
|
|
691
|
-
return sink === "s3" || sink === "azure-blob" || sink === "gcs";
|
|
692
|
-
};
|
|
693
|
-
// Step 1: Select logging category
|
|
694
|
-
const handleLoggingCategorySelect = (item) => {
|
|
695
|
-
const category = item.value;
|
|
696
|
-
setLoggingCategory(category);
|
|
697
|
-
setSubStep("logging-sink");
|
|
698
|
-
};
|
|
699
|
-
// Step 2: Select logging sink based on category
|
|
700
|
-
const handleLoggingSinkSelect = async (item) => {
|
|
943
|
+
// === Logging Configuration (external logging platforms) ===
|
|
944
|
+
const handleLoggingSinkSelect = (item) => {
|
|
701
945
|
const sink = item.value;
|
|
702
946
|
setLoggingSink(sink);
|
|
703
947
|
dispatch({ type: "SET_LOGGING_SINK", sink });
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
948
|
+
switch (sink) {
|
|
949
|
+
case "datadog":
|
|
950
|
+
setSubStep("logging-datadog-config");
|
|
951
|
+
break;
|
|
952
|
+
case "splunk":
|
|
953
|
+
setSubStep("logging-splunk-config");
|
|
954
|
+
break;
|
|
955
|
+
case "elasticsearch":
|
|
956
|
+
setSubStep("logging-elasticsearch-config");
|
|
957
|
+
break;
|
|
958
|
+
case "loki":
|
|
959
|
+
setSubStep("logging-loki-config");
|
|
960
|
+
break;
|
|
961
|
+
case "newrelic":
|
|
962
|
+
setSubStep("logging-newrelic-config");
|
|
963
|
+
break;
|
|
964
|
+
case "axiom":
|
|
965
|
+
setSubStep("logging-axiom-config");
|
|
966
|
+
break;
|
|
707
967
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
case "splunk":
|
|
715
|
-
setSubStep("logging-splunk-config");
|
|
716
|
-
break;
|
|
717
|
-
case "elasticsearch":
|
|
718
|
-
setSubStep("logging-elasticsearch-config");
|
|
719
|
-
break;
|
|
720
|
-
case "loki":
|
|
721
|
-
setSubStep("logging-loki-config");
|
|
722
|
-
break;
|
|
723
|
-
case "newrelic":
|
|
724
|
-
setSubStep("logging-newrelic-config");
|
|
725
|
-
break;
|
|
726
|
-
case "axiom":
|
|
727
|
-
setSubStep("logging-axiom-config");
|
|
728
|
-
break;
|
|
729
|
-
}
|
|
968
|
+
};
|
|
969
|
+
// === Logging Platform Config Handlers ===
|
|
970
|
+
const handleDatadogConfigSubmit = () => {
|
|
971
|
+
if (!datadogApiKey) {
|
|
972
|
+
setError("Datadog API key is required");
|
|
973
|
+
return;
|
|
730
974
|
}
|
|
975
|
+
setError(null);
|
|
976
|
+
dispatch({
|
|
977
|
+
type: "SET_LOGGING_CONFIG",
|
|
978
|
+
config: {
|
|
979
|
+
loggingPlatformCredential: datadogApiKey, // platform API key
|
|
980
|
+
loggingPlatformDetail: datadogSite, // platform site
|
|
981
|
+
},
|
|
982
|
+
});
|
|
983
|
+
advanceToNext("logging-datadog-config");
|
|
731
984
|
};
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
985
|
+
const handleSplunkConfigSubmit = () => {
|
|
986
|
+
if (!splunkUrl) {
|
|
987
|
+
setError("Splunk HEC URL is required");
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
if (!splunkHecToken) {
|
|
991
|
+
setError("Splunk HEC token is required");
|
|
737
992
|
return;
|
|
738
993
|
}
|
|
739
|
-
setSubStep("logging-region-loading");
|
|
740
994
|
try {
|
|
741
|
-
|
|
742
|
-
if (regions.length > 0) {
|
|
743
|
-
setAvailableRegions(regions);
|
|
744
|
-
}
|
|
745
|
-
else {
|
|
746
|
-
setAvailableRegions(CLOUD_REGIONS[provider]);
|
|
747
|
-
}
|
|
995
|
+
new URL(splunkUrl);
|
|
748
996
|
}
|
|
749
997
|
catch {
|
|
750
|
-
|
|
998
|
+
setError("Invalid URL format");
|
|
999
|
+
return;
|
|
751
1000
|
}
|
|
752
|
-
|
|
753
|
-
};
|
|
754
|
-
// After region is selected, load buckets in that region
|
|
755
|
-
const handleLoggingRegionSelect = async (item) => {
|
|
756
|
-
setLoggingRegion(item.value);
|
|
1001
|
+
setError(null);
|
|
757
1002
|
dispatch({
|
|
758
1003
|
type: "SET_LOGGING_CONFIG",
|
|
759
|
-
config: {
|
|
1004
|
+
config: {
|
|
1005
|
+
loggingPlatformCredential: splunkHecToken,
|
|
1006
|
+
loggingPlatformDetail: splunkUrl,
|
|
1007
|
+
},
|
|
760
1008
|
});
|
|
761
|
-
|
|
762
|
-
const provider = sinkToProvider(loggingSink);
|
|
763
|
-
if (provider) {
|
|
764
|
-
setSubStep("logging-bucket-loading");
|
|
765
|
-
try {
|
|
766
|
-
const buckets = await listBucketsInRegion(provider, item.value);
|
|
767
|
-
setAvailableBuckets(buckets);
|
|
768
|
-
}
|
|
769
|
-
catch {
|
|
770
|
-
setAvailableBuckets([]);
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
setSubStep("logging-bucket");
|
|
1009
|
+
advanceToNext("logging-splunk-config");
|
|
774
1010
|
};
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
return;
|
|
779
|
-
const provider = sinkToProvider(loggingSink);
|
|
780
|
-
if (!provider || !loggingRegion)
|
|
1011
|
+
const handleElasticsearchConfigSubmit = () => {
|
|
1012
|
+
if (!elasticsearchUrl) {
|
|
1013
|
+
setError("Elasticsearch URL is required");
|
|
781
1014
|
return;
|
|
782
|
-
|
|
1015
|
+
}
|
|
783
1016
|
try {
|
|
784
|
-
|
|
785
|
-
setAvailableBuckets(buckets);
|
|
1017
|
+
new URL(elasticsearchUrl);
|
|
786
1018
|
}
|
|
787
1019
|
catch {
|
|
788
|
-
|
|
1020
|
+
setError("Invalid URL format");
|
|
1021
|
+
return;
|
|
789
1022
|
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
// Select bucket (no create option)
|
|
793
|
-
const handleLoggingBucketSelect = (item) => {
|
|
794
|
-
setLoggingBucket(item.value);
|
|
1023
|
+
setError(null);
|
|
1024
|
+
// Store the connection as JSON in the credential field for complex config.
|
|
795
1025
|
dispatch({
|
|
796
1026
|
type: "SET_LOGGING_CONFIG",
|
|
797
|
-
config: {
|
|
1027
|
+
config: {
|
|
1028
|
+
loggingPlatformCredential: JSON.stringify({
|
|
1029
|
+
url: elasticsearchUrl,
|
|
1030
|
+
user: elasticsearchUser,
|
|
1031
|
+
password: elasticsearchPass,
|
|
1032
|
+
index: elasticsearchIndex,
|
|
1033
|
+
}),
|
|
1034
|
+
loggingPlatformDetail: elasticsearchIndex,
|
|
1035
|
+
},
|
|
798
1036
|
});
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
if (
|
|
804
|
-
|
|
1037
|
+
advanceToNext("logging-elasticsearch-config");
|
|
1038
|
+
};
|
|
1039
|
+
// === Distributed Tracing (Elastic APM) ===
|
|
1040
|
+
const handleTracingEndpointSubmit = () => {
|
|
1041
|
+
if (!tracingEndpoint) {
|
|
1042
|
+
setError("Elastic APM OTLP endpoint is required");
|
|
805
1043
|
return;
|
|
806
1044
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
return;
|
|
1045
|
+
try {
|
|
1046
|
+
new URL(tracingEndpoint);
|
|
810
1047
|
}
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
const handleS3RoleArnSubmit = () => {
|
|
814
|
-
if (!s3RoleArn.startsWith("arn:")) {
|
|
815
|
-
setError("IAM role ARN is required for S3 IRSA");
|
|
1048
|
+
catch {
|
|
1049
|
+
setError("Invalid URL format");
|
|
816
1050
|
return;
|
|
817
1051
|
}
|
|
818
1052
|
setError(null);
|
|
819
1053
|
dispatch({
|
|
820
|
-
type: "
|
|
1054
|
+
type: "SET_TRACING_CONFIG",
|
|
821
1055
|
config: {
|
|
822
|
-
|
|
823
|
-
|
|
1056
|
+
tracingElasticEndpoint: tracingEndpoint,
|
|
1057
|
+
tracingElasticAuthMode: "secret-token",
|
|
824
1058
|
},
|
|
825
1059
|
});
|
|
826
|
-
|
|
1060
|
+
setSubStep("tracing-token");
|
|
827
1061
|
};
|
|
828
|
-
const
|
|
829
|
-
if (!
|
|
830
|
-
setError("
|
|
1062
|
+
const handleTracingTokenSubmit = () => {
|
|
1063
|
+
if (!tracingToken) {
|
|
1064
|
+
setError("Elastic APM secret token is required");
|
|
831
1065
|
return;
|
|
832
1066
|
}
|
|
833
1067
|
setError(null);
|
|
834
1068
|
dispatch({
|
|
835
|
-
type: "
|
|
836
|
-
config: {
|
|
1069
|
+
type: "SET_TRACING_CONFIG",
|
|
1070
|
+
config: { tracingElasticSecretToken: tracingToken },
|
|
837
1071
|
});
|
|
838
|
-
|
|
1072
|
+
advanceToNext("tracing-token");
|
|
839
1073
|
};
|
|
840
|
-
const
|
|
841
|
-
const
|
|
842
|
-
|
|
1074
|
+
const handleTracingDestinationSelect = (item) => {
|
|
1075
|
+
const destination = item.value;
|
|
1076
|
+
setTracingDestination(destination);
|
|
843
1077
|
dispatch({
|
|
844
|
-
type: "
|
|
845
|
-
config: {
|
|
1078
|
+
type: "SET_TRACING_CONFIG",
|
|
1079
|
+
config: { tracingDestination: destination },
|
|
846
1080
|
});
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1081
|
+
setError(null);
|
|
1082
|
+
if (destination === "elastic")
|
|
1083
|
+
setSubStep("tracing-endpoint");
|
|
1084
|
+
else if (destination === "otlp")
|
|
1085
|
+
setSubStep("tracing-otlp-endpoint");
|
|
1086
|
+
else
|
|
1087
|
+
setSubStep("tracing-azure-connection");
|
|
850
1088
|
};
|
|
851
|
-
const
|
|
852
|
-
if (!
|
|
853
|
-
setError("
|
|
1089
|
+
const handleTracingOtlpEndpointSubmit = () => {
|
|
1090
|
+
if (!tracingOtlpEndpoint) {
|
|
1091
|
+
setError("OTLP endpoint is required");
|
|
854
1092
|
return;
|
|
855
1093
|
}
|
|
1094
|
+
try {
|
|
1095
|
+
new URL(tracingOtlpEndpoint);
|
|
1096
|
+
}
|
|
1097
|
+
catch {
|
|
1098
|
+
setError("Invalid URL format");
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
setError(null);
|
|
1102
|
+
dispatch({
|
|
1103
|
+
type: "SET_TRACING_CONFIG",
|
|
1104
|
+
config: { tracingOtlpEndpoint },
|
|
1105
|
+
});
|
|
1106
|
+
setSubStep("tracing-otlp-auth");
|
|
1107
|
+
};
|
|
1108
|
+
const handleTracingOtlpAuthSelect = (item) => {
|
|
1109
|
+
const mode = item.value;
|
|
1110
|
+
setTracingOtlpAuthMode(mode);
|
|
1111
|
+
dispatch({
|
|
1112
|
+
type: "SET_TRACING_CONFIG",
|
|
1113
|
+
config: { tracingOtlpAuthMode: mode },
|
|
1114
|
+
});
|
|
856
1115
|
setError(null);
|
|
857
|
-
|
|
1116
|
+
if (mode === "none") {
|
|
1117
|
+
// No credential needed; the section is complete.
|
|
1118
|
+
goToAppLogsOrAfter();
|
|
1119
|
+
}
|
|
1120
|
+
else {
|
|
1121
|
+
setSubStep("tracing-otlp-cred");
|
|
1122
|
+
}
|
|
858
1123
|
};
|
|
859
|
-
const
|
|
860
|
-
if (!
|
|
861
|
-
setError("
|
|
1124
|
+
const handleTracingOtlpCredSubmit = () => {
|
|
1125
|
+
if (!tracingOtlpToken) {
|
|
1126
|
+
setError("A credential is required for the selected OTLP auth mode");
|
|
862
1127
|
return;
|
|
863
1128
|
}
|
|
864
1129
|
setError(null);
|
|
865
1130
|
dispatch({
|
|
866
|
-
type: "
|
|
867
|
-
config: {
|
|
868
|
-
loggingCloudAuthMode: "workload-identity",
|
|
869
|
-
loggingAzureBlobContainer: azureBlobContainer,
|
|
870
|
-
loggingAzureBlobClientId: azureBlobClientId,
|
|
871
|
-
loggingAzureBlobTenantId: azureBlobTenantId,
|
|
872
|
-
},
|
|
1131
|
+
type: "SET_TRACING_CONFIG",
|
|
1132
|
+
config: { tracingOtlpToken },
|
|
873
1133
|
});
|
|
874
|
-
advanceToNext("
|
|
1134
|
+
advanceToNext("tracing-otlp-cred");
|
|
875
1135
|
};
|
|
876
|
-
const
|
|
877
|
-
if (!
|
|
878
|
-
setError("
|
|
1136
|
+
const handleTracingAzureConnectionSubmit = () => {
|
|
1137
|
+
if (!tracingAzureConnectionString) {
|
|
1138
|
+
setError("Azure Monitor connection string is required");
|
|
879
1139
|
return;
|
|
880
1140
|
}
|
|
881
1141
|
setError(null);
|
|
882
1142
|
dispatch({
|
|
883
|
-
type: "
|
|
884
|
-
config: {
|
|
885
|
-
loggingAzureBlobContainer: azureBlobContainer,
|
|
886
|
-
loggingCloudAuthMode: "secret",
|
|
887
|
-
loggingAzureBlobConnectionStringSecretRef: azureBlobConnectionStringSecretRef,
|
|
888
|
-
},
|
|
1143
|
+
type: "SET_TRACING_CONFIG",
|
|
1144
|
+
config: { tracingAzureConnectionString },
|
|
889
1145
|
});
|
|
890
|
-
advanceToNext("
|
|
1146
|
+
advanceToNext("tracing-azure-connection");
|
|
891
1147
|
};
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
1148
|
+
// === Application Log Shipping (BYO Elasticsearch) ===
|
|
1149
|
+
const handleAppLogsEndpointSubmit = () => {
|
|
1150
|
+
if (!appLogsEndpoint) {
|
|
1151
|
+
setError("Elasticsearch endpoint is required");
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
try {
|
|
1155
|
+
new URL(appLogsEndpoint);
|
|
1156
|
+
}
|
|
1157
|
+
catch {
|
|
1158
|
+
setError("Invalid URL format");
|
|
895
1159
|
return;
|
|
896
1160
|
}
|
|
897
1161
|
setError(null);
|
|
898
1162
|
dispatch({
|
|
899
|
-
type: "
|
|
1163
|
+
type: "SET_APP_LOGS_CONFIG",
|
|
900
1164
|
config: {
|
|
901
|
-
|
|
902
|
-
|
|
1165
|
+
appLogsElasticEndpoint: appLogsEndpoint,
|
|
1166
|
+
appLogsElasticAuthMode: "basic",
|
|
903
1167
|
},
|
|
904
1168
|
});
|
|
905
|
-
|
|
1169
|
+
setSubStep("applogs-user");
|
|
906
1170
|
};
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
setError("Datadog API key is required");
|
|
1171
|
+
const handleAppLogsUserSubmit = () => {
|
|
1172
|
+
if (!appLogsUser) {
|
|
1173
|
+
setError("Elasticsearch username is required");
|
|
911
1174
|
return;
|
|
912
1175
|
}
|
|
913
1176
|
setError(null);
|
|
914
1177
|
dispatch({
|
|
915
|
-
type: "
|
|
916
|
-
config: {
|
|
917
|
-
loggingBucket: datadogApiKey, // Repurpose bucket field for API key
|
|
918
|
-
loggingRegion: datadogSite, // Repurpose region field for site
|
|
919
|
-
},
|
|
1178
|
+
type: "SET_APP_LOGS_CONFIG",
|
|
1179
|
+
config: { appLogsElasticUsername: appLogsUser },
|
|
920
1180
|
});
|
|
921
|
-
|
|
1181
|
+
setSubStep("applogs-pass");
|
|
922
1182
|
};
|
|
923
|
-
const
|
|
924
|
-
if (!
|
|
925
|
-
setError("
|
|
1183
|
+
const handleAppLogsPassSubmit = () => {
|
|
1184
|
+
if (!appLogsPass) {
|
|
1185
|
+
setError("Elasticsearch password is required");
|
|
926
1186
|
return;
|
|
927
1187
|
}
|
|
928
|
-
|
|
929
|
-
|
|
1188
|
+
setError(null);
|
|
1189
|
+
dispatch({
|
|
1190
|
+
type: "SET_APP_LOGS_CONFIG",
|
|
1191
|
+
config: { appLogsElasticPassword: appLogsPass },
|
|
1192
|
+
});
|
|
1193
|
+
setSubStep("applogs-index");
|
|
1194
|
+
};
|
|
1195
|
+
const handleAppLogsIndexSubmit = () => {
|
|
1196
|
+
const index = appLogsIndex || "rulebricks-app-logs";
|
|
1197
|
+
setError(null);
|
|
1198
|
+
dispatch({
|
|
1199
|
+
type: "SET_APP_LOGS_CONFIG",
|
|
1200
|
+
config: { appLogsElasticIndex: index },
|
|
1201
|
+
});
|
|
1202
|
+
advanceToNext("applogs-index");
|
|
1203
|
+
};
|
|
1204
|
+
// === Valkey Admin Ingress ===
|
|
1205
|
+
const handleValkeyAdminUsernameSubmit = () => {
|
|
1206
|
+
const username = valkeyAdminUsername.trim();
|
|
1207
|
+
if (!username) {
|
|
1208
|
+
setError("Username is required");
|
|
930
1209
|
return;
|
|
931
1210
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
}
|
|
935
|
-
catch {
|
|
936
|
-
setError("Invalid URL format");
|
|
1211
|
+
if (username.includes(":")) {
|
|
1212
|
+
setError("Username cannot contain ':'");
|
|
937
1213
|
return;
|
|
938
1214
|
}
|
|
1215
|
+
setValkeyAdminUsername(username);
|
|
939
1216
|
setError(null);
|
|
940
|
-
|
|
941
|
-
type: "SET_LOGGING_CONFIG",
|
|
942
|
-
config: {
|
|
943
|
-
loggingBucket: splunkHecToken,
|
|
944
|
-
loggingRegion: splunkUrl,
|
|
945
|
-
},
|
|
946
|
-
});
|
|
947
|
-
advanceToNext("logging-splunk-config");
|
|
1217
|
+
setSubStep("valkey-admin-password");
|
|
948
1218
|
};
|
|
949
|
-
const
|
|
950
|
-
|
|
951
|
-
|
|
1219
|
+
const handleValkeyAdminPasswordSubmit = () => {
|
|
1220
|
+
// Empty means "use a generated secure value", matching the Supabase flow.
|
|
1221
|
+
const effectivePassword = valkeyAdminPassword.trim() || defaultValkeyAdminPassword;
|
|
1222
|
+
if (effectivePassword.length < 8) {
|
|
1223
|
+
setError("Valkey Admin password must be at least 8 characters");
|
|
952
1224
|
return;
|
|
953
1225
|
}
|
|
954
1226
|
try {
|
|
955
|
-
|
|
1227
|
+
const htpasswdLine = generateHtpasswdLine(valkeyAdminUsername, effectivePassword);
|
|
1228
|
+
dispatch({
|
|
1229
|
+
type: "SET_EXTERNAL_SERVICES",
|
|
1230
|
+
config: {
|
|
1231
|
+
valkeyAdminExposure: "ingress",
|
|
1232
|
+
valkeyAdminHostname: "",
|
|
1233
|
+
valkeyAdminBasicAuthUsers: [htpasswdLine],
|
|
1234
|
+
},
|
|
1235
|
+
});
|
|
956
1236
|
}
|
|
957
|
-
catch {
|
|
958
|
-
setError("
|
|
1237
|
+
catch (err) {
|
|
1238
|
+
setError(err instanceof Error ? err.message : "Unable to hash password");
|
|
959
1239
|
return;
|
|
960
1240
|
}
|
|
961
1241
|
setError(null);
|
|
962
|
-
|
|
1242
|
+
setSubStep("valkey-admin-allowed-ips");
|
|
1243
|
+
};
|
|
1244
|
+
const handleValkeyAdminAllowedIPsSubmit = () => {
|
|
1245
|
+
const allowedIPs = valkeyAdminAllowedIPs
|
|
1246
|
+
.split(",")
|
|
1247
|
+
.map((value) => value.trim())
|
|
1248
|
+
.filter(Boolean);
|
|
963
1249
|
dispatch({
|
|
964
|
-
type: "
|
|
965
|
-
config: {
|
|
966
|
-
loggingBucket: JSON.stringify({
|
|
967
|
-
url: elasticsearchUrl,
|
|
968
|
-
user: elasticsearchUser,
|
|
969
|
-
password: elasticsearchPass,
|
|
970
|
-
index: elasticsearchIndex,
|
|
971
|
-
}),
|
|
972
|
-
loggingRegion: elasticsearchIndex,
|
|
973
|
-
},
|
|
1250
|
+
type: "SET_EXTERNAL_SERVICES",
|
|
1251
|
+
config: { valkeyAdminAllowedIPs: allowedIPs },
|
|
974
1252
|
});
|
|
975
|
-
|
|
1253
|
+
setError(null);
|
|
1254
|
+
advanceToNext("valkey-admin-allowed-ips");
|
|
976
1255
|
};
|
|
977
1256
|
const handleLokiConfigSubmit = () => {
|
|
978
1257
|
if (!lokiUrl) {
|
|
@@ -990,8 +1269,8 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
990
1269
|
dispatch({
|
|
991
1270
|
type: "SET_LOGGING_CONFIG",
|
|
992
1271
|
config: {
|
|
993
|
-
|
|
994
|
-
|
|
1272
|
+
loggingPlatformCredential: lokiUrl,
|
|
1273
|
+
loggingPlatformDetail: "",
|
|
995
1274
|
},
|
|
996
1275
|
});
|
|
997
1276
|
advanceToNext("logging-loki-config");
|
|
@@ -1009,8 +1288,8 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
1009
1288
|
dispatch({
|
|
1010
1289
|
type: "SET_LOGGING_CONFIG",
|
|
1011
1290
|
config: {
|
|
1012
|
-
|
|
1013
|
-
|
|
1291
|
+
loggingPlatformCredential: newrelicLicenseKey,
|
|
1292
|
+
loggingPlatformDetail: newrelicAccountId,
|
|
1014
1293
|
},
|
|
1015
1294
|
});
|
|
1016
1295
|
advanceToNext("logging-newrelic-config");
|
|
@@ -1028,8 +1307,8 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
1028
1307
|
dispatch({
|
|
1029
1308
|
type: "SET_LOGGING_CONFIG",
|
|
1030
1309
|
config: {
|
|
1031
|
-
|
|
1032
|
-
|
|
1310
|
+
loggingPlatformCredential: axiomApiToken,
|
|
1311
|
+
loggingPlatformDetail: axiomDataset,
|
|
1033
1312
|
},
|
|
1034
1313
|
});
|
|
1035
1314
|
advanceToNext("logging-axiom-config");
|
|
@@ -1122,41 +1401,76 @@ export function FeatureConfigStep({ onComplete, onBack, }) {
|
|
|
1122
1401
|
});
|
|
1123
1402
|
advanceToNext("email-template-change");
|
|
1124
1403
|
};
|
|
1125
|
-
// Build bucket items for selection (no create option - just existing buckets)
|
|
1126
|
-
const getBucketItems = () => {
|
|
1127
|
-
return availableBuckets.map((b) => ({ label: b, value: b }));
|
|
1128
|
-
};
|
|
1129
|
-
// Get regions based on logging sink (use dynamic regions if available)
|
|
1130
|
-
const getLoggingRegions = () => {
|
|
1131
|
-
if (availableRegions.length > 0) {
|
|
1132
|
-
return availableRegions.map((r) => ({ label: r, value: r }));
|
|
1133
|
-
}
|
|
1134
|
-
const provider = sinkToProvider(loggingSink);
|
|
1135
|
-
if (!provider)
|
|
1136
|
-
return [];
|
|
1137
|
-
return CLOUD_REGIONS[provider].map((r) => ({ label: r, value: r }));
|
|
1138
|
-
};
|
|
1139
1404
|
// If nothing to configure, don't render
|
|
1140
1405
|
if (!needsAI &&
|
|
1141
1406
|
!needsSSO &&
|
|
1142
1407
|
!needsMonitoring &&
|
|
1143
1408
|
!needsLogging &&
|
|
1409
|
+
!needsTracing &&
|
|
1410
|
+
!needsAppLogs &&
|
|
1411
|
+
!needsValkeyAdmin &&
|
|
1144
1412
|
!needsCustomEmails) {
|
|
1145
1413
|
return null;
|
|
1146
1414
|
}
|
|
1415
|
+
// Shared list item renderer (matches the wizard's other select lists).
|
|
1416
|
+
const selectItem = ({ isSelected, label, }) => (_jsxs(Text, { color: isSelected ? colors.accent : undefined, children: [isSelected ? "❯ " : " ", label] }));
|
|
1147
1417
|
// Progress summary
|
|
1148
1418
|
const ProgressSummary = () => (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [state.openaiApiKey && (_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsx(Text, { color: "gray", children: " OpenAI API key configured" })] })), state.ssoProvider && (_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsxs(Text, { color: "gray", children: [" SSO: ", state.ssoProvider] })] })), state.prometheusRemoteWriteUrl && (_jsxs(Box, { children: [_jsx(Text, { color: colors.success, children: "\u2713" }), _jsx(Text, { color: "gray", children: " Metrics remote write configured" })] }))] }));
|
|
1149
1419
|
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" &&
|
|
1150
1420
|
"e.g., https://login.microsoftonline.com/your-tenant-id", ssoProvider === "okta" && "e.g., https://your-org.okta.com", ssoProvider === "keycloak" &&
|
|
1151
1421
|
"e.g., https://keycloak.example.com/realms/your-realm", ssoProvider === "ory" &&
|
|
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"
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1422
|
+
"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-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-loading" && (_jsx(Box, { flexDirection: "column", marginY: 1, children: _jsx(Spinner, { label: "Loading AWS regions..." }) })), 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 of your AMP workspace (defaults to your cluster region)." }), _jsx(Box, { marginTop: 1, height: 10, flexDirection: "column", overflowY: "hidden", children: _jsx(SelectInput, { items: rwRegions.map((r) => ({ label: r, value: r })), onSelect: handleAwsRegionSelect, limit: 8, initialIndex: Math.max(0, rwRegions.indexOf(remoteWriteAwsRegion)), indicatorComponent: () => null, itemComponent: selectItem }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-aws-workspace-loading" && (_jsx(Box, { flexDirection: "column", marginY: 1, children: _jsx(Spinner, { label: "Discovering AMP workspaces..." }) })), subStep === "monitoring-aws-workspace" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Select AMP Workspace" }), _jsxs(Text, { color: "gray", dimColor: true, children: ["Choose the workspace your Rulebricks role can write to. cluster-setup creates ", `${state.clusterName || "<cluster>"}-amp`, " and grants aps:RemoteWrite on it."] }), rwTargets.length === 0 && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: ["None found in ", remoteWriteAwsRegion, ". Refresh after creating one, or enter a URL manually."] }) })), (() => {
|
|
1423
|
+
const recommendedPrefix = `${state.clusterName || ""}-amp`.toLowerCase();
|
|
1424
|
+
const isRec = (name) => recommendedPrefix !== "-amp" &&
|
|
1425
|
+
name.toLowerCase().startsWith(recommendedPrefix);
|
|
1426
|
+
const sorted = [...rwTargets].sort((a, b) => {
|
|
1427
|
+
return ((isRec(a.name) ? 0 : 1) - (isRec(b.name) ? 0 : 1) ||
|
|
1428
|
+
a.name.localeCompare(b.name));
|
|
1429
|
+
});
|
|
1430
|
+
return (_jsx(Box, { marginTop: 1, height: 10, flexDirection: "column", overflowY: "hidden", children: _jsx(SelectInput, { items: [
|
|
1431
|
+
...sorted.map((t) => ({
|
|
1432
|
+
label: isRec(t.name) ? `${t.name} - recommended` : t.name,
|
|
1433
|
+
value: t.url,
|
|
1434
|
+
})),
|
|
1435
|
+
{ label: "↻ Refresh list", value: REFRESH },
|
|
1436
|
+
{ label: "Enter URL manually…", value: MANUAL },
|
|
1437
|
+
], onSelect: handleAwsWorkspaceSelect, limit: 8, indicatorComponent: () => null, itemComponent: selectItem }) }));
|
|
1438
|
+
})(), _jsx(ProgressSummary, {})] })), subStep === "monitoring-azure-target-loading" && (_jsx(Box, { flexDirection: "column", marginY: 1, children: _jsx(Spinner, { label: "Discovering Azure Monitor data collection rules..." }) })), subStep === "monitoring-azure-target" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Select Azure Monitor target" }), _jsxs(Text, { color: "gray", dimColor: true, children: ["Choose the Data Collection Rule your Rulebricks identity can publish to. cluster-setup grants that on ", `${state.clusterName || "<cluster>"}-dcr`, "; the workspace's auto-created ", `${state.clusterName || "<cluster>"}-amw`, " rule usually lacks the publish role."] }), rwTargets.length === 0 && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: "None found. Refresh after creating a Prometheus DCR/DCE, or enter a URL manually." }) })), (() => {
|
|
1439
|
+
// Recommend the cluster-setup DCR (<cluster>-dcr) -- the one granted
|
|
1440
|
+
// Monitoring Metrics Publisher -- and list it first.
|
|
1441
|
+
const recommendedName = `${state.clusterName || ""}-dcr`.toLowerCase();
|
|
1442
|
+
const sorted = [...rwTargets].sort((a, b) => {
|
|
1443
|
+
const aRec = a.name.toLowerCase() === recommendedName ? 0 : 1;
|
|
1444
|
+
const bRec = b.name.toLowerCase() === recommendedName ? 0 : 1;
|
|
1445
|
+
return aRec - bRec || a.name.localeCompare(b.name);
|
|
1446
|
+
});
|
|
1447
|
+
return (_jsx(Box, { marginTop: 1, height: 10, flexDirection: "column", overflowY: "hidden", children: _jsx(SelectInput, { items: [
|
|
1448
|
+
...sorted.map((t) => ({
|
|
1449
|
+
label: t.name.toLowerCase() === recommendedName
|
|
1450
|
+
? `${t.name} - recommended`
|
|
1451
|
+
: t.name,
|
|
1452
|
+
value: t.url,
|
|
1453
|
+
})),
|
|
1454
|
+
{ label: "↻ Refresh list", value: REFRESH },
|
|
1455
|
+
{ label: "Enter URL manually…", value: MANUAL },
|
|
1456
|
+
], onSelect: handleAzureTargetSelect, limit: 8, indicatorComponent: () => null, itemComponent: selectItem }) }));
|
|
1457
|
+
})(), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-destination" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Metrics Export Destination" }), _jsx(Text, { color: "gray", dimColor: true, children: "Select the backend to send Prometheus metrics to so required auth fields can be collected." }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: remoteWriteDestinations, onSelect: handleRemoteWriteDestinationSelect, indicatorComponent: () => null, itemComponent: selectItem }) }), _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: selectItem }) }), _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: selectItem }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-azure-identity-loading" && (_jsx(Box, { flexDirection: "column", marginY: 1, children: _jsx(Spinner, { label: "Loading managed identities..." }) })), subStep === "monitoring-remote-write-client-id" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Azure Identity" }), _jsx(Text, { color: "gray", dimColor: true, children: "Select the managed/workload identity for remote_write, or enter a client ID manually." }), _jsx(Box, { marginTop: 1, height: 10, flexDirection: "column", overflowY: "hidden", children: _jsx(SelectInput, { items: [
|
|
1458
|
+
...rwIdentities.map((i) => ({
|
|
1459
|
+
label: `${i.name} (${i.clientId})`,
|
|
1460
|
+
value: i.clientId,
|
|
1461
|
+
})),
|
|
1462
|
+
{ label: "Enter manually…", value: MANUAL },
|
|
1463
|
+
], onSelect: handleRemoteWriteClientIdSelect, limit: 8, initialIndex: Math.max(0, findClusterSetupDefaultIndex(rwIdentities.map((i) => i.name), "metrics-identity", { provider: "azure", clusterName: state.clusterName })), indicatorComponent: () => null, itemComponent: selectItem }) }), _jsx(ProgressSummary, {})] })), subStep === "monitoring-remote-write-client-id-manual" && (_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: rwTenantAutoDetected
|
|
1464
|
+
? "Auto-detected from your Azure CLI session - edit if needed."
|
|
1465
|
+
: "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-sink" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Additional Log Forwarding" }), _jsx(Text, { color: "gray", dimColor: true, children: "Optional: forward a copy of logs to a third-party logging platform. Decision logs are always archived to your object storage (configured in the Object Storage step); this is an additional destination." }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: LOGGING_PLATFORM_SINKS, onSelect: handleLoggingSinkSelect, indicatorComponent: () => null, itemComponent: selectItem }) }), _jsx(ProgressSummary, {})] })), 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: selectItem })] }), _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
|
|
1160
1466
|
? "→ Press Enter to continue"
|
|
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" }) })] }));
|
|
1467
|
+
: "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] })] })] })] })), subStep === "tracing-destination" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Distributed Tracing - destination" }), _jsx(Text, { color: "gray", dimColor: true, children: "Where the in-cluster OpenTelemetry Collector exports traces. Works on AWS and Azure." }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: [
|
|
1468
|
+
{ label: "Elastic APM (Elastic Cloud / self-hosted)", value: "elastic" },
|
|
1469
|
+
{ label: "Generic OTLP/HTTP (Tempo, Honeycomb, Jaeger, ...)", value: "otlp" },
|
|
1470
|
+
{ label: "Azure Monitor / Application Insights", value: "azure-monitor" },
|
|
1471
|
+
], initialIndex: Math.max(0, ["elastic", "otlp", "azure-monitor"].indexOf(tracingDestination)), onSelect: handleTracingDestinationSelect }) })] })), subStep === "tracing-otlp-endpoint" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Distributed Tracing - OTLP/HTTP endpoint" }), _jsx(Text, { color: "gray", dimColor: true, children: "Full OTLP/HTTP traces endpoint of your backend (e.g. a Grafana Cloud OTLP gateway or Honeycomb)." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: tracingOtlpEndpoint, onChange: setTracingOtlpEndpoint, onSubmit: handleTracingOtlpEndpointSubmit, placeholder: "https://otlp-gateway.example.com/otlp" }) })] })), subStep === "tracing-otlp-auth" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Distributed Tracing - OTLP authentication" }), _jsx(Text, { color: "gray", dimColor: true, children: "How the collector authenticates to the OTLP endpoint. (For a custom header name, configure tracing in your config file.)" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: [
|
|
1472
|
+
{ label: "None", value: "none" },
|
|
1473
|
+
{ label: "Bearer token (Authorization: Bearer)", value: "bearer" },
|
|
1474
|
+
{ label: "API key (Authorization: ApiKey)", value: "api-key" },
|
|
1475
|
+
], initialIndex: Math.max(0, ["none", "bearer", "api-key"].indexOf(tracingOtlpAuthMode)), onSelect: handleTracingOtlpAuthSelect }) })] })), subStep === "tracing-otlp-cred" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Distributed Tracing - OTLP credential" }), _jsxs(Text, { color: "gray", dimColor: true, children: ["Sent as Authorization:", " ", tracingOtlpAuthMode === "api-key" ? "ApiKey" : "Bearer", " <value>."] }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: tracingOtlpToken, onChange: setTracingOtlpToken, onSubmit: handleTracingOtlpCredSubmit, placeholder: "otlp-credential", mask: "*" }) })] })), subStep === "tracing-azure-connection" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Distributed Tracing - Azure Monitor connection string" }), _jsx(Text, { color: "gray", dimColor: true, children: "Application Insights connection string (carries the ingestion endpoint + instrumentation key)." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: tracingAzureConnectionString, onChange: setTracingAzureConnectionString, onSubmit: handleTracingAzureConnectionSubmit, placeholder: "InstrumentationKey=...;IngestionEndpoint=https://...", mask: "*" }) })] })), subStep === "tracing-endpoint" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Distributed Tracing - Elastic APM endpoint" }), _jsx(Text, { color: "gray", dimColor: true, children: "OTLP endpoint of your (customer-managed) Elastic APM. The in-cluster OpenTelemetry Collector forwards traces here." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: tracingEndpoint, onChange: setTracingEndpoint, onSubmit: handleTracingEndpointSubmit, placeholder: "https://<deployment>.apm.<region>.cloud.es.io:443" }) })] })), subStep === "tracing-token" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Distributed Tracing - Elastic APM secret token" }), _jsx(Text, { color: "gray", dimColor: true, children: "Sent as Authorization: Bearer <token> to Elastic APM. (For API key auth, configure tracing in your config file instead.)" }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: tracingToken, onChange: setTracingToken, onSubmit: handleTracingTokenSubmit, placeholder: "elastic-apm-secret-token", mask: "*" }) })] })), subStep === "applogs-endpoint" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Application Log Shipping - BYO Elasticsearch endpoint" }), _jsx(Text, { color: "gray", dimColor: true, children: "Optional BYO sink via Vector. For AWS/Azure native log collection, enable the provider's cluster logging agent instead. Decision logs stay in object storage." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: appLogsEndpoint, onChange: setAppLogsEndpoint, onSubmit: handleAppLogsEndpointSubmit, placeholder: "https://<host>.es.<region>.cloud.es.io:9243" }) })] })), subStep === "applogs-user" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Application Log Shipping - Elasticsearch username" }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: appLogsUser, onChange: setAppLogsUser, onSubmit: handleAppLogsUserSubmit, placeholder: "elastic" }) })] })), subStep === "applogs-pass" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Application Log Shipping - Elasticsearch password" }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: appLogsPass, onChange: setAppLogsPass, onSubmit: handleAppLogsPassSubmit, placeholder: "password", mask: "*" }) })] })), subStep === "applogs-index" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Application Log Shipping - index name" }), _jsx(Text, { color: "gray", dimColor: true, children: "Elasticsearch index (data stream) for app logs." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: appLogsIndex, onChange: setAppLogsIndex, onSubmit: handleAppLogsIndexSubmit, placeholder: "rulebricks-app-logs" }) })] })), subStep === "valkey-admin-username" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Valkey Admin BasicAuth Username" }), _jsxs(Text, { color: "gray", dimColor: true, children: ["This username protects https://valkey.", state.domain, "."] }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: valkeyAdminUsername, onChange: setValkeyAdminUsername, onSubmit: handleValkeyAdminUsernameSubmit, placeholder: "admin" }) })] })), subStep === "valkey-admin-password" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Valkey Admin BasicAuth Password" }), _jsx(Text, { color: "gray", dimColor: true, children: "Password for accessing the Valkey Admin console. Leave empty to generate a secure value. The CLI stores only an htpasswd bcrypt hash in generated Helm values." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: valkeyAdminPassword, onChange: setValkeyAdminPassword, onSubmit: handleValkeyAdminPasswordSubmit, placeholder: "Leave empty to generate a secure value", mask: "*" }) })] })), subStep === "valkey-admin-allowed-ips" && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Valkey Admin Allowed IPs" }), _jsx(Text, { color: "gray", dimColor: true, children: "Optional comma-separated CIDR allowlist. Leave blank to allow any IP that can reach Traefik." }), _jsx(Box, { marginTop: 1, children: _jsx(TextInput, { value: valkeyAdminAllowedIPs, onChange: setValkeyAdminAllowedIPs, onSubmit: handleValkeyAdminAllowedIPsSubmit, placeholder: "203.0.113.0/24, 198.51.100.10/32" }) })] })), 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" }) })] }));
|
|
1162
1476
|
}
|