One JSON document for storage; read-only dashboard; import asks before wiping - #5
Open
Grantmiller99 wants to merge 3 commits into
Open
One JSON document for storage; read-only dashboard; import asks before wiping#5Grantmiller99 wants to merge 3 commits into
Grantmiller99 wants to merge 3 commits into
Conversation
Rebuilds the storage layer around a single JSON document rather than a loose collection of helpers, and documents the whole format in DATA.md. Storage model: - All data is one document under one localStorage key. Every operation reads or writes the whole document, so what is stored is always complete and valid; nothing writes a partial record. - read() parses it, write() serialises it back, clear() deletes the key outright, replaceFromJSON() overwrites it with an imported file, and exportToFile() writes it out verbatim. - Clear now genuinely wipes the file. A read afterwards returns a fresh empty document without recreating the key, so cleared stays cleared. - Import replaces rather than merges. Entries and settings are both taken from the file, and the confirmation says how many entries are about to be overwritten instead of a vague warning. - Export re-imported returns identical data, ids included. - One validateEntry gate now covers both typed input and imported files, so a form and a backup cannot disagree about what a valid entry is. Dashboard: - "Incoming Paychecks" and "Weekly Spending" are read-only listings mirroring the Entries page: same Date / Amount / Notes columns, same newest-first order, no add forms and no delete buttons. Each panel links to Entries for editing. - Both listings show every entry, scrolling inside the panel with a sticky header, rather than silently cutting off after five rows. - Totals, charts and listings all refresh from the stored document, so entries added on the Entries or Groceries page and data restored by an import both land on the dashboard correctly. - Removed the form and delete-button CSS the dashboard no longer uses. Also adds DATA.md describing the document, the entry rules, every operation, how totals are derived, and why writes re-read before saving.
Import always replaced everything, so restoring a backup silently destroyed any
entries added since it was taken. It now asks.
The file is parsed and validated BEFORE anything is stored, so the dialog can
show real numbers ("This file holds 12 entries. You currently have 4 stored.")
and an unusable file can never damage what is already there.
Three answers:
- Yes, wipe and replace - discard everything stored, entries and settings, and
keep only the backup. The previous behaviour, now chosen deliberately.
- No, keep mine and add - append the file's entries to what is stored. Existing
entries and existing settings are left alone. An entry already present, same
id, which is what happens when the same file is imported twice, is counted as
a duplicate and skipped rather than added again.
- Cancel - nothing is touched. The backdrop and Escape do the same.
With nothing stored yet there is nothing to wipe, so the question is skipped and
the file imports directly.
Native confirm() only offers two answers, so this is a small in-page dialog
styled to match the settings panels. Every outcome reports what actually
happened: how many entries were added or restored, how many duplicates were
skipped, how many were dropped for a bad date or amount, and how many of your
own entries were wiped.
Splits the store's import into parseBackup (validate without storing),
replaceWith (wipe) and mergeWith (keep), and updates DATA.md to match.
… data loss
Four defects found reviewing the data layer, each reproduced before fixing.
Duplicate ids deleted the wrong entry. validateEntry trusted any id string in a
backup and never checked uniqueness, so two entries could share one; delete
works by id and removes the first match. Importing a file with two spend entries
both carrying id "dup" and clicking the trash on the top row removed the other
one. Ids are now unique across the whole document, with a repeated one reissued
on the way in. This also stops "keep mine and add" silently discarding a
legitimate entry whose id happened to collide.
Clearing a settings field rewrote it to the minimum. Number('') is 0, which
clamped an emptied percentage box to 1% and an emptied grocery limit to $0.01,
then redisplayed the new value as though it had been typed. Blank input now
keeps the current setting: clampNumber treats empty as "no value", and
validateSettings takes the fallbacks to use, so editing falls back to the
current settings while importing falls back to the defaults.
Exporting an empty tracker downloaded a file and then said there was nothing to
export, because the anchor was clicked before the count was returned. It now
returns early with the counts and downloads nothing.
Loading silently destroyed invalid entries. read() rewrote storage whenever any
entry failed validation, so a hand-edited document lost those rows permanently
just by opening a page, with no message. Load now only rewrites for a genuine
upgrade (missing ids, repeated ids, older schema) and logs a warning about
anything it ignored, leaving the data on disk.
Also corrects the store's header comment, which still claimed import always
replaces the document and predated the wipe/keep choice, and removes
replaceFromJSON, unused since the import dialog landed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #1, #2 and #4. Rebuilds the storage layer around a single JSON document, makes the dashboard a read-only view, and gives import a choice instead of always destroying what you have. The format is documented in
DATA.md.1. Import asks whether to wipe your entries
Import always replaced everything, so restoring a backup silently destroyed any entries added since it was taken. It now asks.
The file is parsed and validated before anything is stored, so the dialog shows real numbers — "This file holds 12 entries. You currently have 4 stored." — and an unusable file can never damage what is already there.
With nothing stored yet there is nothing to wipe, so the question is skipped and the file imports directly.
On add, an entry already present (same
id— what happens when the same file is imported twice) is counted as a duplicate and skipped rather than added again.Native
confirm()only offers two answers, so this is a small in-page dialog styled to match the settings panels. Every outcome reports what actually happened: entries added or restored, duplicates skipped, entries dropped for a bad date or amount, and how many of your own entries were wiped.2. Storage is one JSON document
All data lives in one document under one key — think of it as a single JSON file. Every operation reads or writes the whole thing, so nothing writes a partial record.
read()write(doc)clear()parseBackup(text)replaceWith(doc)/mergeWith(doc)exportToFile()Export re-imported with wipe returns identical data, ids included. One
validateEntrygate covers both typed input and imported files, so a form and a backup cannot disagree about what a valid entry is.3. Dashboard is a read-only view
"Incoming Paychecks" and "Weekly Spending" mirror the Entries page — same Date / Amount / Notes columns, same newest-first order — with no add forms and no delete buttons. Each panel links to Entries for editing, so entries are managed in exactly one place. Both listings now show every entry, scrolling inside the panel with a sticky header, rather than silently cutting off after five rows.
Totals, charts and listings all refresh from the stored document, so entries added on Entries or Groceries and data restored by an import both land on the dashboard correctly.
Verified
Driven through the real UI against a local server, no console errors:
null; a later read does not recreate it