OPC # 0001: Extract OPC into standalone repo
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
import { useState } from 'react';
|
||||
import { Button, Intent } from '@blueprintjs/core';
|
||||
import ClientDetailsStep from './ClientDetailsStep';
|
||||
import DeploymentConfigStep from './DeploymentConfigStep';
|
||||
import ReviewStep from './ReviewStep';
|
||||
import DeploymentLiveStep from './DeploymentLiveStep';
|
||||
import { submitProvisioningJob } from '../../api/provisioningApi';
|
||||
import type { ProvisioningRequest } from '../../types/provisioning';
|
||||
|
||||
const EMPTY: ProvisioningRequest = {
|
||||
clientName: '', stateCode: '', subdomain: '', adminEmail: '',
|
||||
siteCode: '', environment: 'fdev', tier: 'Shared',
|
||||
};
|
||||
|
||||
const STEP_LABELS = ['Client Details', 'Deployment Config', 'Review', 'Deploying'];
|
||||
|
||||
interface Props {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export default function DeployWizard({ onClose }: Props) {
|
||||
const [activeStep, setActiveStep] = useState(0);
|
||||
const [formData, setFormData] = useState<ProvisioningRequest>(EMPTY);
|
||||
const [step0Valid, setStep0Valid] = useState(false);
|
||||
const [step1Valid, setStep1Valid] = useState(true); // tier has a default
|
||||
const [jobId, setJobId] = useState<string | null>(null);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [submitError, setSubmitError] = useState<string | null>(null);
|
||||
|
||||
const handleChange = (u: Partial<ProvisioningRequest>) =>
|
||||
setFormData((p) => ({ ...p, ...u }));
|
||||
|
||||
const handleDeploy = async () => {
|
||||
setSubmitting(true);
|
||||
setSubmitError(null);
|
||||
try {
|
||||
const id = await submitProvisioningJob(formData);
|
||||
setJobId(id);
|
||||
setActiveStep(3);
|
||||
} catch (e: unknown) {
|
||||
setSubmitError(e instanceof Error ? e.message : 'Deployment failed. Please try again.');
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const canGoBack = activeStep > 0 && !jobId;
|
||||
const isLastFormStep = activeStep === 2;
|
||||
|
||||
return (
|
||||
<div className="wizard-page">
|
||||
{/* Header */}
|
||||
<div className="wizard-page-header">
|
||||
<div className="wizard-page-title">
|
||||
<h2>Deploy New Client</h2>
|
||||
<p>Provision a new Clarity tenant from scratch.</p>
|
||||
</div>
|
||||
{!jobId && (
|
||||
<Button minimal icon="cross" onClick={onClose} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Step progress */}
|
||||
<div className="wizard-progress">
|
||||
{STEP_LABELS.map((label, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className={`wizard-progress-step${i === activeStep ? ' active' : i < activeStep ? ' done' : ''}`}
|
||||
>
|
||||
<div className="wizard-progress-dot">{i < activeStep ? '✓' : i + 1}</div>
|
||||
<span>{label}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Step content */}
|
||||
<div className="wizard-page-body">
|
||||
{activeStep === 0 && (
|
||||
<ClientDetailsStep
|
||||
data={formData}
|
||||
onChange={handleChange}
|
||||
signalParent={({ isValid }) => setStep0Valid(isValid)}
|
||||
/>
|
||||
)}
|
||||
{activeStep === 1 && (
|
||||
<DeploymentConfigStep
|
||||
data={formData}
|
||||
onChange={handleChange}
|
||||
signalParent={({ isValid }) => setStep1Valid(isValid)}
|
||||
/>
|
||||
)}
|
||||
{activeStep === 2 && (
|
||||
<ReviewStep data={formData} signalParent={() => {}} />
|
||||
)}
|
||||
{activeStep === 3 && jobId && (
|
||||
<DeploymentLiveStep jobId={jobId} subdomain={formData.subdomain} />
|
||||
)}
|
||||
|
||||
{submitError && (
|
||||
<p className="wizard-error" style={{ marginTop: 12 }}>{submitError}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Footer nav */}
|
||||
{activeStep < 3 && (
|
||||
<div className="wizard-page-footer">
|
||||
{canGoBack && (
|
||||
<Button text="Back" minimal icon="arrow-left" onClick={() => setActiveStep((s) => s - 1)} disabled={submitting} />
|
||||
)}
|
||||
<div style={{ flex: 1 }} />
|
||||
{activeStep === 0 && (
|
||||
<Button intent={Intent.PRIMARY} text="Next" rightIcon="arrow-right" disabled={!step0Valid} onClick={() => setActiveStep(1)} />
|
||||
)}
|
||||
{activeStep === 1 && (
|
||||
<Button intent={Intent.PRIMARY} text="Next" rightIcon="arrow-right" disabled={!step1Valid} onClick={() => setActiveStep(2)} />
|
||||
)}
|
||||
{isLastFormStep && (
|
||||
<Button intent={Intent.DANGER} text="Deploy Client" icon="cloud-upload" loading={submitting} onClick={handleDeploy} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user