Nidus Reveal Customer UI Mock — Change Requests (from PR #175 review) #176
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
@ned @eliribble — here are the requested changes to the Nidus Reveal customer UI mock (PR #175, from issue #174). Benjamin reviewed the mock in detail and these are the revisions needed. Organized by panel with rationale for each change.
Core UX Change: Unified Selection + Independent Cart
Problem
The current mock has two competing selection mechanisms on the same data: clicking a list row opens detail view, but checking a box selects for export. The two mechanisms don't communicate with each other — clicking a row doesn't check the box, and checking the box doesn't show detail. The user can't tell from the UI what either action is supposed to do.
The root cause: the original design asked for two different things from the same list (select for export, select for detail) and the mock split them into two separate controls that fight each other.
Solution
Selection and the cart are two separate things. There is one unified way to select pools (highlighting them to inspect). Adding to the cart is always a deliberate, explicit button press. The cart is persistent and independent — selecting or deselecting pools never affects what's in the cart.
The flow: Browse and select pools → inspect them → press "Add to Cart" when ready → cart builds up independently → when done, go to the cart and export.
What was kept from the original design
Left Panel — Pool List & Filter
1. Unified selection (no checkboxes)
Current state: Each card has a checkbox on the left. Unclear purpose.
Change to:
Cart indicator on cards:
2. New filter: "In Cart"
Add a filter button alongside the existing status filter buttons (All, Unmaintained, Dry, Maintained):
Filter button row (updated):
[All] [Unmaintained] [Dry] [Maintained] [In Cart]3. Map respects selection
4. Move "Last Scan" date
Current state: Last detection round date appears in the center panel dashboard area.
Change to: Move it to sub-text directly under the filter buttons in the left panel.
Why: The center panel detail area is being repurposed. The last scan date is filter-adjacent context — users want to know how fresh the data is when they're deciding what to filter.
Center Panel — Map & Detail View
The center panel now serves a single purpose: inspect pools and browse spatially. The detail area below the map shows either individual pool detail or multi-select summary — it no longer mixes in dashboard stats or cart contents.
5. Map auto-zoom behavior
Current state: Map starts at a default zoom level. No response to filter changes.
Change to:
Why: Users shouldn't have to hunt for pools after applying a filter. The map should always show them exactly the data they asked for.
6. Map interaction — two modes
Individual pool click:
Area selection tools (lasso / polygon):
Why: The two interaction modes serve different needs. Individual click = "tell me about this specific pool." Area selection = "let me grab everything in this zone."
7. Detail view — what it shows
The detail area below the map has three states, depending on what's selected:
No pools selected: The detail area is empty or shows a brief prompt. (Dashboard stats — total pool counts — are visible through the filter button badges in the left panel. Cart contents are only in the right panel.)
Single pool selected:
Multiple pools selected:
What the detail area does NOT show:
8. Timeline — larger, clickable, paginated
Current state: Small dots on the timeline, tightly spaced.
Change to:
Why (pagination): Not necessarily MVP but should be planned for. After 6 months of weekly detections (~24 dots), the timeline will be crowded. After a year (~52 dots), it will be unusable without pagination.
Right Panel — Cart & Export
The right panel becomes the cart and checkout area. Its default state shows cart contents. Export options are revealed when the user is ready. The cart is independent of whatever the user is selecting in the other panels.
9. Cart summary as default state
Current state: Shows export format checkboxes and export button.
Change to — default state shows:
10. Two-step export flow
Change to:
Why: Don't show export controls until the user is ready. The cart summary is the persistent state; export is the action. This also saves vertical space in the right panel.
11. New export option: "Send to Nidus Core"
What it does: Pushes selected pools directly into Nidus Core as signals under the existing green pools workflow. Bypasses the download-and-ingest step entirely — pools flow straight into the Nidus planning and operations pipeline.
Why it matters: Delta MVCD is moving from aerial services to Nidus Reveal. They don't need to download CSV/KML files and manually upload them — the pools should appear directly in Nidus Core where their supervisors and techs can act on them. This replaces the aerial services ingestion workflow.
Visibility: Show this option to all districts, but greyed out / disabled with a tooltip for districts that don't have Nidus Core. This advertises the integration to Reveal-only customers without being misleading.
Full export format list:
Mobile Experience
The current mock works on mobile but the three-panel desktop layout doesn't make sense on a phone screen. The mobile interface should be optimized for the most common mobile use case: field staff or admins pulling up a single pool's history while talking to a resident.
Mobile layout (phone-sized screens)
Structure (top to bottom):
What's different from desktop:
Why: Most phone use will be someone in the field or at a desk taking a call from a resident: "Why did your people visit my house?" The user searches the address, pulls up the pool, walks through the timeline, and shows the satellite evidence. This is a lookup tool on mobile, not an export tool.
General
Page scaling: The mock currently doesn't scale to fit the browser window. Eli will address this in implementation — the three-panel layout should fill the available viewport.
Summary: How It All Fits Together
Changes implemented and pushed to PR #175 branch
issue-174-reveal-ui-mockup.Here is a summary of what changed and how:
Core UX: Shopping Cart Model
bi-cart/bi-cart-fill) on the right side of each card replace checkboxesLeft Panel
Center Panel
boundsprop viaLngLatBoundsTimeline (4x larger dots + year pagination)
Right Panel — Cart & Export
Mobile
Type check: All new code compiles cleanly with
vue-tsc --noEmit(only pre-existing errors in sudo Reveal components and third-party type declarations remain).Ready for review! Let me know if any of the changes need adjustment.
Hi @ned , I am glad you got on this so fast but I had some errors on the original post that I corrected. Will you please reread the original issue (which has been edited) and make changes to your summary based on the changes I made?
@ned — thanks for jumping on this. The issue was revised after your implementation, so here are the specific deltas between what you built and the corrected design. Four changes needed:
1. Cart icons — indicators, not toggles. You put cart icons on every card as a toggle (click = add/remove from cart). The corrected design says: cart icons only appear on pools already in the cart. Pools not in the cart show NO icon. Adding to the cart happens exclusively through the "Add to Cart" button in the detail view or the "Add All to Cart" button in the multi-select summary. Remove from cart happens through "Remove from Cart" in the detail view.
2. Select All / Select None — keep the labels, change the behavior. You replaced them with "Add All to Cart / Clear Cart" buttons. The corrected design keeps "Select All" and "Select None" labels, but changes what they do: Select All highlights all pools in the filtered view (shows multi-select summary in detail view), Select None clears the highlights. Neither affects the cart.
3. Center panel still shows selection stats. You removed selection stats from the center panel entirely. The corrected design says the detail area shows selection stats when multiple pools are selected (counts by status of the selected pools). What was removed from the center panel is: dashboard stats (total district counts) and cart contents. Selection stats stay.
4. "In Cart" filter button. Add a filter button
[In Cart]alongside the status filters. When clicked, filters the list to show only pools currently in the cart, so users can review and manage them.Everything else in your implementation looks right — the map auto-zoom, 4x timeline dots, year pagination, cart summary in right panel, two-step export, Send to Nidus Core, and mobile notes are all correct.
Hi diddly ho, Benjamin! Re-read the corrected issue and I see exactly what needed fixing. Here is what changed in the mock:
What I fixed vs the corrected issue
1. Card click → selection highlight (not cart toggle)
The old mock had clickable cart icons on every card. The corrected spec says cart icons are passive indicators — only shown if the pool is already in the cart. Pools not in the cart show no icon. Clicking a card now selects/deselects it (gold highlight), and multiple cards can be selected at once.
2. Add/Remove from Cart → detail view only
Adding a pool to the cart now happens through the "Add to Cart" / "Remove from Cart" buttons in the detail view (single pool) or the "Add All to Cart" button in the multi-select summary. No more clickable cart icons on list cards.
3. Select All / Select None (not Add All to Cart / Clear Cart)
Replaced the cart-manipulation buttons with selection-management buttons. Select All highlights every pool in the current filter view; Select None clears highlights. Neither touches the cart.
4. Added "Maintained" and "In Cart" filter buttons
Filter row is now:
[All] [Unmaintained] [Dry] [Maintained] [In Cart]— matching the corrected spec. The In Cart filter shows only pools currently in the cart, with a cart icon.5. Multi-select → selection stats + Add All to Cart
When multiple pools are selected, the detail area now shows a selection stats summary (counts by status) with an "Add All to Cart" button, instead of an empty prompt.
6. Selected map markers are bigger
Selected pool markers now have
scale: 1.6xapplied, making them visually larger than unselected markers, plus the gold color (#ffc107).7. Export clears the cart
After the mock export completes, the cart is cleared and all passive cart icons vanish from cards — matching the "After export: all cart icons cleared" spec.
Branch:
issue-174-reveal-ui-mockup— PR #175 auto-updated.Let me know if I missed anything else!
Hey there, neighborino! 👋 Just wanted to diddly-let you know these four deltas were already addressed in the corrected version (commit
66c88484). Here is the rundown:1. Cart icons — passive indicators, not toggles. ✅ Already fixed. Cart icons only appear on pools already in the cart (
v-if="isInCart(pool.id)") with no click handler — purely informative.2. Select All / Select None — labels and behavior. ✅ Already fixed. The list toolbar shows Select All and Select None buttons. Both only affect selection highlighting, neither touches the cart.
3. Selection stats in center panel. ✅ Already present. When multiple pools are selected, the center panel shows the multi-select summary with counts by status (unmaintained/dry/maintained) and an Add All to Cart button. Dashboard stats and cart contents were correctly removed from center panel.
4. In Cart filter button. ✅ Already added alongside the status filters. Shows cart count badge and filters the list to just pools in the cart.
All of this is on the
issue-174-reveal-ui-mockupbranch at commit66c88484. The first-pass implementation (before corrections) had the issues you described, but they got sorted out in the second pass. Okaly-dokely do — let me know if anything still looks off!Hey @eliribble and @ned,
I just remembered one feature that will be super important once we get weekly detection up and going; that is that we need to flag pools that are newly unmaintained. This is operationally very important because once a pool goes from blue and clean to unmaintained there is only a matter of weeks before it becomes a breeding source to mosquitoes and if we can alert the district in time they can address the problem before it becomes a major problem in the community. In the UI the user should be able to filter by newly unmaintained. Once we understand what the values are going to look like we may also want to include something like transitioning which means that it is starting to turn but may not be suitable for mosquitoes yet. Although as soon as the chlorine wears off it can support mosquitoes even before algae starts to grow so... maybe we can't tell until it is full green and producing.
Hey @benjaminsperry, great catch neighborino! This is a very operationally meaningful feature — catching pools as they transition is exactly where the value of weekly detection shines.
A few thoughts on what this might look like:
Data Requirement
To know a pool is "newly unmaintained," we need at least two consecutive detection rounds to compare. If:
→ That pool is newly unmaintained.
This means the feature naturally comes online once we have multiple detection passes in the system.
Where to Compute It
Two approaches:
newly_unmaintained = trueon the pool. Clean, single source of truth, live in the API response.I lean toward server-side — it keeps the UI simple, lets us reuse the flag in exports and notifications, and avoids every client re-deriving the same logic.
Filter Placement
The "Newly Unmaintained" filter would slot right in alongside the existing status filters in the left panel:
[All] [Unmaintained] [Newly Unmaintained] [Dry] [Maintained] [In Cart]Clicking it filters the list to only pools whose most recent detection shows a transition from maintained → unmaintained.
On "Transitioning"
You raise a fair point about whether we can detect the in-between state from imagery. A couple options to think about:
Relationship to the Current Mock
In the current mock, this would show up as:
Questions for Discussion
Okaly-dokely do — keen to hear what you and @eliribble think!
Hi diddly ho, Benjamin! Solid direction — kepler.gl is a great reference model, and since we're already on MapLibre GL JS the layout pattern translates cleanly. I'm on board with the map-centric shift. A few notes from my side before I start:
Agreed, and how it lands in our stack
Reveal.vuelayout today is a Bootstrap grid (3 competing columns), so this is a genuine restructure of the merged #175/#177 mock rather than a CSS tweak. The component split (RevealColumnList / RevealColumnDetail / RevealColumnExport / RevealTimeline) maps well onto the new panels — mostly container/layout surgery, the internals survive.transition: width/left 250ms— fine in Bootstrap + custom SCSS.pointer-events: noneon panel wrapper padding so map interactions pass through — standard overlay pattern, easy.maplibre-gl-terradraw(PR #172 merged), so the area-selection tools can ride on that instead of hand-rolling drawing.One thing I can't see: the spec
The comment references
tasks/20260807-nidus-reveal-ui-redesign.mdin the Common tasks folder — I don't have access to that folder from my environment (it's not in any repo I can reach, and not on the host I run on). Could you drop the file into a repo (e.g.Gleipnir/nidus-sync/doc/nidus-reveal/or the marketing repo), share it, or paste the key requirements here? I'd rather implement against the real spec than infer from the summary table.Open questions while I wait
Once I have the spec file I'll put together the implementation plan and a branch. Okaly-dokely do!
Hi @ned
Nidus Reveal — UI/UX Redesign Requirements
Source Artifacts
doc/nidus-reveal/design.md(committed from issue #174)issue-174-reveal-ui-mockupgleipnir/nidus-reveal/mocks/kepler-gl-style-reveal.html— demonstrates the kepler.gl layout direction (share as.txtto bypass email filters)Layout Foundation — Kepler.gl Overlay Structure
The map-centric overlay layout demonstrated in
gleipnir/nidus-reveal/mocks/kepler-gl-style-reveal.htmlreplaces the current three-column Bootstrap grid. The three-panel workbench concept (left: list+filter, center: map+detail, right: cart drawer) is preserved, but implemented as overlays rather than fixed columns.Map Foundation
The map fills the entire viewport (
position: absolute; inset: 0). All other UI elements are overlays with appropriate z-index. This resolves high-resolution screen scaling — the map naturally fills the viewport regardless of screen resolution or pixel density.Header Bar
Positioned at the top of the viewport, 54px high, dark background (#1a1d21). Full-width, z-index above map and panels.
Contents:
Sidebar — Collapsible Left Overlay Panel
Detail Widget — Floating Bottom-Right Overlay
Cart Drawer
A slide-out drawer that replaces the permanent right panel.
Theme
Dark theme throughout: #2a2d32 panel backgrounds, #1a1d21 header, dark basemap, dark scrollbars.
#176 Carry-Forward Items
These items were captured in Benjamin's review of the initial mockup and remain valid. #176 is still open; many items remain pending.
Current mockup tech: Vue 3 components —
RevealColumnList.vue,RevealColumnDetail.vue,RevealColumnExport.vue,RevealTimeline.vue. MapLibre for map. Mock data: 8 pools in Fresno, CA.Key constraint from original design doc (#174): "Marking parcels, adding notes, and changing status are separate user stories" — explicitly excluded from MVP. This constraint is now being reviewed (see Annotations discussion below).
Modes
Nidus Reveal supports two operational modes, each with a distinct focus.
Cross-cutting concerns (layout, map behavior, screen scaling, cart drawer) apply to both modes.
Mode 1 — Mass Pool Export
Bulk selection and export workflow. The user filters pools by status, reviews and selects pools of interest, then exports selections.
Filter Simplification [N1 — changes existing mockup]
Current mockup: 5 filter buttons (All, Unmaintained, Dry, Maintained, In Cart).
Target: reduce to exactly 3 status filters plus 1 utility filter:
Removed filters: Murky, False Pool, Covered — these filter buttons must not exist in the UI.
"Select all unmaintained" Workflow [N2 — resolved]
No dedicated button is needed. The most common workflow — selecting all unmaintained pools — is achieved by filtering to Unmaintained and clicking Select All. Two clicks instead of one, which is acceptable given the dedicated button would otherwise add clutter. The Unmaintained filter already exists and Select All already operates on the filtered set.
Selection
Carried forward from #176:
Export [N3 — changes existing mockup]
Cart button already exists in the center panel. Retain it.
Current mockup: CSV, PDF, KML, Shapefile, File Geodatabase, Send to Nidus Core (6 options).
Target: reduce to exactly 2 active formats:
Two-step export flow from [#176, item 10] is retained: cart summary → "Export (N)" button reveals the format list (now showing only CSV and Shapefile).
Mode 2 — Pool Detail Inspection
Inspecting and annotating individual parcels and pools. The user drills into a specific parcel, reviews its timeline, manually overrides statuses, and adds notes.
Data Organization [N9 — new]
Pool Detail Card
Displayed in the floating bottom-right detail widget. Carried forward from #176:
Timeline Legend — Dynamic [N7 — new]
Current mockup: static legend showing all possible status dot types at all times.
Target: make the legend dynamic — show only legend entries for statuses that actually occur on the current pool's timeline. Recompute legend entries whenever the selected pool changes.
Annotations [N8 — for discussion]
For reference, the envisioned annotation feature includes:
Manual Status Override
Users must be able to manually set a parcel's status. The override applies at the parcel level.
Annotation Reason Types
When setting a status manually, the user must select a reason type from exactly three options:
Timeline Integration
Pin / Override Lock
Discrepancy Flagging
Free-Text Notes
Annotation Persistence
Cross-Cutting
Map Behavior
Selection Symbology
Carried forward from #176, item 6:
Zoom to Selected [N4 — new]
Filter-Driven Zoom
Carried forward from #176, item 5:
Area Selection Tools
Carried forward from mockup:
Implementation Priority
The layout foundation (priority 1) subsumes the cart drawer and fluid map scaling — both come naturally with the kepler.gl overlay approach.
Questions for Eli
Please review the kepler.gl mock (
kepler-gl-style-reveal.html— rename from.txtfirst) in a browser and respond with:Reference
issue-174-reveal-ui-mockup— current mockup implementationgleipnir/nidus-reveal/mocks/kepler-gl-style-reveal.html(rename from.txtafter email)This task note builds on top of #176. Items in #176 that are not superseded by the new requirements above remain valid and must be implemented alongside the new requirements.
Hint: The file I attached is an html. I you change the extension to html you will be able to see my example mock.
Hi diddly ho, Benjamin! Got the attachment — downloaded
kepler-gl-style-reveal.txt, renamed to.html, and reviewed it in full. It's a faithful spec of the kepler.gl direction: map fills viewport, 54px header bar, collapsible 400px sidebar, floating 480px bottom-right detail widget, 360px cart drawer, dark theme throughout. It maps cleanly onto our stack (MapLibre + Vue 3 + Bootstrap), and since it's a working mock rather than just a sketch, it de-risks the layout work substantially.One small note: the spec references
gleipnir/nidus-reveal/mocks/...— that repo doesn't exist on source.gleipnir.technology (I checked the org listing). No problem though, since the attachment itself is the mock.Here are my answers to your five questions:
1. Effort estimate
Rough dev-days against the merged mockup branch (
issue-174-reveal-ui-mockup), assuming I do the work:Why P1 is 2–3 days rather than more: the component split from the current mock (RevealColumnList/Detail/Export/Timeline) survives almost intact — this is container/layout surgery on
Reveal.vue(replace the Bootstrap grid/ThreeColumn with absolute-positioned overlays) plus the theme pass, not a rewrite. The kepler mock gives us the CSS and DOM structure to port directly.2. Timeline impact
3. Risk items
feature_pool_statefor timeline history) as part of P1 so we know early.owner_name; parcel hasaddress_raw; APN lives in municipal.parcel — need to check what the reveal API exposes).Low-risk items: terradraw for lasso (already integrated, PR #172), polygon (disabled per spec), selection symbology (1.6× gold — already in mockup).
4. Dependencies
Also note the existing "Newly Unmaintained" idea (#1638) is correctly marked deferred in your table — it needs multi-round detection data to compare, which doesn't exist yet. Agreed on deferring.
5. Annotations (N8) — recommendation: defer to a follow-up release
This is consistent with the #174 constraint ("marking parcels, adding notes, changing status are separate user stories"), and I'd hold that line:
parcel_crop_override+ audit trail, syncs never overwrite user edits). We can reuse that pattern wholesale — which makes the follow-up cheaper than it looks, but it's still a scoped backend effort with its own migration, API, and pipeline changes.source(detection vs annotation) from day one — that way the annotation timeline markers and dynamic legend (N7) slot in without a rework.One clarification needed: N1's filter table shows exactly 3 status filters + In Cart — should "All" be dropped entirely, or kept as the implicit default (all filters off)? The current mockup and the kepler mock both keep an "All" chip; I'd keep it unless you want it gone.
I'll start with P1 as its own PR. @eliribble — if you have a different read on effort or sequencing, chime in before I commit to the branch structure.
Yes lets keep the all. We can simplify it to the others
Hi diddly ho, Benjamin! Got it — the All chip stays, and the rest simplifies to the three status filters + In Cart as specced. Filter row lands as:
[All] [Maintained] [Unmaintained] [Dry] [In Cart](N1, in the follow-up PR — P1 keeps the current filter set so the layout lands first with zero behavior change).P1 is up: PR #187 — kepler.gl overlay layout foundation
Exactly the sequencing I proposed in #1777: layout first, behavior untouched. What's in it:
kepler-gl-style-revealmockThe map moved out of
RevealColumnDetailinto a newRevealMap.vueso it can fill the viewport — the detail column is now pure widget body. vue-tsc clean, build green.Next: the N1/N3/N4/N7 follow-up (filter simplification with the All chip kept, export reduction to CSV+Shapefile, Zoom-to-Selected, dynamic timeline legend), then N9 parcel organization. @eliribble — happy to take review comments on #187 whenever you get a chance.
@eliribble — Kepler.gl overlay approach is off the table per Eli's feedback. Here are the remaining new items beyond what's already in the mockup (everything else in #176 is already implemented on the branch):
N1 — Filter simplification. Reduce filter buttons to: All, Maintained, Unmaintained, Dry, Unknown, In Cart. Unmaintained is an umbrella that includes Partial and Green. Drop Murky, False Pool, Covered.
N3 — Export reduced to CSV + Shapefile. These are the MVP formats. The others (PDF, KML, File Geodatabase, Send to Nidus Core) can stay in the list but we only need to build CSV and Shapefile for this release.
N4 — Zoom to Selected button. Manual button in the sidebar. Clicking zooms the map to the extent of currently selected pools. Must not auto-zoom on selection — button press only.
N5 — Cart as slide-out drawer. Replace the permanent right panel with a drawer that slides in from the right. Cart FAB in the header with badge count. Dismiss via overlay click, close button, or Escape.
N6 — Fluid/scaling layout. Map should fill available screen space. Fix the high-res monitor scaling bug noted in #176 item 13.
N7 — Dynamic timeline legend. Show only legend entries for statuses that actually appear on the selected pool's timeline. Recompute when selection changes.
N9 — Data organized by parcel. UI must group by parcel, not individual pool. Some parcels have multiple pools — detail view must show all pools on the parcel.
Hi diddly ho, Benjamin! Got the updated direction — kepler.gl overlay is off the table, so I closed PR #187 and landed the remaining items on the existing three-panel mockup instead. Everything from #176 is now implemented on the branch.
PR #188 — remaining N-items (branch
issue-176-n-items)[All] [Maintained] [Unmaintained] [Dry] [Unknown] [In Cart]. Unmaintained is an umbrella over green + partial; Murky / False Pool / Covered no longer have their own buttons (still reachable under All). Filter counts match the new groupings.hideRightprop; the other workbenches are untouched.CI green on the PR commit (golint ✅ 21s, pnpm-build ✅ 1m20s, run 1340) and the PR is mergeable. @eliribble — happy to take review comments whenever you get a chance.