Files
Ready2Blob/.planning/phases/13-add-remaining-rclone-remotes/13-04-PLAN.md
T
kawaandClaude Opus 4.6 4bf3f1e45f docs(13): create phase plan for backend expansion
4 plans across 3 waves to expand from 7 to 17 rclone backends:
- Plan 01 (W1): Registry refactoring, BackendType derivation, 10 new entries
- Plan 02 (W2): OAuthInstructions, GdriveAuthToggle, BackendIcons components
- Plan 03 (W2): BackendSelectionStep UX overhaul with categories, search, icons
- Plan 04 (W3): RemoteConfigStep wiring for all new backends + visual verify

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 15:58:51 +02:00

279 lines
12 KiB
Markdown

---
phase: 13-add-remaining-rclone-remotes
plan: 04
type: execute
wave: 3
depends_on: [13-01, 13-02, 13-03]
files_modified:
- src/components/wizard/RemoteConfigStep.tsx
- src/components/wizard/RemoteConfigStep.test.tsx
autonomous: false
requirements: [REMOTE-05]
must_haves:
truths:
- "RemoteConfigStep renders correct form fields for every new backend"
- "Google Drive shows GdriveAuthToggle with OAuth Token and Service Account tabs"
- "Dropbox, Box, pCloud show OAuthInstructions + token field"
- "FTP, WebDAV, SMB, HTTP, Seafile, Azure Files, Swift render via generic FieldRenderer loop"
- "backendLabel is derived from registry displayName (not duplicated)"
- "All form submissions produce correct remote params"
artifacts:
- path: "src/components/wizard/RemoteConfigStep.tsx"
provides: "Form rendering for all 17 backends"
- path: "src/components/wizard/RemoteConfigStep.test.tsx"
provides: "Tests for new backend form rendering"
key_links:
- from: "src/components/wizard/RemoteConfigStep.tsx"
to: "src/components/wizard/GdriveAuthToggle.tsx"
via: "import and render for gdrive backend"
pattern: "GdriveAuthToggle"
- from: "src/components/wizard/RemoteConfigStep.tsx"
to: "src/components/wizard/OAuthInstructions.tsx"
via: "import and render for OAuth backends"
pattern: "OAuthInstructions"
- from: "src/components/wizard/RemoteConfigStep.tsx"
to: "src/schemas/registry.ts"
via: "BACKEND_REGISTRY field lookup"
pattern: "BACKEND_REGISTRY\\["
---
<objective>
Wire all 10 new backends into RemoteConfigStep so every backend type renders the correct configuration form with appropriate auth handling (AuthToggle, OAuthInstructions, or generic FieldRenderer loop).
Purpose: This is the final integration plan — connecting registry data to the form UI. After this, every backend is fully functional end-to-end.
Output: Updated RemoteConfigStep with all backend branches, updated tests, visual verification.
</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/13-add-remaining-rclone-remotes/13-CONTEXT.md
@.planning/phases/13-add-remaining-rclone-remotes/13-RESEARCH.md
@.planning/phases/13-add-remaining-rclone-remotes/13-01-SUMMARY.md
@.planning/phases/13-add-remaining-rclone-remotes/13-02-SUMMARY.md
@.planning/phases/13-add-remaining-rclone-remotes/13-03-SUMMARY.md
<interfaces>
<!-- From Plan 01: Registry with 17 backends -->
From src/schemas/registry.ts:
```typescript
export type BackendType = keyof typeof BACKEND_REGISTRY;
// Includes: azureblob, s3, s3-compatible, onedrive, sftp, gcs, b2,
// azure-files, swift, gdrive, dropbox, box, pcloud,
// ftp, webdav, smb, http, seafile
```
<!-- From Plan 02: New components -->
From src/components/wizard/OAuthInstructions.tsx:
```typescript
interface OAuthInstructionsProps {
backendName: string;
authorizeCommand: string;
steps?: string[];
}
```
From src/components/wizard/GdriveAuthToggle.tsx:
```typescript
interface GdriveAuthToggleProps {
register: UseFormRegister<any>;
errors: {
token?: FieldError;
service_account_credentials?: FieldError;
};
}
```
<!-- Current RemoteConfigStep pattern -->
From src/components/wizard/RemoteConfigStep.tsx:
```typescript
// Three-branch ternary: azureblob -> AzureAuthToggle, sftp -> SftpAuthToggle, else -> generic loop
// backendLabel: Record<NonNullable<typeof backendType>, string> — manual duplication
```
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Wire all new backends into RemoteConfigStep</name>
<files>src/components/wizard/RemoteConfigStep.tsx</files>
<action>
1. Replace the manual `backendLabel` record with auto-derived version:
```typescript
const backendLabel = Object.fromEntries(
Object.entries(BACKEND_REGISTRY).map(([k, v]) => [k, v.displayName])
) as Record<BackendType, string>;
```
This eliminates the duplicate displayName maintenance per Pitfall 2 in the research.
2. Import new components:
```typescript
import { OAuthInstructions } from './OAuthInstructions';
import { GdriveAuthToggle } from './GdriveAuthToggle';
```
3. Expand the rendering branch logic. The current three-branch ternary (azureblob/sftp/else) needs new branches for backends with special auth handling:
a. `gdrive` — GdriveAuthToggle (handles token + service_account_credentials) + FieldRenderer for root_folder_id:
```tsx
) : backendType === 'gdrive' ? (
<>
<GdriveAuthToggle
register={register}
errors={{
token: errors.token as FieldError | undefined,
service_account_credentials: errors.service_account_credentials as FieldError | undefined,
}}
/>
{BACKEND_REGISTRY.gdrive.fields
.filter(f => f.key !== 'token' && f.key !== 'service_account_credentials')
.map(field => (
<FieldRenderer key={field.key} field={field} register={register} error={errors[field.key] as FieldError | undefined} />
))}
</>
```
b. `dropbox` — OAuthInstructions + generic FieldRenderer loop:
```tsx
) : backendType === 'dropbox' ? (
<>
<OAuthInstructions backendName="Dropbox" authorizeCommand='rclone authorize "dropbox"' />
{BACKEND_REGISTRY.dropbox.fields.map(field => (
<FieldRenderer key={field.key} field={field} register={register} error={errors[field.key] as FieldError | undefined} />
))}
</>
```
c. `box` — OAuthInstructions + generic FieldRenderer loop:
```tsx
) : backendType === 'box' ? (
<>
<OAuthInstructions backendName="Box" authorizeCommand='rclone authorize "box"' />
{BACKEND_REGISTRY.box.fields.map(field => (
<FieldRenderer key={field.key} field={field} register={register} error={errors[field.key] as FieldError | undefined} />
))}
</>
```
d. `pcloud` — OAuthInstructions + generic FieldRenderer loop:
```tsx
) : backendType === 'pcloud' ? (
<>
<OAuthInstructions backendName="pCloud" authorizeCommand='rclone authorize "pcloud"' />
{BACKEND_REGISTRY.pcloud.fields.map(field => (
<FieldRenderer key={field.key} field={field} register={register} error={errors[field.key] as FieldError | undefined} />
))}
</>
```
e. All other new backends (azure-files, swift, ftp, webdav, smb, http, seafile) fall through to the existing generic `else` branch which iterates `BACKEND_REGISTRY[backendType].fields` — NO new branches needed for these since they have no auth toggles.
f. `onedrive` already has OAuthInstructions-worthy fields but currently works via the generic loop. Add OAuthInstructions to onedrive too for consistency:
```tsx
) : backendType === 'onedrive' ? (
<>
<OAuthInstructions backendName="OneDrive" authorizeCommand='rclone authorize "onedrive"' />
{BACKEND_REGISTRY.onedrive.fields.map(field => (
<FieldRenderer key={field.key} field={field} register={register} error={errors[field.key] as FieldError | undefined} />
))}
</>
```
4. The branch order should be: azureblob -> sftp -> gdrive -> onedrive -> dropbox -> box -> pcloud -> else (generic loop). Consider refactoring the deep ternary into a helper function or switch-like pattern for readability with 7 branches. A `renderBackendFields()` function with a switch statement is cleaner than nested ternaries.
5. Verify the form still submits correctly — the onNext handler and validation logic should remain unchanged since BACKEND_SCHEMAS auto-generates for all types.
</action>
<verify>
<automated>npx tsc --noEmit 2>&1 | tail -10 && npx vitest run src/components/wizard/RemoteConfigStep.test.tsx --reporter=verbose 2>&1 | tail -30</automated>
</verify>
<done>RemoteConfigStep renders correct form for all 17 backends. GdriveAuthToggle shown for gdrive. OAuthInstructions shown for onedrive, dropbox, box, pcloud. Generic loop for all others. backendLabel derived from registry. TypeScript compiles, existing tests pass.</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Add tests for new backend form rendering</name>
<files>src/components/wizard/RemoteConfigStep.test.tsx</files>
<behavior>
- Test 1: gdrive renders GdriveAuthToggle with "OAuth Token" and "Service Account" tabs
- Test 2: dropbox renders OAuthInstructions with 'rclone authorize "dropbox"' command
- Test 3: ftp renders host, username, password, port, TLS mode fields
- Test 4: webdav renders URL, username, password, vendor select fields
- Test 5: smb renders host, username fields
- Test 6: http renders only URL field
</behavior>
<action>
Add test cases to RemoteConfigStep.test.tsx following the existing test pattern:
- Each test sets up WizardState with the target backendType
- Renders RemoteConfigStep within WizardProvider
- Asserts form fields are present by label text or role
- For gdrive: assert the segmented control buttons exist (OAuth Token, Service Account)
- For dropbox: assert OAuthInstructions toggle button is present
- For protocol backends: assert expected fields render
Use the existing test setup pattern from the file. Each new backend test should be a focused assertion on field presence — not full form submission (submission is already tested for existing backends and the mechanism is generic).
Write tests first, then verify they pass against the implementation from Task 1.
</action>
<verify>
<automated>npx vitest run src/components/wizard/RemoteConfigStep.test.tsx --reporter=verbose</automated>
</verify>
<done>6 new test cases pass verifying form rendering for gdrive, dropbox, ftp, webdav, smb, and http backends.</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<name>Task 3: Visual verification of complete backend expansion</name>
<files>n/a</files>
<action>
Human verifies the complete backend expansion visually. What was built:
Complete backend expansion — 17 backends with categories, search, icons, OAuth instructions, and correct form rendering for each backend type.
</action>
<verify>
1. Run `npm run dev` and open http://localhost:5173
2. Step 1 (Backend Selection):
- Verify 3 category headings appear: "Cloud Object Storage", "Cloud Drives", "Protocol-based"
- Verify all 17 backend cards are visible with icons
- Type "ftp" in search — only FTP and SFTP should be visible
- Type "Cloudflare" in search — S3-Compatible should appear
- Clear search — all backends visible again
3. Select "Google Drive" — verify Step 2 shows OAuth Token / Service Account toggle
- OAuth Token tab: collapsible instructions + token field
- Service Account tab: service account credentials field
4. Go back, select "Dropbox" — verify Step 2 shows collapsible OAuth instructions + token field
5. Go back, select "FTP" — verify Step 2 shows host, username, password, port, TLS mode fields
6. Go back, select "WebDAV" — verify Step 2 shows URL, username, password, vendor select
7. Go back, select "SMB / Windows Share" — verify host, user, password, domain, port fields
8. Go back, select "HTTP (read-only)" — verify only URL field
9. Toggle dark mode — verify all new backends render correctly in dark mode
10. Run `npx vitest run` — all tests pass
</verify>
<done>User approves visual appearance and functionality of all 17 backends in both light and dark modes.</done>
</task>
</tasks>
<verification>
- `npx vitest run` — full suite green (all existing + new tests)
- `npx tsc --noEmit` — no type errors
- Visual verification of all 17 backends in both light and dark mode
- Form submission works for at least 3 new backends (gdrive, ftp, webdav)
</verification>
<success_criteria>
- Every backend type in BACKEND_REGISTRY has a working form in RemoteConfigStep
- OAuth backends (gdrive, dropbox, box, pcloud, onedrive) show OAuthInstructions
- gdrive shows GdriveAuthToggle with two auth paths
- Protocol backends render via generic FieldRenderer loop
- backendLabel derived from registry (no manual duplication)
- User approves visual appearance in both light and dark modes
</success_criteria>
<output>
After completion, create `.planning/phases/13-add-remaining-rclone-remotes/13-04-SUMMARY.md`
</output>