Skip to content

feat(webapp): dashboard redesign - #1399

Open
satsh-co wants to merge 23 commits into
mlco2:masterfrom
satsh-co:feat/webapp-dashboard-redesign
Open

satsh-co wants to merge 23 commits into
mlco2:masterfrom
satsh-co:feat/webapp-dashboard-redesign

Conversation

@satsh-co

@satsh-co satsh-co commented Aug 22, 2026 •

Copy link
Copy Markdown

Implements the Figma redesign of the dashboard: sidebar rail (bottom bar on mobile),
account menu, global panel, and the projects page with its empty state and
create-project modal, project dashboard page and members page. Fully responsive, since Figma has desktop frames only.

Screenshots

Homepage (global):

Desktop Mobile
localhost_3000_mock-org-1(1440x900) localhost_3000_mock-org-1(iPhone 14 Pro Max) (1)

Homepage + Account menu open:

Desktop Mobile
localhost_3000_mock-org-1(1440x900) (1) localhost_3000_mock-org-1(iPhone 14 Pro Max) (4)

Account settings page:

Desktop Mobile
localhost_3000_mock-org-1(1440x900) (2) localhost_3000_mock-org-1(iPhone 14 Pro Max) (5)

Projects page:

Desktop Mobile
localhost_3000_mock-org-1(1440x900) (3) localhost_3000_mock-org-1(iPhone 14 Pro Max) (2)

Create project modal:
localhost_3000_mock-org-1(1440x900) (4)

Project settings modal (General tab):

Desktop Mobile
localhost_3000_mock-org-1(1440x900) (5) localhost_3000_mock-org-1(iPhone 14 Pro Max) (3)

Project settings modal (API tokens tab):
localhost_3000_mock-org-1_projects(1440x900)

Project dashboard page:

Desktop Mobile
localhost_3000_mock-org-1_members(1440x900) (1)localhost_3000_mock-org-1_members(1440x900) (2) localhost_3000_mock-org-1_members(iPhone 14 Pro Max) (1)localhost_3000_mock-org-1_members(iPhone 14 Pro Max) (2)localhost_3000_mock-org-1_members(iPhone 14 Pro Max) (3)localhost_3000_mock-org-1_members(iPhone 14 Pro Max) (4)

Members page:

Desktop Mobile
localhost_3000_mock-org-1_members(1440x900) localhost_3000_mock-org-1_members(iPhone 14 Pro Max)

Todo

  • Global navigation (sidebar rail / mobile bottom bar, account menu, settings page)
  • Dashboard homepage (global panel)
  • Projects page
  • Members page
  • Project dashboard page
  • Remaining adjustments (organisation, experiment, delete, project settings)

Remarks

  • Sidebar on desktop has hamburger icon
    • Resolved: desktop shouldn’t have hamburger icon, and the sidebar transforms into a bottom navigation bar on mobile
  • Glossary doesn't exist in current implementation
    • Resolved: replaced with Members + created its pixel-art icon
  • The organisation picture functionality is not implemented in code
    • Resolved: remove it completely from the dashboard + needed to create “organisation” icon
    • What is this “camera +” icon, what does it do?
    • Screenshot 2026-08-22 at 7 24 39 PM
  • Cannot identify logged in user’s organisation to separate it from the “dashboards you’ve been invited to”
    • Resolved: small addition in code to check if organisation admin = logged in user
  • There is no “Members” icon or an “Account” icon
    • Resolved: created missing icons
  • Gauges are not representative of anything
    • Is this fine?
  • All designs, apart from the dashboard homepage, have the old navigation, the wrong background, and no breadcrumbs
    • Resolved: kept navigation in sidebar rail / bottom bar + reused homepage surface and breadcrumbs, and will reuse them across all pages
  • There is no mobile design in Figma
    • Resolved: made logical and coherent design choices and created mobile responsive UI
  • Project page design features non-existent functionality
    • Resolved: replaced "Last updated on 02/02/24" with project description and kept the existing Settings / Delete actions behind the new “⋮” menu, whose contents were never designed
  • You could create a project with an empty name
    • Resolved: “create” button is disabled until a name is entered + it's a real form now so “Enter” submits
  • "Project settings" modal is redesigned as "Edit project" modal in Figma
    • Resolved: redesigned the project settings to match the typography, inputs and button styles. Also implemented the "copy link" share button which was in the project settings page but not in the modal + made it directly appear/disappear when toggling the switch that makes the project public.

Links

AI Usage Disclosure

  • 🟥 AI-vibecoded: You cannot explain the logic. Car analogy : the car drive by itself, you are outside it and just tell it where to go.
  • 🟠 AI-generated: Car analogy : the car drive by itself, you are inside and give instructions.
  • ⭐ AI-assisted. Car analogy : you drive the car, AI help you find your way.
  • ♻️ No AI used. Car analogy : you drive the car.

First step of the dashboard redesign. Remove the mobile header and its
drawer. Implement a single navigation component that presents as a vertical rail
beside the content on desktop and as a bottom bar on mobile, with the
account menu at its end. Rework the org global panel around a consumed-
energy gauge and an extended date range picker, and add a settings panel
wired into the router.

Add the Disket Mono display face, a Figma-derived icon set, and the
supporting Tailwind and global CSS type/color tokens the new surfaces use.
Extend the API schemas and mock data/handlers to back them, with tests.

Also ignore the Vite cache directory (.vite/).
@satsh-co
satsh-co requested a review from a team as a code owner August 22, 2026 16:28
Satsh and others added 16 commits August 22, 2026 19:30
Second step of the dashboard redesign. Rebuild the Projects page in both
its empty and populated states: breadcrumb and surface shared with the
global panel, a heading row carrying the primary action, and a table of
rows whose two text columns light as one item and whose overflow menu
holds the existing Settings and Delete actions.

Rework the create-project and project-settings dialogs onto the design's
panel, fields and buttons. Project settings now opens in place from a
project row, which makes ProjectSettingsPage a duplicate of it, so that
page and its route are removed and the public sharing link it owned moves
into the dialog beside the toggle that produces it. The visibility toggle
saves on its own so that link appears and disappears with it, while
"Save changes" writes the fields and closes; a failed save keeps the
dialog open so the edits survive. Creating a project with an empty name is
no longer possible, and the form submits on Enter.

Fix the dialog transition app-wide. The panel was centred with a transform
that tailwindcss-animate's keyframes overwrote, which the shadcn default
compensates for by sliding it in from the top-left corner; centring it by
layout instead lets it fade and rise in place, with a reduced-motion
variant. Fix the account menu regrouping its organizations as it closes,
by latching the admin lookup instead of keying it on the open state.

Extract the redesign's controls into components — form field, primary and
secondary button, menu panel and item, tab nav, modal header, project row,
settings nav item, rail button — replacing the class-string constants the
first step left behind, and adopt them in the pages and dialogs already
redesigned. Drop the Figma node ids from comments, keeping the reasoning
they carried, and rename createProjectModal to kebab-case to match the
convention the rest of the components follow.
Every icon exported from the Figma file lived in a single figma-icons.tsx. Give each its own module, named
the way the icons supplied outside that file already were, and delete the
barrel. Repoint the rail, the account menu, the project row, the global
dashboard and the settings page at the new modules.

Declare the props contract once as FigmaIconProps, replacing the local
copy each icon carried, and reduce every icon's comment to a line saying
what the glyph shows — the sizes, insets, hex fills and node ids they
listed described the design file rather than the code, and went stale the
moment either changed.
Square 2px corners like the fields and buttons, lime when on, and the
palette's hover colour. Restyled in place rather than added alongside the
shadcn switch, since the project-settings dialog is its only caller.
The pre-redesign navigation, the page-header breadcrumb and the radial
chart have had no callers since the rail, the pages' inline breadcrumbs
and the consumed-energy gauges replaced them. Four test files were the
only thing still importing them, so the suite was covering code no user
could reach.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Put the page on the redesigned shell — dark surface, breadcrumb, display
title carrying the project's description and its visibility pill — and
move the project's own actions into that heading as ProjectActions, so
nothing about the project's identity is drawn from inside its panels.
ProjectSettingsPage went with it: opening settings in place from a row
made that page a duplicate of the dialog.

Replace the three radial charts with the global dashboard's gauges and
equivalences, both now shared components, and give the four charts one
section treatment: a heading, a line of context, its export control, and
no card. They sit in a cross of rules rather than in boxes, with the gaps
as padding inside the cells so the rules meet.

Rework the experiment controls: a section heading with the picker and
"Add an experiment" beside it, the selected experiment's details in a
field-styled panel, and the create-experiment dialog on the same panel,
fields and buttons as the other two dialogs.

Add the pixel-art refresh, download, share, logout, cog, padlock and
overflow glyphs, and restyle the select, the toast-adjacent controls and
the token form onto the redesign's fields and buttons.

Cover what the redesign had left untested — the rail, the account menu,
settings, the project row, the dialogs and the equivalences — taking the
suite to 124 tests, and stub ResizeObserver so Radix components can mount
under jsdom.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Put the page on the Projects page's shell — dark surface, breadcrumb,
display title — and give it the same table treatment, with each member as
a MemberRow. The invite control is a form on the page rather than a
dialog, since the API takes a single email address.

Move that call behind addOrganizationUser: the endpoint subscribes an
existing account and answers with a bare status object, so there is
nothing to validate and the page refetches the list instead.

Restyle the toasts onto the design's alert. Sonner's own rules hang off a
stylesheet it injects after Tailwind's, which no class can outrank, so
they render unstyled and restate the shape the design draws.

Let Table take classes for its scroll container, which the members table
needs to bound its own height.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Put the panel on the app's dark surface, outlined in the page's own rule
rather than the menus' green — a menu's border marks where the pointer is
working, and a panel you only read does not need that weight. The date
range picker's calendar shares the primitive and follows.

Show the public link as text instead of a read-only field: it is read and
copied, never typed into. Its copy control becomes an icon button, so it
matches the four in the project's heading.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…design

Rebuild the create-organization modal on the same shell as the create-project
and create-experiment dialogs: ModalHeader, FormField, PrimaryButton and the
bordered 560px panel, replacing the shadcn DialogHeader/Separator/Label/Input
layout with its outline Cancel button.

Submission now goes through a real form with toast.promise, and the button is
disabled while loading or while the name is blank, so the manual "name is
required" toast is no longer needed. Also drops a duplicated "Organization
Description" label block and renames the file to kebab-case to match the other
components.
…t the

pre-rename path and asserted the validation toast that the disabled submit
button replaced. It now mirrors the create-project test.
Add webapp/AGENTS.md as the source of truth for work in this folder: the
expected workflow (propose before editing, update the tests and docs alongside
the change, leave committing to the user), the conventions worth writing down —
the split between the redesign primitives in components/ui and the older
shadcn ones, the shared modal shell, the design tokens — and a section on
implementing Figma designs covering responsiveness, what to ask about versus
decide alone, extending the redesign rather than forking it, and the traps
worth checking.

CLAUDE.md points Claude at it. The README gains a pointer too.
The public toggle wrote to the API the moment it was flipped, which made it
the one control in the dialog that ignored the Save button and could commit a
visibility change the user was still deciding on. It now behaves like the
other fields: local state until Save, sent with the rest of the form.

Saving no longer closes the dialog, and the sharing link sits beside the save
button and follows the visibility that was last saved, so enabling public
access and copying the link it produces is one trip through the modal. That
saved visibility is tracked in the dialog rather than read from the project
prop, because the projects list opens the dialog with a snapshot it does not
re-pass after a save.
The four pages with a breadcrumb each repeated the same nav, the same two
colour classes and the same separator, which is how the slashes ended up
glued to the crumb labels in the first place. Replace the unused shadcn
breadcrumb with a redesign one taking the trail as a list of labels and
optional destinations, and convert the pages to it.

Separators are now spaced slashes outside the links, so hovering lights the
label alone. Only the last crumb is the current page: the organisation
dashboard's leading crumb is unlinked too, so "not a link" and "where you
are" have to stay separate.
The rule was the fourth item of the working agreement list and was getting
skimmed past. Promote it to a Commits section near the top of AGENTS.md,
stating plainly that committing and staging are the user's alone, that the
message is handed over as text at medium length, and that anything already
staged is asked about rather than assumed. The list item and the Figma
section's closing now point at it instead of restating it.
The experiment bar chart painted unselected bars with --secondary, which
is a near-black surface token in dark mode — the bars read as empty gaps
rather than as data next to the lime selected bar. Switch them to the
design's --cc-gray (#949494), the palette's intended neutral for
inactive marks.
webapp/CLAUDE.md told the agent to go read AGENTS.md, which only helps if
the pointer is noticed and acted on; it now imports the file with
@./AGENTS.md so the working agreement is in context outright. The root
instructions gain a matching line, since the nested file itself only
loads once something under webapp/ is touched.
@satsh-co

Copy link
Copy Markdown
Author

Suggestion regarding removing members:
We could add a section below the current members list, which shows old members greyed out with a button to re-invite them. Makes it easy to know who had access at some point and being able to reinvite them if needed.

The members page offered Settings and Delete as permanently disabled items,
and no endpoint stood behind either — Memberships.remove_user_from_organization
was an abstract method with no implementation anywhere.

Add DELETE /organizations/{id}/users/{user_id}, gated by the same admin check
as add-user. Nothing records who created an organization, so administrators
are protected from each other rather than ranked: the endpoint refuses to
remove an admin, and the row hides its menu for anyone who may not act.

On the page, Settings is removed rather than left inert, and Delete opens a
confirmation dialog on the redesign's modal shell. Removal is not destructive
— the invite field on the same page adds the member straight back — so there
is no type-the-name gate.
@satsh-co

satsh-co commented Sep 30, 2026 •

Copy link
Copy Markdown
Author

For the account settings + logout:

  • Add https://dashboard.codecarbon.io/ to the codecarbon-web client's Valid post logout redirect URIs in Keycloak — without it Keycloak rejects the redirect and drops the user on its own error page.
  • Confirm FRONTEND_URL is set to https://dashboard.codecarbon.io in the deployed API, since the post-logout redirect now uses it.
  • Verify SessionMiddleware is active in production — the id_token hint is stored there; without it logout falls back to the client_id hint, which still works but is weaker.

@inimaz can you help?

Satsh added 2 commits September 30, 2026 20:41
… page

Signing out revoked our access token and cleared the local cookie, but never
touched the provider's SSO session, so the next login silently re-authenticated
and sign-out appeared to do nothing. Logout now performs RP-initiated logout:
the id_token is kept at login and passed as id_token_hint to the provider's
end_session_endpoint, with post_logout_redirect_uri pointing back at the
dashboard rather than the API host. It also no longer requires a valid session
to run, and falls back to a local-only logout when the provider exposes no
end_session_endpoint or is unreachable.

The settings page only ever showed a read-only email and two controls wired to
an env var that was never defined, since email and password belong to the
identity provider. Its route is removed and the account menu now hands off to
the provider's account console through a new /auth/account redirect, keeping
the issuer URL server-side. The page itself stays in the tree, unrouted.

Also sets SameSite on the session cookie and relaxes Secure outside production,
which is what kept it from being stored at all in local development.
Organizations get a dedicated rail item above Account, with a new
pixel-art building icon drawn slightly larger so it balances its
siblings. The organization list, the "add new organization" action and
the create modal move into OrganizationsMenu, leaving the account menu
with just Settings and Log out. Both menus now open beside the rail,
bottom-aligned to their buttons with an 8px gap. Tests are split to
match.
@satsh-co

satsh-co commented Sep 30, 2026 •

Copy link
Copy Markdown
Author

Todo list from meeting of 12/09/2026:

  • Add created icons to the Figma

  • Add spaces before and after slashes in breadcrumbs

  • Replace Dark Gray color in the bar chart with a lighter gray (#949494 present in palette)

  • Fix and update the "Add new organisation" modal to the new design

  • “Make project public” should not directly save, but rather wait for save button to be clicked. The latter doesn’t close modal anymore but makes the copy link appear.

  • Move organizations to a separate button to save space and show a lot of organisations

    • + created organizations icon
  • Members page: remove Settings option from dropdown and make sure Delete is visible and works for admins only

  • Global settings:

    • Do not ship profile page (kept in code but not accessible)
    • Replace Settings with a link that redirects to Keycloak dashboard
    • Fixed the bug that prevented users from signing out
    • To check with @inimaz if we are able to redesign the auth pages on Keycloak to match the new design
  • Add AGENTS.md

Load Matomo from VITE_MATOMO_URL / VITE_MATOMO_SITE_ID and send a page
view on first load and on every router pathname change, since the SPA
would otherwise only register the landing route. Query strings are not
tracked, and nothing is sent when the vars are unset, so dev and mock
builds stay out of the production site.
@satsh-co

satsh-co commented Sep 30, 2026 •

Copy link
Copy Markdown
Author

Matomo tracking:

  • Create a Matomo site for the dashboard
  • Check the webapp can be tracked (route changes, events, sign-up)
  • Add page view tracking, including route changes (webapp, env-driven instead of index.html)
  • Add date picker, CSV export, share and chart-time events
  • Add the account-created event (server-side in the API)
  • Add the activation funnel events (organization, project, experiment, token, first run)

Todo:

  • For the webapp, set VITE_MATOMO_URL and VITE_MATOMO_SITE_ID in the production build env.
  • For the server, set MATOMO_URL and MATOMO_SITE_ID in the production build env.
  • Update privacy policy?
  • Verify if we keep the dashboard stats in a separate site or the original site and enable subdomains? I already created a new one but we can always change the site ID and update the options on the Matomo side. @SaboniAmine @benoit-cty

Satsh added 2 commits September 30, 2026 22:51
Add a trackEvent helper and use it for the activation steps
(organization, project, experiment and token creation), sharing, CSV
export, date ranges and time spent on each chart. The API reports
account_created and an experiment's first_run_received through a small
best-effort MatomoTracker, so the funnel covers what the browser can't
see. Events carry no identifier, Matomo runs cookieless in the webapp,
and everything stays off unless MATOMO_URL / MATOMO_SITE_ID (API) and
VITE_MATOMO_URL / VITE_MATOMO_SITE_ID (webapp) are set. Both
.env.example files list them, and the privacy policy mentions the
analytics.
The rail label is hyphenated ("Organiza-tions") so it breaks on the narrow
rail, which leaked the hyphen into the button's accessible name and broke
the sidebar-rail test. Set aria-label to "Organizations"; the visual label
is unchanged.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants