Skip to content

Console redesign: contacts, lists and segments in one page, with a contact sheet - #539

Merged
pierre-b merged 6 commits into
devfrom
feat/contacts-lists-redesign
Nov 12, 2026
Merged

pierre-b merged 6 commits into
devfrom
feat/contacts-lists-redesign

Conversation

@pierre-b

@pierre-b pierre-b commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Spec 4 of the Nuit claire console redesign. Frontend only; the server parts are in #529.

What changes

  • One page for contacts, lists and segments. A rail lists All contacts, the lists and the segments. Selecting a list shows its KPI strip by status, its settings bar (visibility, double opt-in and its template, ID, Edit list) and the members with their status in the list. Selecting a segment shows what it is defined by and its build status (Recompute, Edit segment). The Lists page is removed and /lists redirects to Contacts.
  • Table. It has a unified search (email, name or external ID), filter chips from « Filter by… », status count tabs on a list, column choice, Load 50 more (capped at 10,000), empty and error states, and bulk actions.
  • Contact sheet. It is a URL-driven full drawer (?contact=<email>), and Back closes it when it was opened from the table. You walk the loaded rows with J/K, and J loads more rows at the last one. The sheet has:
    • a header with Gravatar, a copyable email, and refresh and delete actions;
    • KPIs: emails received, open and click rates, last activity, site visits;
    • an Activity tab with filters;
    • Messages and Web visits tabs (summary, sessions, journey);
    • an aside with inline-editable profile and custom fields (filled first), tracking consent, system dates, and the lists (subscribe, change status, remove) and segments cards.
  • Rights. Every block follows its own permission: contacts, lists, segments, message history, web analytics, and templates. A member with Lists read only lands on Contacts and sees the lists.
  • Shared components (additive).
    • DrawerNav gains totalLabel and buttons.
    • KeyValueList items take an optional key.
    • BulkUpdateDrawer, CreateListDrawer and DrawerSegment can be controlled.
    • TrackingConsentEditor is restyled for the sheet panel; it is only used there.
  • Translations and changelog. New strings are translated in all catalogues, and the CHANGELOG bullet is under 44.0.

Tests

  • vitest: full suite green before the last merges (4,815 tests; the one failure it found, landing for lists-only members, is fixed in this PR). Touched files are green after the merges of dev.
  • tsc, eslint, build: green.
  • e2e:
    • Contacts, lists, segments and protected pages were run against a local dev server: 74 of 75 pass.
    • The one failure is LogsPage loads and renders logs content. It already fails on dev, because the page description changed.
    • The specs and fixtures were updated for the rail and the sheet. Segment fixtures now carry a tree, as the server sends.

Review

  • Plan: reviewed, findings integrated in plans/contacts-lists-console-redesign-plan.md.
  • Code review: an independent review of the first commit, then of each fix delta. Each fix has a test that fails without it.

Known, not addressed

  • A search typed less than 300 ms before clicking a row is not kept when the sheet is then closed with Back. The browser history merges the search write and the sheet push into one entry.
  • saveFields writes the caches without cancelling an in-flight refetch, so a refetch already running can briefly show the value from before the edit.
  • After J loaded more rows, closing the sheet returns to the entry from before it opened (50 rows).
  • During a load-more, the optimistic delete targets the new, still-empty cache key, so the row stays until the refetch.
  • A hand-built URL with segment_id plus several segments shows the « In any of » chip, which the query ignores.
  • No dayjs locale is loaded in the console, so relative durations and ll dates stay in English in every language. This affects the whole console.

Docs: Notifuse/docs docs/contacts-lists (to be opened against dev).

…ct sheet

Contacts, lists and segments share one page with a rail; the Lists page now
opens it. The contact sheet is a full drawer driven by ?contact=, walked with
J and K, with inline editing, KPIs, filtered activity, messages and web visits.
Cleared fields clear in the sheet and the table, profile rows keep their own
field while editing, a pending search no longer closes a sheet just opened,
goal values keep their cents. Translations of the new strings.
…design

# Conflicts:
#	console/src/components/contacts/SegmentsFilter.tsx
#	console/src/components/lists/DeleteListModal.test.tsx
#	console/src/components/lists/ListDrawer.test.tsx
#	console/src/components/lists/ListDrawer.tsx
#	console/src/i18n/locales/ca.po
#	console/src/i18n/locales/de.po
#	console/src/i18n/locales/en.po
#	console/src/i18n/locales/es.po
#	console/src/i18n/locales/fr.po
#	console/src/i18n/locales/it.po
#	console/src/i18n/locales/ja.po
#	console/src/i18n/locales/pt-BR.po
#	console/src/pages/ContactsPage.test.tsx
#	console/src/pages/ContactsPage.tsx
#	console/src/pages/ListsPage.tsx
…y members land on Contacts

A search still waiting for its timer is written to the URL before the sheet
opens, so closing the sheet keeps it. A member who can only read lists lands on
Contacts, which holds them. Wording fixes in fr and pt-BR.
…design

# Conflicts:
#	console/src/i18n/locales/ca.po
#	console/src/i18n/locales/de.po
#	console/src/i18n/locales/en.po
#	console/src/i18n/locales/es.po
#	console/src/i18n/locales/fr.po
#	console/src/i18n/locales/it.po
#	console/src/i18n/locales/ja.po
#	console/src/i18n/locales/pt-BR.po
@codecov

codecov Bot commented Nov 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.96%. Comparing base (6688f19) to head (2070ee8).

Additional details and impacted files
@@           Coverage Diff           @@
##              dev     #539   +/-   ##
=======================================
  Coverage   88.96%   88.96%           
=======================================
  Files         377      377           
  Lines       73836    73836           
=======================================
+ Hits        65688    65689    +1     
+ Misses       5439     5437    -2     
- Partials     2709     2710    +1     
Flag Coverage Δ
unit 88.96% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pierre-b
pierre-b marked this pull request as ready for review November 12, 2026 18:05
@pierre-b
pierre-b merged commit 58b8c06 into dev Nov 12, 2026
5 checks passed
pierre-b added a commit to Notifuse/docs that referenced this pull request Nov 12, 2026
Documents Notifuse/notifuse#539: the lists in the Contacts page's rail, the contact sheet and the rights each part needs, and the Web visits tab.
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.

1 participant