docs(07): create phase plan — 3 plans for VALID-01 and UX-01
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
---
|
||||
phase: 07-validation-ux-polish
|
||||
plan: "02"
|
||||
type: execute
|
||||
wave: 3
|
||||
depends_on:
|
||||
- "07-01"
|
||||
files_modified:
|
||||
- src/schemas/registry.ts
|
||||
- src/components/ui/FieldRenderer.tsx
|
||||
- src/components/ui/PasswordField.tsx
|
||||
- src/components/wizard/SftpAuthToggle.tsx
|
||||
- src/components/wizard/AzureAuthToggle.tsx
|
||||
autonomous: false
|
||||
requirements:
|
||||
- UX-01
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "User can click ⓘ next to the SAS URL label and read an explanation of SAS URL vs access key"
|
||||
- "User can click ⓘ next to the Access Key label and read an explanation of full account key access"
|
||||
- "User can click ⓘ on the SFTP authentication method section and read the difference between password and key-based auth"
|
||||
- "User can click ⓘ next to the OneDrive token label and read how to obtain the JSON token"
|
||||
- "Clicking ⓘ again hides the tooltip panel (toggle behavior)"
|
||||
- "All 147+ tests (including VALID-01 from Plan 01) pass after tooltip implementation"
|
||||
artifacts:
|
||||
- path: "src/schemas/registry.ts"
|
||||
provides: "tooltipText populated for azureblob.sas_url, azureblob.key, onedrive.token"
|
||||
contains: "tooltipText:"
|
||||
- path: "src/components/ui/FieldRenderer.tsx"
|
||||
provides: "ⓘ button + inline tooltip panel when field.tooltipText is present"
|
||||
contains: "showTooltip"
|
||||
- path: "src/components/ui/PasswordField.tsx"
|
||||
provides: "ⓘ button + inline tooltip panel when tooltipText prop is present"
|
||||
contains: "tooltipText"
|
||||
- path: "src/components/wizard/SftpAuthToggle.tsx"
|
||||
provides: "ⓘ button above auth method toggle with inline explanation"
|
||||
contains: "showAuthTip"
|
||||
- path: "src/components/wizard/AzureAuthToggle.tsx"
|
||||
provides: "Passes tooltipText from registry to PasswordField for sas_url and key"
|
||||
contains: "tooltipText"
|
||||
key_links:
|
||||
- from: "BACKEND_REGISTRY azureblob.sas_url.tooltipText"
|
||||
to: "AzureAuthToggle → PasswordField tooltipText prop"
|
||||
via: "BACKEND_REGISTRY.azureblob.fields.find(f => f.key === 'sas_url')?.tooltipText"
|
||||
pattern: "BACKEND_REGISTRY\\.azureblob\\.fields\\.find"
|
||||
- from: "BACKEND_REGISTRY onedrive.token.tooltipText"
|
||||
to: "FieldRenderer ⓘ button rendered"
|
||||
via: "field.tooltipText present → useState showTooltip"
|
||||
- from: "SftpAuthToggle showAuthTip state"
|
||||
to: "inline explanation panel"
|
||||
via: "useState + conditional render"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Implement UX-01: add tooltipText data to 3 registry fields, render ⓘ toggle buttons in FieldRenderer and PasswordField, wire AzureAuthToggle to pass tooltipText from the registry, and add a standalone auth-method tooltip to SftpAuthToggle.
|
||||
|
||||
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.
|
||||
</objective>
|
||||
|
||||
<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>
|
||||
|
||||
<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.md
|
||||
|
||||
<interfaces>
|
||||
<!-- Extracted from codebase + Plan 01 additions. Executor uses these directly. -->
|
||||
|
||||
After Plan 01, FieldDef in src/schemas/registry.ts:
|
||||
```typescript
|
||||
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?:
|
||||
```typescript
|
||||
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 && <p>...}).
|
||||
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 <label> element to avoid label text contamination.
|
||||
Wrap label + ⓘ button in a flex container (e.g. <div className="flex items-center gap-1">).
|
||||
aria-label on the ⓘ button: `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).
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 1: Populate tooltipText in registry + add ⓘ to FieldRenderer and PasswordField</name>
|
||||
<files>src/schemas/registry.ts, src/components/ui/FieldRenderer.tsx, src/components/ui/PasswordField.tsx</files>
|
||||
<behavior>
|
||||
- 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)
|
||||
</behavior>
|
||||
<action>
|
||||
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.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>npx vitest run src/components/wizard/RemoteConfigStep.test.tsx</automated>
|
||||
</verify>
|
||||
<done>UX-01 tests for OneDrive token ⓘ presence and toggle behavior pass. All VALID-01 tests still pass.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: Wire AzureAuthToggle to pass tooltipText + add SFTP auth-method tooltip</name>
|
||||
<files>src/components/wizard/AzureAuthToggle.tsx, src/components/wizard/SftpAuthToggle.tsx</files>
|
||||
<behavior>
|
||||
- azureblob sas_url PasswordField call in AzureAuthToggle shows ⓘ with the registry tooltipText
|
||||
- azureblob key PasswordField call in AzureAuthToggle shows ⓘ with the registry tooltipText
|
||||
- SftpAuthToggle renders a ⓘ button labeled 'More info about authentication methods' above the segmented control
|
||||
- Clicking that ⓘ shows the auth-method explanation panel
|
||||
- Clicking again hides it
|
||||
- SFTP pass and key_pem PasswordField calls do NOT get tooltipText (auth method ⓘ is above the whole toggle)
|
||||
</behavior>
|
||||
<action>
|
||||
AzureAuthToggle.tsx:
|
||||
- Import BACKEND_REGISTRY from '../schemas/registry' (or '../../schemas/registry' — verify the import path)
|
||||
- Add two lookups at the top of the component function:
|
||||
```typescript
|
||||
const sasUrlTooltip = BACKEND_REGISTRY.azureblob.fields.find(f => f.key === 'sas_url')?.tooltipText;
|
||||
const keyTooltip = BACKEND_REGISTRY.azureblob.fields.find(f => f.key === 'key')?.tooltipText;
|
||||
```
|
||||
- Pass `tooltipText={sasUrlTooltip}` to the PasswordField call for sas_url
|
||||
- Pass `tooltipText={keyTooltip}` to the PasswordField call for key
|
||||
|
||||
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.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>npx vitest run src/components/wizard/RemoteConfigStep.test.tsx</automated>
|
||||
</verify>
|
||||
<done>All UX-01 tests from Plan 00 pass (ⓘ on sas_url, key, SFTP auth method, onedrive token; toggle behavior). Full suite green: `npx vitest run`.</done>
|
||||
</task>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking">
|
||||
<name>Task 3: Human verify — tooltip toggle and inline validation in the running wizard</name>
|
||||
<what-built>
|
||||
Phase 7 complete: inline format validation on Azure account, S3 region, and GCS project number; contextual ⓘ tooltips on SAS URL, access key, SFTP auth method, and OneDrive token.
|
||||
</what-built>
|
||||
<how-to-verify>
|
||||
Start the dev server: `npm run dev` (or `npx vite`)
|
||||
|
||||
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
|
||||
</how-to-verify>
|
||||
<action>Run `npm run dev` and follow the verification steps below to confirm all tooltip and validation behaviors work in the browser.</action>
|
||||
<verify>
|
||||
<automated>npx vitest run</automated>
|
||||
</verify>
|
||||
<done>Human confirms all 4 tooltip fields show ⓘ with correct explanations, toggle works, and 3 validation fields show inline errors on bad input.</done>
|
||||
<resume-signal>Type "approved" if all tooltip and validation behaviors work correctly, or describe any issues found</resume-signal>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
1. `npx tsc --noEmit` — no TypeScript errors across all 5 modified files
|
||||
2. `npx vitest run` — full suite passes (147+ tests, 0 failures)
|
||||
3. Human verification: all 4 tooltip fields show ⓘ, toggle works, 3 validation fields show errors on bad input
|
||||
</verification>
|
||||
|
||||
<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>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/07-validation-ux-polish/07-02-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user