in packages/online-editor/src/accounts/kubernetes/ConnectToLocalKubernetesClusterWizard.tsx [113:488]
export function ConnectToLocalKubernetesClusterWizard(props: {
kieSandboxKubernetesService?: KieSandboxKubernetesService;
setMode: React.Dispatch<React.SetStateAction<KubernetesSettingsTabMode>>;
connection: KubernetesConnection;
setConnection: React.Dispatch<React.SetStateAction<KubernetesConnection>>;
status: KubernetesInstanceStatus;
setStatus: React.Dispatch<React.SetStateAction<KubernetesInstanceStatus>>;
setNewAuthSession: React.Dispatch<React.SetStateAction<KubernetesAuthSession>>;
isLoadingService: boolean;
}) {
const { i18n } = useOnlineI18n();
const routes = useRoutes();
const [isConnectionValidated, setConnectionValidated] = useState(false);
const [isConnecting, setConnecting] = useState(false);
const [isConnectLoading, setConnectLoading] = useState(false);
const authSessionsDispatch = useAuthSessionsDispatch();
const [operatingSystem, setOperatingSystem] = useState(getOperatingSystem() ?? OperatingSystem.LINUX);
const [kubernetesFlavor, setKubernetesFlavor] = useState<KubernetesFlavor>(KubernetesFlavor.KIND);
const [previousConnection, setPreviousConnection] = useState<KubernetesConnection>();
const onClearHost = useCallback(() => props.setConnection({ ...props.connection, host: "" }), [props]);
const onClearNamespace = useCallback(() => props.setConnection({ ...props.connection, namespace: "" }), [props]);
const onClearToken = useCallback(() => props.setConnection({ ...props.connection, token: "" }), [props]);
const clusterConfigCommands: ClusterConfigCommands = useMemo(() => {
if (kubernetesFlavor === KubernetesFlavor.KIND) {
return {
createCluster:
operatingSystem === OperatingSystem.WINDOWS
? COMMANDS.kindCreateClusterWindows
: COMMANDS.kindCreateClusterUnix,
applyAndWaitIngress: () =>
operatingSystem === OperatingSystem.WINDOWS
? `${COMMANDS.kindApplyIngress()}; ${COMMANDS.sleep()}; ${COMMANDS.waitForIngress()}`
: `${COMMANDS.kindApplyIngress()} && ${COMMANDS.sleep()} && ${COMMANDS.waitForIngress()}`,
applyDeploymentResources:
operatingSystem === OperatingSystem.WINDOWS
? COMMANDS.applyDeploymentResourcesWindows
: COMMANDS.applyDeploymentResourcesUnix,
getSecret: operatingSystem === OperatingSystem.WINDOWS ? COMMANDS.getSecretWindows : COMMANDS.getSecretUnix,
};
} else {
return {
createCluster: COMMANDS.minikubeCreateCluster,
applyAndWaitIngress: () =>
operatingSystem === OperatingSystem.WINDOWS
? `${COMMANDS.minikubeApllyIngress()}; ${COMMANDS.sleep()}; ${COMMANDS.waitForIngress()}`
: `${COMMANDS.minikubeApllyIngress()} && ${COMMANDS.sleep()} && ${COMMANDS.waitForIngress()}`,
applyDeploymentResources:
operatingSystem === OperatingSystem.WINDOWS
? COMMANDS.applyDeploymentResourcesWindows
: COMMANDS.applyDeploymentResourcesUnix,
getSecret: operatingSystem === OperatingSystem.WINDOWS ? COMMANDS.getSecretWindows : COMMANDS.getSecretUnix,
};
}
}, [kubernetesFlavor, operatingSystem]);
useEffect(() => {
setPreviousConnection(props.connection);
props.setConnection({
namespace: DEFAULT_LOCAL_CLUSTER_NAMESPACE,
host: DEFAULT_LOCAL_CLUSTER_HOST,
token: "",
insecurelyDisableTlsCertificateValidation: false,
});
}, []);
const isNamespaceValidated = useMemo(() => {
return isNamespaceValid(props.connection.namespace);
}, [props.connection.namespace]);
const isHostValidated = useMemo(() => {
return isHostValid(props.connection.host);
}, [props.connection.host]);
const isTokenValidated = useMemo(() => {
return isTokenValid(props.connection.token);
}, [props.connection.token]);
useEffect(() => {
setConnectionValidated(isKubernetesConnectionValid(props.connection));
}, [props.connection]);
const onCancel = useCallback(() => {
if (previousConnection) {
props.setConnection(previousConnection);
}
props.setMode(KubernetesSettingsTabMode.SIMPLE);
}, [props, previousConnection]);
const onNamespaceInputChanged = useCallback(
(event: React.FormEvent<HTMLInputElement>, newValue: string) => {
props.setConnection((c) => ({ ...c, namespace: newValue }));
},
[props]
);
const onHostInputChanged = useCallback(
(event: React.FormEvent<HTMLInputElement>, newValue: string) => {
props.setConnection((c) => ({ ...c, host: newValue }));
},
[props]
);
const onTokenInputChanged = useCallback(
(event: React.FormEvent<HTMLInputElement>, newValue: string) => {
props.setConnection((c) => ({ ...c, token: newValue }));
},
[props]
);
/*
TODO: uncomment when enabling kubernetes deployment to use cors-proxy
const onInsecurelyDisableTlsCertificateValidationChange = useCallback((checked: boolean) => {
props.setConnection({ ...props.connection, insecurelyDisableTlsCertificateValidation: checked });
}, [props]); */
const onStepChanged = useCallback(
async ({ id }) => {
if (id === WizardStepIds.CONNECT) {
setConnectLoading(true);
setConnectionValidated(
(props.kieSandboxKubernetesService && (await props.kieSandboxKubernetesService.isConnectionEstablished())) ===
KubernetesConnectionStatus.CONNECTED
);
setConnectLoading(false);
}
},
[props.kieSandboxKubernetesService]
);
const onSave = useCallback(async () => {
if (isConnecting) {
return;
}
if (!isKubernetesConnectionValid(props.connection)) {
return;
}
setConnecting(true);
const isConnectionEstablished =
props.kieSandboxKubernetesService && (await props.kieSandboxKubernetesService.isConnectionEstablished());
setConnecting(false);
if (isConnectionEstablished === KubernetesConnectionStatus.CONNECTED && props.kieSandboxKubernetesService) {
const newAuthSession: KubernetesAuthSession = {
type: CloudAuthSessionType.Kubernetes,
version: AUTH_SESSION_VERSION_NUMBER,
id: uuid(),
...props.connection,
authProviderId: "kubernetes",
createdAtDateISO: new Date().toISOString(),
k8sApiServerEndpointsByResourceKind: props.kieSandboxKubernetesService.args.k8sApiServerEndpointsByResourceKind,
};
setConnectionValidated(true);
props.setStatus(KubernetesInstanceStatus.CONNECTED);
authSessionsDispatch.add(newAuthSession);
props.setNewAuthSession(newAuthSession);
} else {
setConnectionValidated(false);
return;
}
}, [authSessionsDispatch, isConnecting, props]);
const firstStepContent = useMemo(
() => (
<>
<br />
<List component={ListComponent.ol} type={OrderType.number} className="pf-v5-u-mt-md">
<ListItem>
<TextContent>
<Text component={TextVariants.p}>
<a href={FLAVOR_INSTALL_DOCS[kubernetesFlavor]} target={"_blank"} rel="noreferrer">
{i18n.devDeployments.kubernetesConfigWizard.steps.first.installFlavor(kubernetesFlavor)}
<ExternalLinkAltIcon className="pf-v5-u-mx-sm" />
</a>
</Text>
</TextContent>
</ListItem>
<ListItem>
<TextContent>
<Text component={TextVariants.p}>
<a href={KUBECTL_INSTALL_DOCS[operatingSystem]} target={"_blank"} rel="noreferrer">
{i18n.devDeployments.kubernetesConfigWizard.steps.first.installKubectl}
<ExternalLinkAltIcon className="pf-v5-u-mx-sm" />
</a>
</Text>
</TextContent>
</ListItem>
<ListItem>
<TextContent>
<Text component={TextVariants.p}>
{i18n.devDeployments.kubernetesConfigWizard.steps.first.runCommandsTerminal}
</Text>
</TextContent>
<List component={ListComponent.ol} type={OrderType.lowercaseLetter}>
<ListItem>
<TextContent>
<Text component={TextVariants.p}>
{i18n.devDeployments.kubernetesConfigWizard.steps.first.createCluster}
</Text>
</TextContent>
<CommandCopyBlock
command={clusterConfigCommands.createCluster(
`${window.location.origin}${
window.location.pathname
}${routes.static.devDeployments.kubernetes.clusterConfig.kindClusterConfig.path({})}`
)}
/>
</ListItem>
<ListItem>
<TextContent>
<Text component={TextVariants.p}>
{i18n.devDeployments.kubernetesConfigWizard.steps.first.installIngress}
</Text>
</TextContent>
<CommandCopyBlock command={clusterConfigCommands.applyAndWaitIngress()} />
</ListItem>
<ListItem>
<TextContent>
<Text component={TextVariants.p}>
{i18n.devDeployments.kubernetesConfigWizard.steps.first.installKieSandboxYaml}
</Text>
</TextContent>
<CommandCopyBlock
command={clusterConfigCommands.applyDeploymentResources(
`${window.location.origin}${
window.location.pathname
}${routes.static.devDeployments.kubernetes.clusterConfig.kieSandboxDevDeploymentsResources.path(
{}
)}`
)}
/>
</ListItem>
</List>
</ListItem>
</List>
</>
),
[
clusterConfigCommands,
i18n.devDeployments.kubernetesConfigWizard.steps.first,
kubernetesFlavor,
operatingSystem,
routes.static.devDeployments.kubernetes.clusterConfig,
]
);
const wizardSteps = useMemo(
() => [
{
id: WizardStepIds.CREATE_CLUSTER,
name: i18n.devDeployments.kubernetesConfigWizard.steps.first.name,
component: (
<div>
<Text component={TextVariants.p}>
{i18n.devDeployments.kubernetesConfigWizard.steps.first.introduction}
</Text>
<Tabs
activeKey={kubernetesFlavor}
onSelect={(_, flavor) => setKubernetesFlavor(flavor as KubernetesFlavor)}
isVertical={false}
isBox={false}
>
<Tab
className="kie-tools--settings-tab"
eventKey={KubernetesFlavor.KIND}
title={<TabTitleText>Kind</TabTitleText>}
>
{firstStepContent}
</Tab>
<Tab
className="kie-tools--settings-tab"
eventKey={KubernetesFlavor.MINIKUBE}
title={<TabTitleText>Minikube</TabTitleText>}
>
{firstStepContent}
</Tab>
</Tabs>
</div>
),
},
{
id: WizardStepIds.CONNECTION_INFO,
name: i18n.devDeployments.kubernetesConfigWizard.steps.second.name,
component: (
<div>
<Text component={TextVariants.p}>
{i18n.devDeployments.kubernetesConfigWizard.steps.second.introduction}
</Text>
<Text component={TextVariants.small} style={{ color: "var(--pf-v5-global--palette--red-100)" }}>
{i18n.devDeployments.kubernetesConfigWizard.steps.second.disclaimer}
</Text>
<br />
<br />
<Form className="pf-v5-u-mt-md" onSubmit={(e) => e.preventDefault()}>
<FormGroup
fieldId={"dev-deployments-config-namespace"}
label={i18n.devDeployments.kubernetesConfigWizard.fields.namespace}
isRequired={true}
>
<InputGroup>
<InputGroupItem isFill>
<TextInput
autoFocus={true}
autoComplete={"off"}
type="text"
id="namespace-field"
name="namespace-field"
aria-label="namespace field"
value={props.connection.namespace}
placeholder={i18n.devDeployments.kubernetesConfigWizard.steps.second.namespacePlaceholder}
onChange={onNamespaceInputChanged}
/>
</InputGroupItem>
<InputGroupText>
<Button size="sm" variant="plain" aria-label="Clear namespace button" onClick={onClearNamespace}>
<TimesIcon />
</Button>
</InputGroupText>
</InputGroup>
<HelperText>
{isNamespaceValidated === true ? (
<HelperTextItem variant="error">{i18n.devDeployments.common.requiredField}</HelperTextItem>
) : (
<HelperTextItem icon={ValidatedOptions.success}></HelperTextItem>
)}
</HelperText>
</FormGroup>
<Text component={TextVariants.p}>
{i18n.devDeployments.kubernetesConfigWizard.steps.second.namespaceInputReason}
</Text>
<FormGroup
fieldId={"dev-deployments-config-host"}
label={i18n.devDeployments.kubernetesConfigWizard.fields.kubernetesApiServerUrl}
isRequired={true}
>
<InputGroup>
<InputGroupItem isFill>
<TextInput
autoFocus={true}
autoComplete={"off"}
isRequired
type="text"
id="host-field"
name="host-field"
aria-label="Host field"
value={props.connection.host}
placeholder={i18n.devDeployments.kubernetesConfigWizard.steps.second.hostPlaceholder}
onChange={onHostInputChanged}
/>
</InputGroupItem>
<InputGroupText>
<Button size="sm" variant="plain" aria-label="Clear host button" onClick={onClearHost}>
<TimesIcon />
</Button>
</InputGroupText>
</InputGroup>
<HelperText>
{isHostValidated === true ? (
<HelperTextItem variant="error">{i18n.devDeployments.common.requiredField}</HelperTextItem>
) : (
<HelperTextItem icon={ValidatedOptions.success}></HelperTextItem>
)}
</HelperText>
</FormGroup>
<Text component={TextVariants.p}>
{i18n.devDeployments.kubernetesConfigWizard.steps.second.hostInputReason}
</Text>
</Form>
</div>
),
},