235 lines
8.5 KiB
TypeScript
235 lines
8.5 KiB
TypeScript
// Path: Frontend/src/components/bootstrap/BootstrapWizard/BootstrapWizardDialog.tsx
|
|
|
|
import { Show, type JSX } from "solid-js";
|
|
import { Portal } from "solid-js/web";
|
|
import {
|
|
type AdminForm,
|
|
type BootstrapPersona,
|
|
bootstrapPersonaDefinitions,
|
|
type BootstrapStepDefinition,
|
|
type BootstrapStepKey,
|
|
type InstanceForm,
|
|
type ModeForm,
|
|
type StructureForm,
|
|
} from "./BootstrapWizard.data";
|
|
import { type BootstrapSubmissionState, type FieldTooltipState, type MaterializationState } from "./BootstrapWizard.hook";
|
|
import {
|
|
BootstrapAdminStep,
|
|
BootstrapFinishingState,
|
|
BootstrapInstanceStep,
|
|
BootstrapModeStep,
|
|
BootstrapPersonaStep,
|
|
BootstrapStructureStep,
|
|
BootstrapWizardProgress,
|
|
} from "./BootstrapWizard.parts";
|
|
import styles from "./BootstrapWizard.module.scss";
|
|
|
|
export type BootstrapWizardDialogProps = {
|
|
isOpen: boolean;
|
|
currentStep: BootstrapStepDefinition;
|
|
currentStepState: BootstrapSubmissionState;
|
|
activeWizardSteps: readonly BootstrapStepDefinition[];
|
|
currentWizardStepIndex: number;
|
|
stepState: Record<BootstrapStepKey, BootstrapSubmissionState>;
|
|
bootstrapStepCount: number;
|
|
wizardProgressFillWidth: string;
|
|
showBootstrapFinishingState: boolean;
|
|
materializationState: MaterializationState;
|
|
materializationStatusLabel: string;
|
|
materializationMessage: string;
|
|
isMaterializationInFlight: boolean;
|
|
hasMaterializationFailed: boolean;
|
|
instanceForm: InstanceForm;
|
|
modeForm: ModeForm;
|
|
adminForm: AdminForm;
|
|
structureForm: StructureForm;
|
|
selectedPersona: BootstrapPersona;
|
|
hasChosenPersona: boolean;
|
|
selectedPersonaIsAvailable: boolean;
|
|
usesCondensedBootstrapFlow: boolean;
|
|
bootstrapNamePlaceholder: string;
|
|
isFirstStep: boolean;
|
|
canDismissWizard: boolean;
|
|
fieldTooltip: FieldTooltipState | null;
|
|
onClose: () => void;
|
|
onCloseFinishingState: () => void;
|
|
onSubmit: JSX.EventHandlerUnion<HTMLFormElement, SubmitEvent>;
|
|
onSelectPersona: (persona: BootstrapPersona) => void;
|
|
onProtocolChange: (value: InstanceForm["protocol"]) => void;
|
|
onAccessChange: (value: InstanceForm["access"]) => void;
|
|
onHostChange: (value: string) => void;
|
|
onModeNameChange: (value: string) => void;
|
|
onProjectNameChange: (value: string) => void;
|
|
onTeamNameChange: (value: string) => void;
|
|
onAdminDisplayNameChange: (value: string) => void;
|
|
onAdminEmailChange: (value: string) => void;
|
|
onAdminPasswordChange: (value: string) => void;
|
|
onDepartmentNameChange: (value: string) => void;
|
|
onShowTooltip: (target: HTMLElement, text: string) => void;
|
|
onHideTooltip: () => void;
|
|
statusLabel: (state: BootstrapSubmissionState) => string;
|
|
stepStatusLabel: (step: BootstrapStepDefinition) => string;
|
|
onNavigateBack: () => void;
|
|
onSelectStep: (index: number) => void;
|
|
};
|
|
|
|
export const BootstrapWizardDialog = (props: BootstrapWizardDialogProps): JSX.Element => (
|
|
<Show when={props.isOpen}>
|
|
<Portal>
|
|
<div class={styles.wizardLayer} data-ui="bootstrap-wizard" data-step={props.currentStep.id}>
|
|
<div class={styles.wizardBackdrop} aria-hidden="true" />
|
|
|
|
<section class={styles.wizardPanel} role="dialog" aria-modal="true" aria-labelledby="bootstrap-wizard-title" data-slot="bootstrap-wizard-panel">
|
|
<header class={styles.wizardHeader} data-slot="bootstrap-wizard-header">
|
|
<div class={styles.wizardHeaderCopy}>
|
|
<h2 id="bootstrap-wizard-title" class={styles.wizardTitle}>
|
|
Bootstrap Server
|
|
</h2>
|
|
</div>
|
|
<Show when={props.canDismissWizard}>
|
|
<button type="button" class={styles.wizardCloseButton} onClick={props.onClose}>
|
|
Close
|
|
</button>
|
|
</Show>
|
|
</header>
|
|
|
|
<Show
|
|
when={!props.showBootstrapFinishingState}
|
|
fallback={
|
|
<BootstrapFinishingState
|
|
materializationState={props.materializationState}
|
|
statusLabel={props.materializationStatusLabel}
|
|
message={props.materializationMessage}
|
|
isInFlight={props.isMaterializationInFlight}
|
|
hasFailed={props.hasMaterializationFailed}
|
|
onClose={props.onCloseFinishingState}
|
|
/>
|
|
}
|
|
>
|
|
<div class={styles.wizardBody}>
|
|
<Show when={props.currentStep.id !== "persona"}>
|
|
<BootstrapWizardProgress
|
|
steps={props.activeWizardSteps}
|
|
currentStepId={props.currentStep.id}
|
|
currentWizardStepIndex={props.currentWizardStepIndex}
|
|
stepState={props.stepState}
|
|
bootstrapStepCount={props.bootstrapStepCount}
|
|
wizardProgressFillWidth={props.wizardProgressFillWidth}
|
|
stepStatusLabel={props.stepStatusLabel}
|
|
onSelectStep={props.onSelectStep}
|
|
/>
|
|
</Show>
|
|
|
|
<div class={styles.wizardStepPanel} data-slot="bootstrap-wizard-step-panel">
|
|
<Show when={props.currentStep.id !== "persona" || props.statusLabel(props.currentStepState)}>
|
|
<div class={styles.sectionHeader}>
|
|
<Show when={props.currentStep.id !== "persona"}>
|
|
<div>
|
|
<span class={styles.wizardStepEyebrow}>{`Step ${props.currentWizardStepIndex + 1} of ${props.bootstrapStepCount}`}</span>
|
|
</div>
|
|
</Show>
|
|
<Show when={props.statusLabel(props.currentStepState)}>
|
|
<div class={styles.statusBadge} data-status={props.currentStepState.status}>
|
|
{props.statusLabel(props.currentStepState)}
|
|
</div>
|
|
</Show>
|
|
</div>
|
|
</Show>
|
|
|
|
<form class={styles.form} onSubmit={props.onSubmit}>
|
|
<Show when={props.currentStep.id === "persona"}>
|
|
<BootstrapPersonaStep
|
|
personas={bootstrapPersonaDefinitions}
|
|
hasChosenPersona={props.hasChosenPersona}
|
|
selectedPersona={props.selectedPersona}
|
|
selectedPersonaIsAvailable={props.selectedPersonaIsAvailable}
|
|
onSelectPersona={props.onSelectPersona}
|
|
/>
|
|
</Show>
|
|
|
|
<Show when={props.currentStep.id === "instance"}>
|
|
<BootstrapInstanceStep
|
|
instanceForm={props.instanceForm}
|
|
onProtocolChange={props.onProtocolChange}
|
|
onAccessChange={props.onAccessChange}
|
|
onHostChange={props.onHostChange}
|
|
onShowTooltip={props.onShowTooltip}
|
|
onHideTooltip={props.onHideTooltip}
|
|
/>
|
|
</Show>
|
|
|
|
<Show when={props.currentStep.id === "mode"}>
|
|
<BootstrapModeStep
|
|
modeForm={props.modeForm}
|
|
structureForm={props.structureForm}
|
|
usesCondensedBootstrapFlow={props.usesCondensedBootstrapFlow}
|
|
selectedPersona={props.selectedPersona}
|
|
namePlaceholder={props.bootstrapNamePlaceholder}
|
|
onNameChange={props.onModeNameChange}
|
|
onProjectNameChange={props.onProjectNameChange}
|
|
onTeamNameChange={props.onTeamNameChange}
|
|
onShowTooltip={props.onShowTooltip}
|
|
onHideTooltip={props.onHideTooltip}
|
|
/>
|
|
</Show>
|
|
|
|
<Show when={props.currentStep.id === "admin"}>
|
|
<BootstrapAdminStep
|
|
adminForm={props.adminForm}
|
|
onDisplayNameChange={props.onAdminDisplayNameChange}
|
|
onEmailChange={props.onAdminEmailChange}
|
|
onPasswordChange={props.onAdminPasswordChange}
|
|
/>
|
|
</Show>
|
|
|
|
<Show when={props.currentStep.id === "structure"}>
|
|
<BootstrapStructureStep
|
|
mode={props.modeForm.mode}
|
|
structureForm={props.structureForm}
|
|
onDepartmentNameChange={props.onDepartmentNameChange}
|
|
onTeamNameChange={props.onTeamNameChange}
|
|
onProjectNameChange={props.onProjectNameChange}
|
|
onShowTooltip={props.onShowTooltip}
|
|
onHideTooltip={props.onHideTooltip}
|
|
/>
|
|
</Show>
|
|
|
|
<Show when={props.currentStep.id !== "persona"}>
|
|
<div class={styles.wizardFormActions}>
|
|
<button type="button" class={styles.secondaryButton} disabled={props.isFirstStep} onClick={props.onNavigateBack}>
|
|
Back
|
|
</button>
|
|
<button type="submit" class={styles.primaryButton} disabled={props.currentStepState.status === "submitting"}>
|
|
{props.currentStep.buttonLabel}
|
|
</button>
|
|
</div>
|
|
</Show>
|
|
</form>
|
|
|
|
<Show when={props.currentStepState.error}>
|
|
<p class={styles.errorText}>{props.currentStepState.error}</p>
|
|
</Show>
|
|
</div>
|
|
</div>
|
|
</Show>
|
|
</section>
|
|
|
|
<Show when={props.fieldTooltip}>
|
|
{(tooltip): JSX.Element => (
|
|
<div
|
|
class={styles.fieldTooltip}
|
|
data-placement={tooltip().placement}
|
|
style={{
|
|
left: `${tooltip().left}px`,
|
|
top: `${tooltip().top}px`,
|
|
}}
|
|
>
|
|
<div class={styles.fieldTooltipBubble}>{tooltip().text}</div>
|
|
</div>
|
|
)}
|
|
</Show>
|
|
</div>
|
|
</Portal>
|
|
</Show>
|
|
);
|