feat(bulk-entry): add bulk entry workflow for snapshot creation#26
feat(bulk-entry): add bulk entry workflow for snapshot creation#26
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…, and state tracking Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ng rows Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…port logic Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… list views Add hasZeroValueAssets to SnapshotRowData and display warning triangle icons for assets with marketValue == 0. Also add String overload for helpWhenUnlocked to support table-based localized strings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…picker in NewSnapshotSheet Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…import, and keyboard navigation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add bulkEntry case to SidebarSection enum and wire up BulkEntryView in ContentView's detail pane. Connect NewSnapshotSheet's onBulkEntry callback through SnapshotListView to ContentView for proper navigation flow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…bulk entry Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…CLAUDE.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…pshotDetailView Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ls to BulkEntryView Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Save dialog now mentions values can be filled later - Prohibit entering 0 (zero-value assets should be excluded instead) - Warning icons use hover popovers instead of system tooltips - Sidebar "New Snapshot" shows date picker sheet; cancel navigates back - CSV import surfaces errors, warnings, and success count to users - NewSnapshotSheet cancel from sidebar navigates back to previous section Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address multiple UX issues in the bulk entry workflow: - Remove Cancel button from BulkEntryView; use Go back with discard confirmation instead (matching ImportView pattern) - Detect platform/currency mismatches during CSV import and skip conflicting rows with grouped warning summaries - Fix CSV import race condition where fileImporter binding cleared the target platform before the result handler ran - Fix sidebar "New Snapshot" to show date picker sheet without navigating away, so Cancel is a clean no-op - Restructure CSVImportResult with typed mismatch data for cleaner alert formatting - Improve import result dialog with severity-based titles and grouped mismatch summaries - Add 15 missing zh-Hant translations for new UI strings Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ing snapshots Assets deferred during bulk snapshot creation are saved with marketValue=0 as placeholders. Previously, ImportView flagged these as duplicate errors, blocking users from updating them via CSV. - Skip snapshotDuplicateError when existing asset has marketValue == 0 - Update existing zero-value SAV in place instead of creating a new one - Non-zero existing values still trigger the duplicate error to prevent accidental double-counting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Position the warning icon to the left of the total value so it visually signals that the displayed value needs attention, rather than appearing as an afterthought after the asset count badge. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d design comments Address code review findings: - Add date conflict check in saveSnapshot() using predicate-based fetch with fetchLimit=1 to prevent duplicate snapshots from race conditions - Show inline error label in toolbar when assets have zero values, explaining why Save is disabled - Add comments documenting intentional design decisions: stable row IDs via asset.id and csvCategory being nil due to AssetCSVRow lacking a category field Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allow users to add new assets and platforms directly in BulkEntryView, making it self-sufficient even without prior snapshots. Previously, the empty state was a dead end requiring CSV import. - Add per-platform "Add Asset" button for inline row creation with editable name, currency picker, and category picker - Add "Add Platform" toolbar button with popover for creating new platform groups - Redesign empty state with "Add Platform" action instead of dead-end message - Add CategoryNamePicker for new-asset rows (defers DB creation to save) - Add duplicate asset name validation within platform (case-insensitive) - Extend ValueSource with .manualNew; rename csvCategory to categoryName - Update canSave/hasUnsavedChanges for new row validation - Add 15 tests covering new ViewModel methods and edge cases - Add zh-Hant translations for all new UI strings - Update SPEC.md, BusinessLogic.md, and UserInterfaceDesign.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Improve SwiftUI view composition for better diffing performance and code organization. The main BulkEntryView body previously used @ViewBuilder functions for all subviews, causing unnecessary re-evaluation on every parent state change. - Extract AssetEntryRow, ProgressStats, ColumnHeaders, ValidationWarnings, and CategoryPicker into separate struct views in BulkEntrySubviews.swift - Make @State viewModel private with explicit initializer - Compute duplicateNameRowIDs once at body level instead of per platform section, avoiding repeated O(n) traversals - Move formatImportResult to CSVImportResult.formattedResult() method - Add .ultraThinMaterial toolbar background for Liquid Glass treatment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The bulk entry feature and related UX changes need corresponding user-facing documentation so users can discover and learn the new snapshot creation workflow. - Add dedicated Bulk Entry guide page (EN + zh-TW) covering the full-screen workflow, table layout, inline asset/platform creation, per-platform CSV import, validation, and zero-value warnings - Update snapshots page to replace "Copy from Latest" with creation mode picker (Bulk Entry / Empty Snapshot) and mention zero-value warning icons - Update quick-start page to reflect the new snapshot creation flow - Update import-csv page with per-platform CSV import tip and zero-value overwrite behavior note - Update index pages to include Bulk Entry in the guide topic table - Update keyboard shortcuts with Enter key navigation in Bulk Entry - Add 3 new screenshots (bulk-entry, add-platform, csv-import) and update 3 existing ones (snapshot-create, snapshot-list, snapshot-detail) - Add Bulk Entry to mkdocs.yml nav under Guide Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…changes HelpWhenUnlockedModifier used if/else branching between content.help(key) and bare content, changing the view tree structure on the focused TextField whenever hasZeroValueError toggled. This caused SwiftUI to reset @focusstate, forcing users to re-click the field mid-typing. - Make HelpWhenUnlockedModifier always return content.help(...) with an empty string fallback, keeping the view tree stable Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The "No Assets" empty state was pinned to the top-left because it lived inside the ScrollView's LazyVStack. Move it outside the ScrollView so it can fill the full area and center both horizontally and vertically. Pin the add-platform popover arrow edge to `.bottom` so it always appears above the toolbar button regardless of screen position. - Move ContentUnavailableView out of ScrollView into a conditional branch - Add .frame(maxWidth: .infinity, maxHeight: .infinity) for centering - Set arrowEdge: .bottom on the toolbar popover - Update bulk-entry-add-platform screenshot Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ange Replace inline conditional warning labels with a single stable icon that uses opacity to show/hide without affecting layout. Warning details are displayed in a hover popover following the existing HoverWarningIcon pattern with onHoverWhenUnlocked for lock-aware behavior. - Collapse 0–3 conditional Label views into one fixed-size Image icon - Use opacity(0/1) instead of if/else to reserve layout space - Show all active warnings in a hover popover with lock-aware binding - Reuse existing onHoverWhenUnlocked + popover pattern from HoverWarningIcon Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Refresh the app overview image to reflect the current UI after bulk snapshot entry feature additions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code reviewFound 4 issues:
asset-flow/AssetFlow/ViewModels/BulkEntryViewModel.swift Lines 63 to 66 in bf06caa
asset-flow/AssetFlow/Views/SnapshotListView.swift Lines 347 to 354 in bf06caa asset-flow/AssetFlow/Views/ContentView.swift Lines 178 to 186 in bf06caa
asset-flow/AssetFlow/Views/ContentView.swift Lines 258 to 274 in bf06caa
asset-flow/Documentation/UserInterfaceDesign.md Lines 143 to 147 in bf06caa 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
Fix bugs, documentation gaps, and inconsistencies identified during code review of the bulk snapshot entry feature. - Add hasValidationError guard to canSave so rows with unparseable text (e.g. "abc") cannot be silently saved as Decimal(0) - Fix HelpWhenUnlockedStringModifier to always emit .help() for stable view tree, matching the LocalizedStringKey overload - Reorder sidebarBinding checks so unsaved-changes guards run before the .bulkEntry sheet trigger - Enable empty snapshot creation from sidebar by using modelContext directly when SnapshotListViewModel is unavailable - Truncate forward history on bulk entry discard to prevent goForward() from navigating to nil ViewModel - Use normalizedForIdentity instead of lowercased() in addPlatform() for consistent identity comparison - Anchor empty-state "Add Platform" popover to its own button instead of the toolbar button - Add "Import Error" key to Snapshot.xcstrings with zh-Hant translation for consistency with sibling keys - Remove unused "Cannot create an empty snapshot" localization string - Document zero-value SAV placeholder design invariant in BusinessLogic.md and add explanatory code comments - Update UserInterfaceDesign.md to remove stale "Copy from latest" and fix Bulk Entry description - Update ContentView doc comment to reflect 8-section sidebar Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
All 4 reported issues (plus 8 additional issues found below the reporting threshold) have been addressed in be6f175. Reported issues fixed:
Additional fixes:
🤖 Generated with Claude Code |
Summary
Adds a new "Bulk Entry" mode as the default snapshot creation workflow. Instead of creating empty snapshots or copying from the latest, users now get a full-screen editable table with all assets from the prior snapshot grouped by platform, where they can enter new market values directly or import them from per-platform CSV files. This replaces the previous "Copy from latest" option and provides a significantly more efficient data entry experience.
Changes
Bulk Entry ViewModel & Types
BulkEntryViewModelwith platform-grouped rows, save logic (zero-value fallback for pending rows), and per-platform CSV import with match/append semanticsBulkEntryRowvalue type with rich state tracking (updated, pending, excluded, validation errors, zero-value detection, duplicate name detection)CSVImportResultwith formatted user-facing messages for match counts, errors, and warningsBulk Entry View
BulkEntryViewwith platform-grouped table, keyboard navigation (Tab/Enter between fields), and toolbar with progress stats, validation warnings, and save buttonBulkEntrySubviewsextracted as structs: progress stats, validation warnings, platform section headers, asset rows, empty state, and glass-style toolbarSnapshot List & Navigation
NewSnapshotSheetto replace "Copy from latest" toggle with a creation mode picker (Empty / Bulk Entry)ContentViewupdated to navigate toBulkEntryViewwhen bulk entry mode is selectedHoverWarningIconcomponentCSV Import Enhancement
ImportViewModel+Helpersnow allows CSV import to overwrite zero-value assets in existing snapshots (deferred from bulk entry pending rows)Utilities
WhenUnlockedModifiersextended withhelpWhenUnlocked(_ text: String)overload;HelpWhenUnlockedModifierstabilized to always apply.help()(avoiding@FocusStateresets from view tree changes)Localization
Localizable.xcstringsandSnapshot.xcstringsDocumentation
SPEC.md,BusinessLogic.md, andUserInterfaceDesign.mdwith bulk entry feature spec, validation rules, save semantics, and implementation statusTests
BulkEntryViewModelTestscovering row state logic, platform grouping, counts, save semantics (including zero-value fallback and new asset creation), CSV import matching/appending/re-import, manual row/platform CRUD, duplicate name detection, and category resolutionSnapshotListViewModelTestsextended with zero-value asset detection testsTesting
BulkEntryViewModelTests(25 tests) andSnapshotListViewModelTests(2 new tests) using Swift Testing with in-memory SwiftData containersNotes