Files
Ready2Blob/src/components/wizard/ReviewStep.tsx
T
kawa f6b4070ff9 feat(12-01): add semantic token classes to all step h2 headings
- BackendSelectionStep h2: text-2xl font-bold text-on-surface mb-2
- RemoteConfigStep h2: text-2xl font-bold text-on-surface mb-2
- DeploymentStep h2: text-2xl font-bold text-on-surface mb-2
- ReviewStep h2: text-2xl font-bold text-on-surface mb-2
2026-04-01 14:04:21 +02:00

158 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// src/components/wizard/ReviewStep.tsx
// Step 3 component — live preview + security gate + all download/copy actions.
// Covers CONF-02, CONF-03, DOWN-01DOWN-06, SECU-01, SECU-02.
import { useMemo, useState } from 'react';
import { useWizard } from '../../store/context';
import { MD3_BTN_FILLED, MD3_BTN_OUTLINED } from '../../styles/md3-buttons';
import {
buildRcloneConf,
buildIntuneInstall,
buildIntuneDetection,
buildRmmScript,
} from '../../generators/index';
import { OutputBlock } from './OutputBlock';
import { downloadZip } from '../../utils/downloadZip';
const PLACEHOLDER = '# Fill in the wizard steps to generate your rclone.conf';
export function ReviewStep() {
const { state, dispatch } = useWizard();
const [acknowledged, setAcknowledged] = useState(false);
// CONF-02: live preview — updates on every state change
const rcloneConf = useMemo(() => {
try {
return buildRcloneConf(state);
} catch {
return PLACEHOLDER;
}
}, [state]);
const intuneInstall = useMemo(() => {
try {
return buildIntuneInstall(state);
} catch {
return '';
}
}, [state]);
const intuneDetection = useMemo(() => {
try {
return buildIntuneDetection(state);
} catch {
return '';
}
}, [state]);
const rmmScript = useMemo(() => {
try {
return buildRmmScript(state);
} catch {
return '';
}
}, [state]);
const showIntune = state.deployment.scriptTargets.includes('intune');
const showRmm = state.deployment.scriptTargets.includes('rmm');
// DOWN-05: ZIP bundle — filtered by scriptTargets (TECH-01)
async function handleDownloadZip() {
const files: { name: string; content: string }[] = [
{ name: 'rclone.conf', content: rcloneConf },
];
if (showIntune) {
files.push({ name: 'intune-install.ps1', content: intuneInstall });
files.push({ name: 'intune-detection.ps1', content: intuneDetection });
}
if (showRmm) {
files.push({ name: 'rmm-script.ps1', content: rmmScript });
}
await downloadZip(files, 'rclone-deployment.zip');
}
return (
<div>
<h2 className="text-2xl font-bold text-on-surface mb-2">Step 4: Review &amp; Download</h2>
<p className="text-sm text-on-surface-variant mt-1 mb-4">
Review your generated files and download them. Acknowledge the security notice before
copying or downloading credentials.
</p>
{/* SECU-02: client-side only notice */}
<p className="text-sm text-success bg-success/10 rounded p-3 mb-6">
No data is sent to any server. All file generation happens in your browser.
</p>
{/* SECU-01: security acknowledgement gate */}
<div className="bg-warning/10 border border-warning rounded p-4 mb-6">
<p className="text-sm text-warning font-medium mb-2">
Security warning: generated files contain credentials in plain text.
</p>
<label className="flex items-center gap-2 text-sm text-warning cursor-pointer">
<input
type="checkbox"
checked={acknowledged}
onChange={(e) => setAcknowledged(e.target.checked)}
/>
I understand that the generated files contain credentials in plain text.
</label>
</div>
{/* Output blocks — DOWN-01 through DOWN-04, CONF-03, DOWN-06 */}
<OutputBlock
label="rclone.conf"
content={rcloneConf}
filename="rclone.conf"
disabled={!acknowledged}
/>
{showIntune && (
<OutputBlock
label="Intune Install Script"
content={intuneInstall}
filename="intune-install.ps1"
disabled={!acknowledged}
/>
)}
{showIntune && (
<OutputBlock
label="Intune Detection Script"
content={intuneDetection}
filename="intune-detection.ps1"
disabled={!acknowledged}
/>
)}
{showRmm && (
<OutputBlock
label="RMM Script"
content={rmmScript}
filename="rmm-script.ps1"
disabled={!acknowledged}
/>
)}
{/* TECH-02: Back button — dispatches SET_STEP(2) */}
<div className="flex flex-col sm:flex-row gap-3 mt-6">
<button
type="button"
onClick={() => dispatch({ type: 'SET_STEP', payload: 2 })}
className={`${MD3_BTN_OUTLINED} w-full sm:w-auto`}
>
Back
</button>
</div>
{/* DOWN-05: ZIP bundle */}
<button
type="button"
disabled={!acknowledged}
onClick={handleDownloadZip}
className={`w-full mt-4 ${MD3_BTN_FILLED}`}
>
Download All (ZIP)
</button>
</div>
);
}
export default ReviewStep;