feat(account): implement Accounts view with CRUD, import/export, validation#127
Conversation
Wires the SQLite/keyring/codec adapters introduced in tasks 20–22 to the frontend through nine new Tauri IPC commands and a complete React UI. Backend - 9 IPC commands (account_add/update/delete/validate/export/import/list/ get/traffic_get) registered in invoke_handler! and re-exported. - lib.rs now provides SqliteAccountRepo, KeyringAccountStore and AesGcmPbkdf2Codec to CommandBus + QueryBus so the handlers actually run end-to-end at runtime. Frontend - src/views/AccountsView/ (8 components): main view, AccountList, AccountRow, AddAccountDialog, EditAccountDialog, DeleteAccountDialog, ImportExportDialog, statusUtils. - src/hooks/useAccountsQuery.ts + accountQueries cache keys. - Filter tabs (All/Debrid/Premium/Free) drive the list, kebab menu exposes Edit/Delete, validate button calls account_validate, toggle switch enables/disables, save/open dialogs anchor export/import paths. - Delete honours settings.confirmDelete: shows DeleteAccountDialog when enabled, otherwise calls account_delete immediately. - New i18n namespace accounts.* in en.json + fr.json. Tests - 13 Vitest tests cover render, empty state, filter, add flow, delete flow, export trigger disabled, export-with-passphrase, import-with- picker. Plus 5 unit tests for deriveAccountStatus. - Existing French i18n test updated to reflect that AccountsView is no longer a placeholder. - Rust suite: 1124 passed, 0 failed (handler coverage already added in tasks 21/22; new IPC commands are thin wrappers). Notes - AccountValidator stays unwired this commit; the validate IPC returns the configured Validation error until the first hoster plugin lands (task 38). UI surfaces the error through a toast and never crashes. - The "volume per account" requirement is deferred — needs a future history.account_id column, tracked separately.
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 30225239 | Triggered | Username Password | ed62719 | src/views/AccountsView/tests/AccountsView.test.tsx | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughAdds a complete Accounts feature: frontend React UI with dialogs, row actions and tests; TanStack query keys and a hook; TypeScript account types; i18n namespaces; Tauri IPC endpoints and DTOs; lib startup wiring for account repository/credential store; and CHANGELOG/capabilities updates. Changes
Sequence DiagramssequenceDiagram
participant User
participant Frontend as Frontend (React)
participant TauriIPC as Tauri IPC
participant Backend as Backend (Handlers)
participant Store as Store (Keyring/DB)
User->>Frontend: submit Add Account form
Frontend->>TauriIPC: account_add(payload)
TauriIPC->>Backend: forward AddAccountCommand
Backend->>Store: store credentials in keyring
Backend->>Store: persist account in SQLite
Backend-->>TauriIPC: AccountView DTO
TauriIPC-->>Frontend: success
Frontend->>Frontend: invalidate accounts cache, show toast
sequenceDiagram
participant User
participant Frontend as Frontend (React)
participant TauriIPC as Tauri IPC
participant Backend as Backend (Handlers)
participant External as External Service
participant Store as Store (Keyring/DB)
User->>Frontend: click Validate on row
Frontend->>TauriIPC: account_validate(accountId)
TauriIPC->>Backend: ValidateAccountCommand
Backend->>Store: retrieve credential
Backend->>External: perform validation call
External-->>Backend: validation result
Backend->>Store: update lastValidated
Backend-->>TauriIPC: ValidationOutcome
TauriIPC-->>Frontend: result
Frontend->>Frontend: clear validating state, invalidate cache, show toast
sequenceDiagram
participant User
participant Frontend as Frontend (React)
participant Dialog as Import/Export Dialog
participant TauriIPC as Tauri IPC
participant Backend as Backend (Handlers)
participant Disk as Disk
User->>Frontend: open Export dialog, confirm passphrase
Frontend->>TauriIPC: account_export(passphrase, path)
TauriIPC->>Backend: export handler
Backend->>Backend: serialize & encrypt bundle
Backend->>Disk: write .vxbundle
Backend-->>TauriIPC: Export result
TauriIPC-->>Frontend: success
Frontend->>Frontend: show toast
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Review rate limit: 4/5 reviews remaining, refill in 12 minutes. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ed62719215
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (1)
src/views/AccountsView/__tests__/AccountsView.test.tsx (1)
78-261: Consider adding coverage for validation refresh and export-cancel UX.Given the new flows, add tests for:
account_validateleading to query invalidation/refetch, and- save-dialog cancel during export not emitting an error toast.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/views/AccountsView/__tests__/AccountsView.test.tsx` around lines 78 - 261, Add two tests: one that calls the "account_validate" flow and asserts the accounts list is refreshed (i.e., mockInvoke should be called for "account_validate" and subsequently "account_list" again and the UI updated) by reusing mockInvoke, renderView and waiting for updated DOM entries; and another that simulates cancelling the save dialog during export by making mockSave resolve to undefined (or reject with a cancellation sentinel) after clicking the "accounts-export-trigger" and then asserting that no error toast (mockToastError) was called while no success toast is shown—use the test helpers and testids "accounts-export-trigger", "account-export-passphrase", "account-export-submit", and the invoke command "account_export" to locate relevant behaviour.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@CHANGELOG.md`:
- Line 12: The changelog line incorrectly states "Eight new Tauri IPC commands"
while the list contains nine command names; update the prose to "Nine new Tauri
IPC commands" (or remove the numeric count) so it matches the listed commands
`account_add`, `account_update`, `account_delete`, `account_validate`,
`account_export`, `account_import`, `account_list`, `account_get`, and
`account_traffic_get`.
In `@src-tauri/src/adapters/driving/tauri_ipc.rs`:
- Around line 2802-2820: In account_list, normalize the incoming service_name
before constructing AccountFilter: trim whitespace from the Option<String> and
treat empty/whitespace-only strings as None so they don't become a blank filter;
leave non-empty trimmed values as Some(String). Update the code that builds
AccountFilter (referencing account_list and AccountFilter) to use this
normalized service_name value so filtering behaves correctly.
In `@src/views/AccountsView/AccountRow.tsx`:
- Around line 65-68: The translation call in AccountRow.tsx uses the wrong
interpolation keys and may produce negative values: replace the object passed to
t("accounts.traffic.format", ...) to use keys current and max (not used/total),
and compute current as Math.max(0, account.trafficTotal - account.trafficLeft)
before formatting; continue to call formatBytes on both current and
account.trafficTotal to pass formatted current and max to the translation.
- Line 50: Account type is rendered directly from account.accountType, bypassing
i18n; update the AccountRow rendering to translate the enum before display
(e.g., use the current translation function like t or useTranslation) by
replacing the raw value with a translated key such as
t(`accountTypes.${account.accountType}`) and provide a safe fallback (e.g.,
t('accountTypes.unknown') || account.accountType) so missing translations don't
break the UI; adjust or add a small helper (e.g., formatAccountType or
translateAccountType) if you prefer to centralize mapping from enum values to
i18n keys.
In `@src/views/AccountsView/AccountsView.tsx`:
- Around line 196-199: The current check treats a cancelled save picker as an
error by calling toast.error(t("accounts.toast.missingFile")) when !picked;
change this to treat cancel as a no-op by removing the toast.error call and
simply returning when picked is falsy (or explicitly check for a user-cancel
condition if your picker returns a specific value/throws). Update the block
around the picked variable in AccountsView.tsx so that only genuine failures
show errors and the save-picker cancel just returns without calling
t("accounts.toast.missingFile").
- Around line 165-167: The toast call in AccountsView.tsx uses the wrong
interpolation key: update the t("accounts.toast.validateInvalid", { reason:
outcome.errorMessage ?? "—" }) invocation to pass the expected `message` key
instead of `reason` (e.g., use { message: outcome.errorMessage ?? "—" }) so the
translation template receives the correct variable; keep the fallback "—" as-is.
- Around line 154-176: handleValidate currently calls the backend via
"account_validate" but doesn't refresh the UI model, leaving
status/traffic/validity stale; after the await tauriInvoke(...) (on both success
and invalid branches) trigger a refresh of the account data by either calling
the existing refetch function (e.g. refetchAccounts()) or invalidating the
accounts query via your QueryClient (e.g.
queryClient.invalidateQueries("accounts")), or if you maintain local state
update the specific account in the list using setAccounts to reflect the new
validity/traffic values; keep setValidatingId handling as-is and ensure the
refresh runs before leaving the finally block so the UI shows updated data.
In `@src/views/AccountsView/AddAccountDialog.tsx`:
- Around line 44-52: The effect currently resets form fields whenever either
open or defaultType changes, which clears in-progress edits if defaultType
changes while the dialog is open; change the logic so fields are reset only when
the dialog is opened (i.e., open transitions from false to true). Update the
useEffect watching open (not defaultType) and detect the open transition using a
ref or previousOpen flag, calling setServiceName, setUsername, setPassword,
setAccountType(defaultType), and setSubmitting(false) only when open becomes
true; if you must respond to defaultType changes, handle that separately and
only apply it when the dialog is not currently open or when it's just opening.
In `@src/views/AccountsView/DeleteAccountDialog.tsx`:
- Around line 39-44: The translation call in DeleteAccountDialog uses
interpolation keys username and service but the locale template expects name
(and possibly different key for service); update the t(...) call to pass the
exact keys the translation uses (e.g. replace username with name) or update the
translation template to accept username and service; locate the call in
DeleteAccountDialog inside DialogDescription
(t("accounts.deleteDialog.description", { username: account.username, service:
account.serviceName })) and make the keys consistent with the translation file
so the dynamic value is substituted correctly.
In `@src/views/AccountsView/ImportExportDialog.tsx`:
- Around line 161-173: The path Input (the readOnly Input with value={path ??
""} and data-testid="account-import-path") is unlabeled for assistive tech; add
an accessible name by either giving the label span a unique id (e.g.,
id="import-path-label") and passing aria-labelledby="{that id}" to the Input, or
by adding aria-label with the same translation string
(t("accounts.importDialog.filePath")) to the Input; update the span and the
Input props in ImportExportDialog (the span above the Input and the Input
component itself, which sits next to the Button with onClick={handleBrowse})
accordingly.
- Around line 38-49: The handler signatures use React.FormEvent but the React
namespace is not imported; update both handleSubmit occurrences to use the
imported FormEvent type (e.g. change parameter type from React.FormEvent to
FormEvent) and add a top-level import { FormEvent } from 'react' so TypeScript
with react-jsx/strict compiles correctly; ensure references to handleSubmit,
onSubmit, passphrase, canSubmit, setSubmitting, and onOpenChange remain
unchanged.
---
Nitpick comments:
In `@src/views/AccountsView/__tests__/AccountsView.test.tsx`:
- Around line 78-261: Add two tests: one that calls the "account_validate" flow
and asserts the accounts list is refreshed (i.e., mockInvoke should be called
for "account_validate" and subsequently "account_list" again and the UI updated)
by reusing mockInvoke, renderView and waiting for updated DOM entries; and
another that simulates cancelling the save dialog during export by making
mockSave resolve to undefined (or reject with a cancellation sentinel) after
clicking the "accounts-export-trigger" and then asserting that no error toast
(mockToastError) was called while no success toast is shown—use the test helpers
and testids "accounts-export-trigger", "account-export-passphrase",
"account-export-submit", and the invoke command "account_export" to locate
relevant behaviour.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e4a2dc71-b7ea-4a66-a410-f752c43bba4b
📒 Files selected for processing (21)
CHANGELOG.mdsrc-tauri/src/adapters/driving/tauri_ipc.rssrc-tauri/src/lib.rssrc/api/queries.tssrc/hooks/useAccountsQuery.tssrc/i18n/__tests__/issue30-ui-fr.test.tsxsrc/i18n/locales/en.jsonsrc/i18n/locales/fr.jsonsrc/types/account.tssrc/views/AccountsView.tsxsrc/views/AccountsView/AccountList.tsxsrc/views/AccountsView/AccountRow.tsxsrc/views/AccountsView/AccountsView.tsxsrc/views/AccountsView/AddAccountDialog.tsxsrc/views/AccountsView/DeleteAccountDialog.tsxsrc/views/AccountsView/EditAccountDialog.tsxsrc/views/AccountsView/ImportExportDialog.tsxsrc/views/AccountsView/__tests__/AccountsView.test.tsxsrc/views/AccountsView/__tests__/statusUtils.test.tssrc/views/AccountsView/index.tssrc/views/AccountsView/statusUtils.ts
💤 Files with no reviewable changes (1)
- src/views/AccountsView.tsx
There was a problem hiding this comment.
4 issues found across 21 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/views/AccountsView/AccountRow.tsx">
<violation number="1" location="src/views/AccountsView/AccountRow.tsx:50">
P2: Account type is rendered as a raw enum value instead of a localized label.</violation>
</file>
<file name="CHANGELOG.md">
<violation number="1" location="CHANGELOG.md:12">
P3: The changelog says "Eight" IPC commands but lists nine command names; update the count to avoid incorrect release documentation.</violation>
</file>
<file name="src/views/AccountsView/AccountsView.tsx">
<violation number="1" location="src/views/AccountsView/AccountsView.tsx:40">
P2: Using a single `validatingId` creates a race for concurrent validations; one completion can clear the pending state of another in-flight validation.</violation>
<violation number="2" location="src/views/AccountsView/AccountsView.tsx:158">
P2: After `account_validate`, the accounts query is not invalidated/refetched, so row status/traffic/lastValidated can remain stale.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
- Fix changelog command count (Eight → Nine)
- Trim and collapse empty service_name filter in account_list IPC
- Localize account type cell via t(`accounts.filter.${type}`)
- Clamp negative used bytes in traffic display
- Invalidate accounts query after account_validate so row state refreshes
- Replace single validatingId with Set<string> to handle concurrent validations
- Drop misleading missingFile toast on export save-picker cancel
- Reset AddAccountDialog form only on open transition (defaultType via ref)
- Add aria-label on read-only import path field
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src-tauri/src/adapters/driving/tauri_ipc.rs (1)
2608-2613: Potential truncation innow_unix_ms()when casting from u128 to u64.While
as_millis()returnsu128, milliseconds since Unix epoch will fit inu64for billions of years, so this is safe in practice. However,saturating_castor an explicit check would be more defensive.Optional defensive alternative
fn now_unix_ms() -> u64 { std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) - .map(|d| d.as_millis() as u64) + .map(|d| d.as_millis().min(u64::MAX as u128) as u64) .unwrap_or(0) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src-tauri/src/adapters/driving/tauri_ipc.rs` around lines 2608 - 2613, The helper now_unix_ms() casts a u128 from as_millis() to u64 which could truncate in theory; update now_unix_ms() to defensively clamp or saturating-convert the u128 result into u64 (e.g., use min(u128::from(u64::MAX)) or a checked/saturating conversion) and preserve the unwrap_or(0) behavior on error, so the function returns u64 without silent truncation.src/views/AccountsView/AccountRow.tsx (1)
89-93: Consider a more descriptive aria-label for the enabled/disabled Switch.The current
aria-label={t("accounts.status.active")}is static and doesn't convey the toggle's purpose or current state. Consider using a label that describes the action, such as "Enable account" or "Toggle account enabled".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/views/AccountsView/AccountRow.tsx` around lines 89 - 93, Update the Switch's aria-label in AccountRow to be descriptive and reflect action/state instead of the static t("accounts.status.active"); use account properties and i18n keys (e.g., a key like "accounts.actions.enable" / "accounts.actions.disable" or construct a string using account.enabled and account.name) so the label becomes contextual (e.g., "Enable account <name>" when disabled and "Disable account <name>" when enabled) and keep the onCheckedChange handler as actions.toggleEnabled(account, checked).src/views/AccountsView/AccountsView.tsx (1)
245-249: Consider usingtoast.infofor skipped duplicates instead oftoast.success.Skipped duplicates are informational rather than a success condition. Using a different toast variant would better distinguish this from the actual import success message.
Suggested change
if (result.skippedDuplicates > 0) { - toast.success( + toast.info( t("accounts.toast.importSkipped", { count: result.skippedDuplicates }), ); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/views/AccountsView/AccountsView.tsx` around lines 245 - 249, The toast for skipped duplicates is using toast.success but should be an informational message; in the AccountsView component replace the toast.success call inside the conditional that checks result.skippedDuplicates > 0 with toast.info (keeping the same translation key t("accounts.toast.importSkipped", { count: result.skippedDuplicates })) so skipped duplicates are shown as info rather than success.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/views/AccountsView/AddAccountDialog.tsx`:
- Line 65: The type annotation React.FormEvent used in the handleSubmit function
is referenced without importing the React namespace; either import the React
namespace (import * as React from "react") or replace React.FormEvent with the
named FormEvent type (import { FormEvent } from "react") and update the
handleSubmit signature accordingly so the TypeScript compile error is resolved;
locate the handleSubmit declaration to apply the chosen import and type change.
---
Nitpick comments:
In `@src-tauri/src/adapters/driving/tauri_ipc.rs`:
- Around line 2608-2613: The helper now_unix_ms() casts a u128 from as_millis()
to u64 which could truncate in theory; update now_unix_ms() to defensively clamp
or saturating-convert the u128 result into u64 (e.g., use
min(u128::from(u64::MAX)) or a checked/saturating conversion) and preserve the
unwrap_or(0) behavior on error, so the function returns u64 without silent
truncation.
In `@src/views/AccountsView/AccountRow.tsx`:
- Around line 89-93: Update the Switch's aria-label in AccountRow to be
descriptive and reflect action/state instead of the static
t("accounts.status.active"); use account properties and i18n keys (e.g., a key
like "accounts.actions.enable" / "accounts.actions.disable" or construct a
string using account.enabled and account.name) so the label becomes contextual
(e.g., "Enable account <name>" when disabled and "Disable account <name>" when
enabled) and keep the onCheckedChange handler as actions.toggleEnabled(account,
checked).
In `@src/views/AccountsView/AccountsView.tsx`:
- Around line 245-249: The toast for skipped duplicates is using toast.success
but should be an informational message; in the AccountsView component replace
the toast.success call inside the conditional that checks
result.skippedDuplicates > 0 with toast.info (keeping the same translation key
t("accounts.toast.importSkipped", { count: result.skippedDuplicates })) so
skipped duplicates are shown as info rather than success.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c09ac0ae-e1a5-411f-977a-6afc547192e0
📒 Files selected for processing (7)
CHANGELOG.mdsrc-tauri/src/adapters/driving/tauri_ipc.rssrc/views/AccountsView/AccountList.tsxsrc/views/AccountsView/AccountRow.tsxsrc/views/AccountsView/AccountsView.tsxsrc/views/AccountsView/AddAccountDialog.tsxsrc/views/AccountsView/ImportExportDialog.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- CHANGELOG.md
- src/views/AccountsView/AccountList.tsx
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6eb2046ca5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@GitGuardian on
False positive. The literal |
Without this capability the import bundle picker silently resolves to null and users cannot select a file. Reported on PR #127 as P1.
Summary
Replace
AccountsViewplaceholder with complete Accounts management UI. Implements multi-account CRUD across three categories (Debrid/Premium/Free), real-time validation with status tracking, AES-256 encrypted import/export with passphrase protection, and traffic monitoring. Integrates with backend Accounts repository (task 20), command handlers (task 21), and query handlers (task 22).Why
Accounts are critical for Debrid/Premium services and file hosters. Users need intuitive multi-account management: add credentials, validate access, toggle enable/disable per account, track traffic consumption, and backup encrypted bundles. Phase 1 (v0.3 beta) target feature.
Changes
Backend (Rust)
tauri_ipc.rs:account_add,account_update,account_delete,account_validate,account_list,account_get,account_traffic_get,account_export,account_importAccountPatchDto,ValidationOutcomeView,ExportAccountsView,ImportAccountsViewlib.rsFrontend (React/TypeScript)
AccountView,AccountTraffic,AddAccountInput,ValidationOutcomeinsrc/types/account.tsuseAccountsQuery()with TanStack Query cache + staleTimeAccountsView.tsx: filter tabs (All/Debrid/Premium/Free), add/edit/delete/validate flows, import/export dialogs, real-time validation feedbackAccountList(table),AccountRow(row with status badge + traffic bar),AddAccountDialog(form),EditAccountDialog(patch form),DeleteAccountDialog(confirm),ImportExportDialog(two-part: export passphrase prompt + file save, import file picker + passphrase)statusUtils.tsderives account status (active/expired/disabled/unverified) from account state +valid_until+enabledflagi18n
en.json/fr.jsonunderaccountsnamespace: titles, labels, filter tabs, dialog copy, success/error toasts, empty stateTests
AccountsView.test.tsx: 18 Vitest cases covering render, tabs, add/delete/import/export flows, passphrase inputstatusUtils.test.ts: 5 unit tests for status derivation (all combinations of enabled/valid_until/error)Documentation
Testing
All tests passing locally:
Manual flows verified:
confirmBeforeDeletesetting) ✓Related Issues
Notes for Reviewer
Large diff (2029 insertions, 21 files): review strategy recommended.
src-tauri/src/adapters/driving/tauri_ipc.rs,lib.rs): 9 new IPC commands, 278 linessrc/views/AccountsView/*): 800 lines across 8 files, organized by responsibilityen.json,fr.json): 100+ lines per file, follow existing namespace patternDeferred from acceptance criteria: "Stats: volume downloaded via this account" — requires
history.account_idcolumn (separate schema migration task).Checklist
Summary by cubic
Replaces the Accounts placeholder with a full management UI (CRUD, validate, traffic) plus AES-256 encrypted import/export. Adds nine Tauri IPC commands and wires SQLite repo, OS keyring, and passphrase codec to meet task #23.
New Features
@tanstack/react-querycaching viauseAccountsQuery.account_add/update/delete/validate/export/import/list/get/traffic_get) with runtime wiring ofSqliteAccountRepo,KeyringAccountStore,AesGcmPbkdf2Codec.accounts.*keys in English and French.Bug Fixes
account_validate; support concurrent validations with a Set of IDs.t('accounts.filter.${type}').dialog:allow-opencapability for the import file picker; remove misleading “missing file” toast on canceled save; add aria-label to import path; reset Add dialog on open (keeps default type).service_nameinaccount_listfilter.Written for commit c97172c. Summary will update on new commits. Review in cubic
Summary by CodeRabbit
New Features
Internationalization
Tests
Documentation