Skip to content

undo a few changes#5

Open
Greensand321 wants to merge 238 commits into
claude/review-flowboard-lQTTZfrom
main
Open

undo a few changes#5
Greensand321 wants to merge 238 commits into
claude/review-flowboard-lQTTZfrom
main

Conversation

@Greensand321

Copy link
Copy Markdown
Owner

undo some of the changes in the branch

Greensand321 and others added 30 commits April 9, 2026 09:20
…ually

- Archive entire columns (with all their cards) via ⊡ button in column header
- Archive individual cards via 📦 Archive button in card modal footer
- Archive browser modal (📦 Archive in top nav) shows archived columns and cards
  with Restore and Delete actions per item
- Restoring a column also clears archive flags on all cards within it
- Archived items are fully filtered from the board, card counts, and stats
- Archived columns are excluded from the card modal's column picker
- All archive actions integrate with undo/redo stack

https://claude.ai/code/session_01VxiEThbmeb8Y6ro3A68Mnd
…n-SVfAr

Add archival feature to FlowBoard — archive columns and cards individ…
Replace flat lists with a horizontally scrollable row of column panels
that use the same .col / .col-hdr / .col-body / .card CSS as the live
board, making the archive immediately recognizable.

- mkArchivePanel(): renders a column panel using the column's real PAL
  color and header style. Fully archived columns get an amber 🗄 Archived
  badge plus ↩ / × column-level actions. Context panels (active columns
  with individually archived cards) show the column name and count only.
- mkArchiveCard(): renders a .card with the same border-left color,
  title, priority badge, tags, progress bar, and due-date badge as the
  live board. Appends ↩ Restore and 🗑 buttons. Restore is omitted for
  cards inside a fully archived column (whole-column restore is the
  right action there).
- showArchiveModal(): builds the modal with DOM nodes directly (no HTML
  string), widens to min(92vw, 960px), and uses .group-cols for
  horizontal scroll. Panels sorted newest-archived first. Includes a
  legend row distinguishing the two panel types. Empty state preserved.

https://claude.ai/code/session_01VxiEThbmeb8Y6ro3A68Mnd
…n-SVfAr

Redesign archive modal to mirror the board's visual layout
Creates Section 60 Checklist.html from the section00-template, populated with all
60.001 required information items for Cover Drawing (30 items) and Right of Way
Plan Drawings – General (42 items), with source bold formatting preserved via
HTML strong tags.

https://claude.ai/code/session_017f8GsiJFXxhAyvEViGmJxs
…klist-uF70W

Add Section 60 Right Of Way Plans Checklist
Creates Section 50 Checklist.html from the section00-template, populated with
all content from sections 50.001 General (1 item), 50.002 Required Information
(26 items covering ESPCP cover drawing requirements), and 50.002 Additional
Items (1 item noting optional delineation elements).

https://claude.ai/code/session_017f8GsiJFXxhAyvEViGmJxs
…cklist-uF70W

Add Section 50 Erosion, Sedimentation and Pollution Control Checklist
Replaces the one-line placeholder with a complete overview covering both tools:
FlowBoard (features, sync, backups, themes) and the PPG compliance checklists
(Sections 24, 50, 60). Includes a combined workflow showing how the two tools
complement each other, a quick-start guide, and a clear statement of the target
audience (GDOT civil engineers and consultants).

https://claude.ai/code/session_017f8GsiJFXxhAyvEViGmJxs
…cklist-uF70W

Rewrite README with full product marketing copy
Moves the uploaded demo images into assets/screenshots/ for clean repo
organization and adds a two-column light/dark comparison table in the
FlowBoard section of the README so visitors get an immediate visual of
the tool.

https://claude.ai/code/session_017f8GsiJFXxhAyvEViGmJxs
…cklist-uF70W

Add FlowBoard screenshots and embed in README
Comprehensive engineer-facing spec covering all 9 pages/modals, data model,
color palettes, animations, drag-and-drop mechanics, Firebase sync system,
undo/redo, and implementation notes derived from the reference flowboard.html.

https://claude.ai/code/session_01SXRYeiXpndK6y9y9Bo3Ls7
…mpt-Tw6gQ

Add detailed FlowBoard website implementation prompt
…n00-template-to-section-50-checklist

Add Section 50 ESPCP cover drawing checklist
claude and others added 30 commits June 13, 2026 03:32
The card modal stops propagation on its own clicks, so the old bubble-phase
document listener never saw clicks inside the modal and the sort menu stayed
open. Move dismissal to the capture phase (fires before the modal swallows the
event), add scroll/resize/Escape dismissal, exclude the trigger button and the
menu itself, and properly remove all listeners on close to stop the leak.
… time

- notify() default duration 2600ms -> 7800ms (triple), and now clears any
  pending hide-timeout on a new call so a fast second toast isn't cut short
  by the first one's timer.
- localStorage save failures now distinguish quota-exceeded vs blocked
  storage (private/incognito) vs unknown error, and report actual board/
  backup/auto-snap sizes so the message reflects what's really happening
  instead of a generic "storage may be full" guess.
- Firebase per-edit write failures were previously silent to the user (only
  the sync badge changed color, error logged to console). They now surface
  a toast with the Firebase error code/message and a note that the local
  copy is safe, distinguishing offline vs permission-denied vs other errors.
Extracts Flowboard's local+cloud persistence architecture (autosave,
undo/redo with crash recovery, manual + automatic snapshots, export/
import, diff viewer, whole-document cloud sync with a heuristic safety
gate) into a config-driven module that doesn't assume any particular
state shape or a global named S. A minimal demo task list proves the
module end-to-end; the DSK_CONFIG block at the top is the only section
meant to change when adopting this in another program.

Also fixes a known inefficiency from the original Flowboard
implementation: auto-snapshots are now stored as individually keyed
Firebase children instead of one whole-array overwrite per snapshot.

Includes a prominent integration warning listing 8 conditions (existing
undo system, non-matching state shape, partial-update cloud writers,
regulated data, multi-writer concurrency, existing soft-delete/
versioning, different storage-budget assumptions, non-function-based
mutations) under which an integrator should flag the conflict to a
human instead of silently implementing.
…al backup interface

Replaces the earlier minimal mockup with the real thing: the Backup &
Restore modal, auto/manual snapshot lists, Compare/diff viewer, and
their CSS (buttons, .bak-item/.auto-bak-item, .diff-* classes,
.overlay/.modal) are cloned from Flowboard's showBackupModal()/
showDiffPicker()/showSnapshotDiff(), not reimagined. Theme is fixed to
Flowboard's "pearl" light variables, no dark option, per request.

The DSK module underneath is unchanged in behavior; only its UI-facing
surface (setModal/closeModal, the modal HTML builders, triggerBadge,
diffExpand) was added so the generic DSK_CONFIG adapters now drive the
same interface instead of a scaled-down demo panel. Flowboard's
USB-drive section is intentionally omitted (hardware file-access
feature out of scope for this generic kit) and noted as such in a
comment rather than silently dropped.
Rebuild Data Safety Kit UI as a light-theme clone of Flowboard's actu…
…dd drag edge auto-scroll

Four fixes from the audited bug list, in order:

1. Card modals in light themes now tint with the card color
   (color-mix 8% toward white) instead of staying flat white — the tint
   was previously applied only when !isLight(), in both renderCM and
   setCMColor; extracted shared _cmModalBg() helper.

2. Checklist truncation preview is now robust: the hover handler moved
   from the text span to the whole row (the chevron/x/badge zone where
   the ellipsis visually sits previously had no handler at all), and the
   truncation test gained a sub-pixel Range measurement to catch text
   overflowing by less than 1px, which the integer scrollWidth
   comparison misses.

3. Description box gets a custom 34px grab handle (double the native
   ~17px resize corner), always visible, pointer-event based so it works
   with touch, persisting height through the existing EC.descH path. The
   native resize:vertical corner remains as a fallback.

4. Dragging a column or card near the edge of a scrollable container now
   auto-scrolls it (group row horizontally, limited column bodies and the
   board vertically) via a rAF loop that keeps scrolling while the
   pointer holds still in the 70px edge zone, refreshing the drop
   indicator as content moves under the pointer. Previously a drag could
   never reach an off-screen destination.
… scale setting

Due dates: when a card's due is auto-synced from checklist items, the
header now shows a ✕ button that clears every item's due date in one
click (guarded by confirm + a pre-action auto-snapshot). Previously a
synced due date could only be removed by opening each item's calendar
individually. Card due is cleared explicitly since the sync leaves the
stale derived date in place once no item has a due.

UI scale: new "UI Scale" section in the settings panel with −/+ stepping
(60–150%) and an Auto mode that seeds the scale from the screen width
(0.85–1.1 across <1300 to ≥2400 px). Manual choice persists in
localStorage — deliberately per-device, not in synced prefs, since the
right scale differs between monitors (the reported home-vs-work problem).
Applied via body zoom at boot.
…phan purge

Option B storage/sync stopgap:

- CRITICAL correctness fix: a failed local (localStorage) write no longer
  falls through to push to the cloud. Previously save() bumped
  lastModified and ran the Firebase set() even when the local write threw
  quota-exceeded — leaving the device's disk behind the cloud and
  silently desyncing it on the next reload/tab-discard. This is the
  mechanism behind "sync stopped being reliable after switching devices."
  Now: on unrecoverable local failure the timestamp is reverted, the sync
  badge shows error, and nothing is pushed, keeping the cloud consistent
  with what the device can actually persist.

- Auto-cull safety valve: on a quota error, reclaim space (purge orphaned
  auto-snap stores, then trim every board's auto-snaps to the 3 newest)
  and retry the write once before surfacing a hard error. Manual
  snapshots are never touched.

- Honest usage gauge: the "storage nearly full" warning now measures TRUE
  origin-wide localStorage usage across all keys, not just the current
  board's 3 keys — so it can no longer stay green while other boards'
  backups fill the shared ~5MB quota.

- Orphan purge on load: auto-snapshot stores for boards no longer in the
  keys list are removed at startup (disposable auto-snaps only, keyed by
  share-key; user-created manual snapshots are never auto-deleted).

Verified headlessly: failed write reverts timestamp + skips cloud push +
shows error badge; successful auto-cull retry saves and notifies; gauge
counts other boards; orphan purge removes dead stores and keeps live ones.
…a real storage usage bar

Implements items 1-3 from the storage/sync report:

1. Persistent save-error banner: local-save failures now show a
   body-level banner (survives full board re-renders, unlike a toast)
   with real action buttons (Export Backup Now / Open Backups) instead
   of prose telling the user where to go. Auto-hides the next time a
   save succeeds; auto-dismissible manually. Quota failures also
   invalidate the cached capacity probe, since a failure despite a
   cached "plenty of room" reading means that reading was wrong.

2. Backups button now reflects real storage state: green/amber/red
   (70%/90% of measured ceiling) plus a red dot badge when an
   auto-cull has run and not yet been acknowledged. A small persisted
   cull log (fb4_cull_log/fb4_cull_ack, capped at 10 entries) drives
   both the badge and a banner inside the Backup modal itself
   ("Storage auto-cleanup ran on <date> — N old auto-snapshots
   removed"). Opening the modal acknowledges it and clears the red
   state.

3. Real storage usage bar in the Backup modal, backed by an empirical
   capacity probe (_probeStorageCapacity): binary-search-writes a
   throwaway key to find this browser/profile's actual localStorage
   ceiling instead of guessing a per-browser constant that drifts out
   of date across versions. Cached (fb4_cap_probe), runs lazily off
   the initial render tick on first Backup-modal open so it can't
   block the UI, with a manual "Recalculate" action. _storageStats()
   is now the single source of truth for usage/ceiling/percentage,
   replacing the old hardcoded 4MB threshold that was duplicated
   across the save() warning, so the toast, button color, and bar can
   no longer disagree with each other.

Verified headlessly: probe finds a plausible ceiling and cleans up its
own temp key; storage bar renders and Recalculate works; cull event
turns the button red with a badge and the modal shows the banner;
opening the modal acknowledges and clears both; the error banner
appears with working action buttons, survives a full render() wipe,
and hides itself on the next successful save.

Note: item 4 from the report (orphan auto-snapshot purge currently
runs silently and irreversibly on every boot) is NOT addressed here —
scoped out of this round per explicit instruction, but still an open
risk flagged for a follow-up.
Add persistent save-error banner, backups-button warning states, and …
… modal

Item 4 from the storage/sync report. The previous _purgeOrphanAutoSnaps()
ran on every boot and permanently deleted any local-only (or removed-key)
board's auto-snapshots with zero confirmation — for boards that were never
cloud-synced, those were the only copy, so this was quietly destroying
unrecoverable data on every launch.

- _findOrphanAutoSnaps() is now a pure detection function (never deletes),
  shared by both paths below.
- New boot-time flow: _checkOrphanSnapshots() runs once per fresh page
  load (400ms after boot, so it doesn't compete with initial paint/sync/
  USB-reconnect) and, if orphaned groups exist, shows a review modal
  listing each one (board key, snapshot count, size, date range) with
  per-group Export All / Delete This Group, and a per-snapshot expander
  with individual Restore-into-current-board / Export. Dismissing via
  "Keep All For Now" deletes nothing — the same groups are re-detected
  and re-shown on the NEXT startup, for as long as they still exist.
- The emergency quota-reclaim path (_reclaimSpace, used mid-save when
  storage is full and there's no time for a prompt) keeps its original
  silent/automatic behavior via a refactored _purgeOrphanAutoSnaps() built
  on the same detection function — that cull is still surfaced afterward
  via the existing cull-log/banner (item 2), just not gated on a prompt,
  since blocking a save on user input would defeat its purpose.

Verified headlessly: modal auto-shows on boot for a seeded orphan, data
is untouched by showing/dismissing it, reappears on next reload after
"Keep All For Now", Export All doesn't delete, per-snapshot rows render
and both restore-into-current-board and explicit group deletion work,
and the modal stops appearing once resolved. Also verified the emergency
reclaim path is unaffected and still silent/automatic.
…fallback

First of four commits for item 5. Pure addition — this IDB layer is NOT yet
wired into getBaks/setBaks, so behavior is completely unchanged.

- _openIdb / _idbGet / _idbPut / _idbDelete / _idbKeys: a ~90-line vanilla
  IndexedDB wrapper (no dependencies, single-file property preserved), two
  object stores (manual, auto) keyed by the same key strings used today
  (fb4_baks_<boardId> / fb4_auto_<key>), values are the snapshot arrays.
- Every op degrades safely: unavailable IDB, blocked opens, and transaction
  errors all resolve to null/false/[] rather than throwing, so callers can
  fall back to the existing localStorage path.
- _idbCheckUsable: one-time round-trip probe (write/read/delete) that
  detects IndexedDB that exists but silently fails to persist (private mode,
  opaque file:// origins) before we trust it.

Verified headlessly in Chromium: full round-trip works AND data persists
across a page reload on a file:// origin (the load-bearing feasibility risk
for this whole migration). Full browser/device matrix still pending (Phase 4).
…rror

The cutover. Backups (manual + auto snapshots) now live in IndexedDB;
getBaks/getAutoBaks/setBaks/setAutoBaks keep their synchronous signatures
by reading/writing an in-memory mirror of the current board's IDB record
(Option B). All existing call sites are unchanged.

- Mirror + hydration: _hydrateManualMirror/_hydrateAutoMirror load the
  current board's record from IDB; getters return the mirror (or [] while
  a stale/unhydrated key re-hydrates); setters update the mirror and
  persist immediately (puts are cheap — no debounce, so no lost-on-close
  window). setters refuse to persist when the mirror isn't hydrated for
  the current board, so they can never clobber unloaded data.
- One-time migration (_migrateAllBackupsToIdb): moves every fb4_baks_* /
  fb4_auto_* from localStorage into IDB, sequentially, verifying each
  round-trip before deleting the localStorage original (reclaiming the
  space that was the whole problem). Corrupt/failed entries are left in
  place and retried next boot. Gated by fb4_idb_migrated.
- Boot ordering: _initBackupStore() (probe usability -> migrate ->
  hydrate) runs before session-start snapshot, orphan review, and
  initSync, so nothing reads backups before the mirror is ready.
- Cloud-listener race fix: the auto-snapshot Firebase listener now
  attaches only AFTER _hydrateAutoMirror() resolves, guarded by a
  captured-key check, so a merge can't run against an empty mirror and
  overwrite un-pushed local-only snapshots.
- _applyRemote re-hydrates the manual mirror on board switch/join.
- item 4 orphan review rewritten to enumerate the IDB 'auto' store
  (async detection cached in _orphanGroups; sync modal + handlers;
  async delete). item 2 emergency reclaim stays localStorage-only
  (correct: culling IDB can't relieve a localStorage-quota failure, and
  the tiny live board rarely triggers one).
- Full localStorage fallback: if IDB is unusable (private mode, opaque
  file:// origin, absent), _backupsUseIdb stays false and every function
  uses the original localStorage path. Also hardened pre-existing USB
  _usbIDB() against a missing indexedDB (it called .open unguarded).

Live board (fb4) intentionally still in localStorage — loads
synchronously at boot; a total IDB failure costs backup history, never
the working board.

NOTE: the storage gauge (item 3) still reads _lsBytes and will now show
near-empty since backups left localStorage — the IDB usage isn't
reflected until commit 3 (navigator.storage.estimate). Cosmetic only.

Verified headlessly in Chromium (file://): migration moves+verifies+
deletes originals; sync mirror reads; create/restore/delete for manual
and auto; persistence across reload; orphan review reads IDB and deletes
from it; and the localStorage-fallback path works with zero errors when
IDB is forced unavailable.
…mate()

Now that backups live in IndexedDB, the localStorage-only gauge (_lsBytes)
would read near-empty and misreport. Switch _storageStats() to the origin
Storage API:

- _refreshStorageEstimate() caches navigator.storage.estimate() {usage,quota}
  (async); _storageStats() reads the cache synchronously so the save()-path
  warning and the Backups button color stay synchronous. Refreshed at boot,
  on modal open, and via the bar's Recalculate button.
- Falls back to the previous localStorage probe before the first estimate
  resolves, or where the Storage API is unavailable.
- Storage bar formats large ceilings as GB, labels the source
  "(IndexedDB + localStorage)", and keeps a 1% sliver visible when usage is
  tiny against a huge quota. Button thresholds (70/90%) now reflect true
  disk-backed pressure, so red/amber effectively only appear under the
  localStorage-fallback backend or a genuinely full disk — which is correct.

Verified headlessly on file:// (Chromium): estimate resolves, gauge reports
real quota (895MB in the sandbox) at ~0%, bar renders, no errors.
Final robustness pass for item 5.

- _requestPersistentStorage(): best-effort navigator.storage.persist() at
  boot so the browser is less likely to evict our IndexedDB under disk
  pressure. Non-blocking, checks persisted() first, tolerant of browsers
  that ignore/prompt. (Does not defend against Safari/iOS's ~7-day
  inactivity purge — cloud sync + export remain the backstop there.)

Verification (headless Chromium on file://, covering the Chromium family —
Chrome/Edge/Brave):
  * cutover suite: migrate+verify+delete originals, sync mirror reads,
    create/restore/delete (manual+auto), persist across reload, orphan
    review reads+deletes IDB — all pass, zero errors.
  * adversarial suite (all pass): migration idempotency; corrupt LS entry
    survives migration; no cross-board mirror bleed on switch; stale-write
    guard refuses to clobber an unloaded board; concurrent hydration
    dedups to one promise; empty boot doesn't crash.
  * gauge reads navigator.storage.estimate() on file:// (real quota, ~0%).
  * localStorage fallback engages cleanly when IDB is forced unavailable.

NOT covered here (no engine available in CI): Firefox (Gecko) and iPad
Safari (WebKit). file:// storage behavior genuinely varies on those, which
is exactly why the localStorage fallback exists. These need manual
verification on real devices before this is trusted as done on them —
open the file, create a snapshot, fully close and reopen, confirm it
survived. If IDB doesn't persist there, the app silently stays on
localStorage with no data loss.
Closes the Q1 gap from the drawbacks review: which backend is active
(IndexedDB vs the localStorage fallback) was previously invisible —
console-only, no UI signal — so a device silently stuck on the old ~5MB
cap looked identical to one on the large IndexedDB store.

- _backupModeInfo(): single source of truth for backend state/label,
  used by both the button and the modal.
- Backups button now also goes amber when the fallback is active (not
  just on storage-pressure %), and its tooltip states the backend and
  usage on one line.
- Backup modal's storage section gains a mode line ("✅ Backup storage:
  IndexedDB (large capacity)" / "⚠ Backup storage: Limited local
  storage only (~5MB)...") plus, when on the fallback, an explanatory
  note recommending regular exports on that device.
- One-time boot toast when the fallback engages, so it's seen even if
  Backups is never opened — gated to once per browser session
  (sessionStorage flag) so it doesn't repeat on every reload.
- The two previously-silent stale-write guards (setBaks/setAutoBaks
  refusing to persist because the mirror wasn't hydrated yet) now also
  notify() the user instead of only console.warn — rare, but a skipped
  save should never be invisible.

Verified headlessly: normal (IDB) mode shows green button + "IndexedDB"
label + no boot toast; forced-fallback mode shows amber button + boot
toast (fires on first clean session, correctly suppressed on repeat
reloads within the same session) + modal warning block; both stale-write
paths produce a visible toast. Full cutover/adversarial/gauge regression
suites re-run clean with zero errors.
…fault

Previously checking a checklist item always live-moved it toward the done
block (_autoResortDone ran unconditionally whenever no static sort was
active), which meant items could disappear from view the moment you
checked them, whether you wanted that or not.

- New per-board preference S.prefs.chkAutoResort, OFF by default —
  checking an item now just toggles its checkbox/strikethrough in place
  and stays put.
- A toggle switch ("Auto-move checked items to bottom") now lives at the
  top of the checklist Sort dropdown, above the existing sort-mode
  options. Clicking it flips the pref, persists via save(), and refreshes
  the dropdown IN PLACE rather than closing it, so it reads as a real
  switch rather than a menu action.
- toggleCMItem's auto-resort call is now gated on the toggle in addition
  to the existing !_chkSorted check, so it's fully inert unless
  explicitly enabled.
- Static sort modes (By Due Date / By Priority / Done to Bottom) are
  unaffected — they're a separate, explicit user action already.

Verified headlessly: default is off and item order is unchanged after
checking; the toggle appears in the menu; clicking it flips state without
closing the menu and persists the pref; with it on, checking an item
reproduces the exact prior live-reorder behavior; the sort menu's
capture-phase outside-click dismissal still works with the new content.
PWA packaging is superseded by a future React app; FlowBoard sync
docs now focus solely on the Firebase cross-device sync architecture.
…bluool

Remove Android PWA section from deployment report
Replaces the FFD bin-packing agenda with a CSS multi-column newspaper
flow in board order: each column (project) is a section, each card
(deliverable) is one line with a dotted note-space for handwriting, and
checklist items flow inline underneath. Priority is flagged only for
High/Med (Low is the default and was noise); progress counts are dropped.

Removes the now-obsolete machinery this layout no longer needs:
- the per-card height estimation used to balance the two columns
- the beforeprint "continued header" injection script and its ag-cont-*
  styles, plus the hardcoded Letter-size / 0.85 page-height math

Pagination is now handled entirely by the browser via break-inside:avoid
on cards and break-after:avoid on section headers, so the layout no
longer depends on guessed heights and works regardless of page size.
…bluool

Rewrite Meeting Agenda report as a two-up project flow
The "✓ Done" pill is driven by card.completed, which was a manual flag
only ever cleared by the explicit Reopen / due-✕ buttons. Checking or
unchecking checklist items updated done/completedAt but never reconciled
completed, and saveCard only maintained completedAt. So after marking a
card done (which fills all its items), unchecking an item left
completed=true and the pill stuck on both the board and the card modal.
toggleCMItem also only refreshed the modal header on a due-date change,
so a corrected flag wouldn't repaint.

Reconcile completion against the checklist on every item toggle:
- new _allItemsDone(card) helper
- toggleCMItem / toggleAllItems now set completed = all items checked, so
  checking the last item completes the card and unchecking any item
  reopens it; the header refreshes whenever the pill state changes, not
  only on a due change
- saveCard clears a stale completed flag whenever a card has an open
  item (never auto-sets, so Reopen still holds even with all items
  checked); item-less cards remain governed by the manual flag

Verified headlessly across manual-done→uncheck, check-all/uncheck-all,
Reopen-holds, and item-less-card scenarios.
…bluool

Fix sticky Done pill when unchecking items or clearing a deadline
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants