feat(09-06): MergeTab multi-file UI + PFX convert option + render tests
- actions.ts: mergeCertsAction(files, outputFormat, password?) builds FormData with
multiple file fields; delegates to postForm('merge', ...) (T-09-02/T-09-04)
- MergeTab.tsx: multi-file state (local), file input (multiple), output selector
(pem|pfx), Zusammenfuehren button disabled when < 2 files (data-testid for tests),
onOutputFormatChange callback to page.tsx for shared PasswordField visibility
- ConvertTab.tsx: gains pfx option + onTargetFormatChange callback (same pattern)
- page.tsx: lifts mergeOutputFormat + convertOutputFormat state; showPassword now
also true when active tab's output format is 'pfx'; passes callbacks to tabs
- cert-manager.test.tsx: 5 new tests — MergeTab disabled/enabled by file count,
shared PasswordField appears on pfx output, downloadBase64 called on success;
ConvertTab pfx option present; all 19/19 web tests green
- All production cert-manager files type-clean (pre-existing test type issues unchanged)
This commit is contained in:
@@ -25,6 +25,10 @@ function isPfxFile(file: File | null): boolean {
|
||||
* Layout per UI-SPEC: max-w-4xl, shared input card, tab nav, tab content card.
|
||||
* T-09-02: password lives in local React state only; never logged or placed in URLs.
|
||||
* T-09-04: all API calls via postForm() which sends credentials:'include'.
|
||||
*
|
||||
* The shared PasswordField is shown when:
|
||||
* 1. A PFX/P12 file is selected in the shared DropZone, OR
|
||||
* 2. The active tab (Merge or Convert) has PFX chosen as the output format.
|
||||
*/
|
||||
export default function CertManagerPage() {
|
||||
const t = useTranslations('certManager');
|
||||
@@ -34,7 +38,15 @@ export default function CertManagerPage() {
|
||||
const [pemText, setPemText] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
|
||||
const showPassword = isPfxFile(file);
|
||||
// Track the output format of the active Merge and Convert tabs
|
||||
// so the shared PasswordField can be shown when PFX output is chosen.
|
||||
const [mergeOutputFormat, setMergeOutputFormat] = useState('pem');
|
||||
const [convertOutputFormat, setConvertOutputFormat] = useState('pem');
|
||||
|
||||
const showPassword =
|
||||
isPfxFile(file) ||
|
||||
(activeTab === 'merge' && mergeOutputFormat === 'pfx') ||
|
||||
(activeTab === 'convert' && convertOutputFormat === 'pfx');
|
||||
|
||||
const handleFile = (selected: File) => {
|
||||
setFile(selected);
|
||||
@@ -61,16 +73,27 @@ export default function CertManagerPage() {
|
||||
};
|
||||
|
||||
const renderActiveTab = () => {
|
||||
const props = { file, pemText, password };
|
||||
switch (activeTab) {
|
||||
case 'inspect':
|
||||
return <InspectTab {...props} />;
|
||||
return <InspectTab file={file} pemText={pemText} password={password} />;
|
||||
case 'split':
|
||||
return <SplitTab {...props} />;
|
||||
return <SplitTab file={file} pemText={pemText} password={password} />;
|
||||
case 'merge':
|
||||
return <MergeTab {...props} />;
|
||||
return (
|
||||
<MergeTab
|
||||
password={password}
|
||||
onOutputFormatChange={setMergeOutputFormat}
|
||||
/>
|
||||
);
|
||||
case 'convert':
|
||||
return <ConvertTab {...props} />;
|
||||
return (
|
||||
<ConvertTab
|
||||
file={file}
|
||||
pemText={pemText}
|
||||
password={password}
|
||||
onTargetFormatChange={setConvertOutputFormat}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user