16 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 07-validation-ux-polish | 02 | execute | 3 |
|
|
false |
|
|
Purpose: Users can access plain-language explanations of sensitive or confusing credential fields without leaving the wizard. Output: 5 modified files; ⓘ buttons visible on sas_url, key, onedrive token, and SFTP auth method.
<execution_context> @C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/phases/07-validation-ux-polish/07-CONTEXT.md @.planning/phases/07-validation-ux-polish/07-RESEARCH.md @.planning/phases/07-validation-ux-polish/07-01-SUMMARY.mdAfter Plan 01, FieldDef in src/schemas/registry.ts:
export interface FieldDef {
key: string;
label: string;
inputType: 'text' | 'password' | 'select' | 'toggle';
required: boolean;
placeholder?: string;
helpText?: string;
options?: { value: string; label: string }[];
validate?: { regex: RegExp; message: string };
tooltipText?: string; // Added in Plan 01 — now populate it for tooltip fields
}
Current PasswordField props (src/components/ui/PasswordField.tsx) — to add tooltipText?:
interface PasswordFieldProps {
id: string;
label: string;
error?: FieldError;
registration: UseFormRegisterReturn;
placeholder?: string;
helpText?: string;
// tooltipText?: string ← add this
}
CRITICAL pitfall: azureblob.sas_url and azureblob.key are NOT rendered through the FieldRenderer registry loop. They are rendered inside AzureAuthToggle.tsx which calls PasswordField with hardcoded props. To wire the tooltip, AzureAuthToggle must read from BACKEND_REGISTRY: BACKEND_REGISTRY.azureblob.fields.find(f => f.key === 'sas_url')?.tooltipText BACKEND_REGISTRY.azureblob.fields.find(f => f.key === 'key')?.tooltipText Then pass those strings as tooltipText prop to the respective PasswordField calls.
SFTP auth method tooltip is NOT field-level — it's a standalone explanation above the segmented control. SftpAuthToggle manages its own useState for showAuthTip. The PasswordField calls inside SftpAuthToggle for 'pass' and 'key_pem' do NOT get tooltipText.
CSS-hidden toggle pattern is established project convention (AzureAuthToggle, SftpAuthToggle use div.block/div.hidden). CONTEXT.md decision: use CSS-hidden pattern (div.hidden / div.block) for tooltip panel visibility — not conditional render with &&. Actually re-read: CONTEXT.md says "toggle state is local to the field component (no global state needed)" and research shows both CSS-hidden and conditional render work; CSS-hidden is the project convention. Use div.hidden / div.block OR useState + conditional render ({showTooltip &&
...}). Research Pattern 3 shows conditional render. Either is fine — use Claude's discretion for tooltip panel; CSS-hidden for SftpAuthToggle to stay consistent with its existing pattern.
Accessibility: the ⓘ button MUST be outside (sibling to, not inside) the element to avoid label text contamination. Wrap label + ⓘ button in a flex container (e.g.
More info about ${field.label} (for FieldRenderer/PasswordField) or 'More info about authentication methods' (for SftpAuthToggle).
⓪ icon source: use the Unicode character ⓘ (text character — no Heroicons needed, no new dependency).
Task 1: Populate tooltipText in registry + add ⓘ to FieldRenderer and PasswordField src/schemas/registry.ts, src/components/ui/FieldRenderer.tsx, src/components/ui/PasswordField.tsx - FieldRenderer renders a ⓘ button next to the label when field.tooltipText is present - Clicking ⓘ shows the tooltip panel below the input - Clicking ⓘ again hides the tooltip panel - PasswordField renders the same ⓘ + panel when tooltipText prop is provided - OneDrive token field (inputType: password, rendered via FieldRenderer → PasswordField) shows ⓘ - Fields without tooltipText show no ⓘ (no empty button rendered) Step 1 — Populate tooltipText in src/schemas/registry.ts for 3 fields:azureblob sas_url field — add:
```typescript
tooltipText: 'A SAS URL (Shared Access Signature) bundles the storage endpoint with a time-limited, scope-limited token. It grants access only to containers you specify and expires automatically. Use this if you want limited-access credentials. If you have the full account key, switch to Access Key.',
```
azureblob key field — add:
```typescript
tooltipText: 'The full storage account key grants unrestricted read/write access to all containers in the account. Keep this secret. If you only need limited access, use a SAS URL instead.',
```
onedrive token field — add:
```typescript
tooltipText: 'This is the JSON token obtained by running `rclone authorize "onedrive"` on a machine with a browser. The command opens a browser window, you authenticate, and rclone prints a JSON token — paste that entire JSON blob here.',
```
Step 2 — Update PasswordField (src/components/ui/PasswordField.tsx):
- Add `tooltipText?: string` to PasswordFieldProps interface
- Add `const [showTooltip, setShowTooltip] = useState(false)` inside the component
- Add import for useState if not already imported
- Wrap the existing `<label>` and any required star in a flex container `<div className="flex items-center gap-1">`, place the ⓘ button OUTSIDE and AFTER the label element:
```tsx
<div className="flex items-center gap-1">
<label htmlFor={id} className="text-sm font-medium text-gray-700">{label}{required star if present}</label>
{tooltipText && (
<button
type="button"
onClick={() => setShowTooltip(v => !v)}
aria-label={`More info about ${label}`}
className="text-blue-500 hover:text-blue-700 text-xs leading-none"
>
ⓘ
</button>
)}
</div>
```
- Add tooltip panel below the input (above helpText/error):
```tsx
{tooltipText && showTooltip && (
<p className="text-xs text-blue-700 bg-blue-50 border border-blue-200 rounded px-2 py-1.5 mt-1">
{tooltipText}
</p>
)}
```
Step 3 — Update FieldRenderer (src/components/ui/FieldRenderer.tsx):
- Add `const [showTooltip, setShowTooltip] = useState(false)` (one useState per FieldRenderer instance)
- Add import for useState if not already present
- For text and select input cases: apply the same pattern as PasswordField — flex container for label + ⓘ button sibling (outside label), tooltip panel below input
- For password input case: FieldRenderer calls PasswordField — pass `tooltipText={field.tooltipText}` as a prop
Note: FieldRenderer likely has a switch/if on field.inputType. Apply the ⓘ + panel to each branch (text, select), and pass tooltipText down to PasswordField for the password branch.
SftpAuthToggle.tsx:
- Add `const [showAuthTip, setShowAuthTip] = useState(false)` to the component
- Import useState if not already present (it likely already is — component uses CSS-hidden toggle state)
- Before the segmented control div (the Password / Private Key tabs), add:
```tsx
<div className="flex items-center gap-1">
<span className="text-sm font-medium text-gray-700">Authentication Method</span>
<button
type="button"
onClick={() => setShowAuthTip(v => !v)}
aria-label="More info about authentication methods"
className="text-blue-500 hover:text-blue-700 text-xs leading-none"
>
ⓘ
</button>
</div>
{showAuthTip && (
<p className="text-xs text-blue-700 bg-blue-50 border border-blue-200 rounded px-2 py-1.5 mt-1">
Password auth sends your password to the SFTP server on each connection.
Key-based auth uses a private key (more secure — the server only stores your public key).
Paste the full private key PEM content (including the -----BEGIN/END----- lines) if using key-based auth.
</p>
)}
```
- Do NOT add tooltipText to the pass or key_pem PasswordField calls inside SftpAuthToggle.
1. Go to the wizard, select Azure Blob Storage
- Type 'ABC' in Storage Account Name → expect inline error 'Must be 3–24 lowercase alphanumeric characters' after clicking Next
- Type 'mystorageaccount' → error clears
- Confirm ⓘ icon appears next to 'SAS URL' and 'Access Key' labels
- Click ⓘ on SAS URL → explanation panel appears below the field
- Click ⓘ again → explanation panel disappears
2. Select Amazon S3
- Type 'us east 1' in Region → expect inline error about valid format
- Type 'us-east-1' → error clears
3. Select Google Cloud Storage
- Type 'abc' in Project Number → expect inline error about digits only
- Type '123456789' → error clears
4. Select SFTP
- Confirm ⓘ icon appears above the Password/Private Key tabs with label 'Authentication Method ⓘ'
- Click ⓘ → explanation panel appears
- Click ⓘ again → panel disappears
5. Select OneDrive
- Confirm ⓘ icon appears next to the Token field label
- Click ⓘ → explanation of rclone authorize JSON token appears
<success_criteria>
- UX-01 tests from Plan 00 all pass (GREEN)
- All VALID-01 tests from Plan 01 still pass
- Full test suite passes with 0 regressions
- Human verifies tooltip toggle and inline validation in the running wizard UI
- Phase 7 complete — VALID-01 and UX-01 requirements satisfied </success_criteria>