Home screen#5327
Conversation
There was a problem hiding this comment.
Pull request overview
This PR replaces the previous “organizations list” landing page with a new home screen that surfaces user-tailored data (favorites + recent runs) backed by a local-storage provider, and moves the organizations listing to /organizations.
Changes:
- Implement a new home page (
/) with sections for browsing organizations, favorites, and recently started runs. - Add local-storage backed “favorites” and “recent runs” infrastructure (provider + helpers + Zustand stores) and wire it into the app.
- Add “favorite” star buttons across organization/product/repository/run pages and adjust navigation links/tests accordingly.
Reviewed changes
Copilot reviewed 29 out of 29 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| ui/tests/smoke-test.spec.ts | Updates smoke test to validate the new home page and then navigate to organizations. |
| ui/src/store/recent-runs.store.ts | Adds Zustand persisted store for per-user recent runs. |
| ui/src/store/favorites.store.ts | Adds Zustand persisted store for per-user favorites and favorite group ordering. |
| ui/src/routes/organizations/index.tsx | Introduces the organizations listing page previously served at /. |
| ui/src/routes/organizations/$orgId/settings/index.tsx | Redirects post-delete / cancel navigation to /organizations. |
| ui/src/routes/organizations/$orgId/products/$productId/repositories/$repoId/runs/$runIndex/-components/run-details-bar.tsx | Adds a run favorite button to the run details header area. |
| ui/src/routes/organizations/$orgId/products/$productId/repositories/$repoId/-components/repository-runs-table.tsx | Adds run favorites support in the runs table (including extra entity fetching for favorite context). |
| ui/src/routes/organizations/$orgId/products/$productId/repositories/$repoId/_repo-layout/runs/index.tsx | Adds repository favorite button and passes org/product IDs into the runs table. |
| ui/src/routes/organizations/$orgId/products/$productId/repositories/$repoId/_repo-layout/create-run/index.tsx | Records newly created runs into the “recent runs” home section (local). |
| ui/src/routes/organizations/$orgId/products/$productId/index.tsx | Adds product favorite button to the product header card. |
| ui/src/routes/organizations/$orgId/products/$productId/-components/product-repository-table.tsx | Adds repository favorite button in repositories table, with org/product lookup. |
| ui/src/routes/organizations/$orgId/index.tsx | Adds organization favorite button to the organization header card. |
| ui/src/routes/organizations/$orgId/-components/organization-product-table.tsx | Adds product favorite button in the products table, with org lookup. |
| ui/src/routes/index.tsx | Replaces old landing page with the new home screen layout and data hooks. |
| ui/src/routes/admin/index.tsx | Updates the admin dashboard “Organizations” card link to /organizations. |
| ui/src/routes/-components/home-recent-runs-section.tsx | Adds home section rendering recent runs with polling and cleanup-on-404 behavior. |
| ui/src/routes/-components/home-organizations-section.tsx | Adds home section with CTA link to browse organizations. |
| ui/src/routes/-components/home-favorites-section.tsx | Adds favorites home section with grouping, drag-and-drop group ordering, and data refresh logic. |
| ui/src/routes/-components/home-empty-state.tsx | Adds shared empty state presentation component for home sections. |
| ui/src/providers/home-data/types.ts | Defines types for favorites / recent runs and provider API. |
| ui/src/providers/home-data/recent-runs.ts | Adds recent-run helper functions and inline vitest tests. |
| ui/src/providers/home-data/local-home-data-provider.ts | Implements local-storage home data provider scoped by authenticated user ID. |
| ui/src/providers/home-data/index.ts | Adds barrel exports for the home-data provider module. |
| ui/src/providers/home-data/home-data-provider.tsx | Adds provider component that scopes home data by OIDC profile identity. |
| ui/src/providers/home-data/home-data-context.ts | Adds context + hooks for home data access throughout the UI. |
| ui/src/providers/home-data/favorites.ts | Adds favorites helper functions and inline vitest tests. |
| ui/src/providers/home-data/favorite-builders.ts | Adds builders for favorite/recent-run items from API entities. |
| ui/src/components/providers.tsx | Wires HomeDataProvider into the global provider tree. |
| ui/src/components/favorite-button.tsx | Adds reusable favorite button components for org/product/repo/run entities. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
6c1b933 to
8661b92
Compare
ea528ea to
d881c22
Compare
|
There should be some hint to the user that the data is only stored in the browser to avoid wrong expectations and resulting frustration. |
I guess as only favorites are affected by this, that hint could go straight to the description in the favorites card, right? |
| product={row.original} | ||
| size='xs' | ||
| variant='ghost' | ||
| className='size-6 p-0' |
There was a problem hiding this comment.
Why are the size, variant, and className parameters not defined within the buttons but repeated for each call? Not a change request, just a question out of curiosity because this is an omnipresent pattern in the UI code which contradicts DRY. For example, it's the same with link styles which are also not defined in a central place but repeated for every link.
There was a problem hiding this comment.
shadcn-ui is a "headless" library, which means exactly what you're seeing: it wants to provide very minimal UI defaults, and lets the users specify their own very freely. So it is a deliberate design choice (and I like it - many UI libraries are too restricted and only provide some alternatives for the look and feel).
Usage of className for overriding many, many UI concepts is a very common, modern design pattern. variant meanwhile is used quite extensively on our UI.
By doing it like this, instead of hiding the look-and-feel behind the component API makes all code stay close to the UI element - I don't want to go and change the component from the library, it is much easier to read when these "modifiers" are close to where the component is used.
Maybe, but the recent runs list is also affected. I didn't make a concrete proposal because I had no good idea where this could go, I was hoping @Etsija has an idea. |
Is it? I thought these are always determined dynamically, without storing anything. Anyway, if more cards are affected, maybe putting the hint (which will be temporary only) to where @Etsija previously had the subtitle (i.e. directly below the title) could work. |
I noticed for the runs the UI already contains such a hint:
|
|
Neither of the lists is persisted by back-end - there is no API support for it. The first implementation is local storage only. |
That's clear. The question (to me) is: What needs to be persisted for recent runs? I assumed nothing needs to be persisted on any storage as recent runs are just determined dynamically when the home page is loaded. Is that not the case? |
Move the organization table from the root route to `/organizations` and leave `/` as a minimal placeholder that links to the organizations table. Update existing links from `/` to `/organizations` and update the smoke test to use the new route. Signed-off-by: Jyrki Keisala <jyrki.keisala@doubleopen.io>
First implementation of home page is based on browser's `localStorage`, but ideally, it could be based on data persisted in database and manipulated with API endpoints. Implement a generalized data provider which functions as an abstraction layer between the data and its consumers. This will make it easier to later replace `localStorage` with the real API-based implementation. Provide hooks for reading and updating data and helper functions for building home page items. Signed-off-by: Jyrki Keisala <jyrki.keisala@doubleopen.io>
Add buttons for adding and removing home page favorites. The buttons indicate the current favoriting status and clicking updates the status through the home data provider. Signed-off-by: Jyrki Keisala <jyrki.keisala@doubleopen.io>
Expose favoriting buttons on several UI pages so users can add organizations, products, repositories, and even runs to their home page favorites from the page they are currently viewing. Keep the UI actions behind the home data provider abstraction. Signed-off-by: Jyrki Keisala <jyrki.keisala@doubleopen.io>
Record successfully created ORT runs through the home data provider so the home screen can show recent activity. Note that the recent runs list is updated and persisted locally when new runs are created, and the home page just reads and renders the persisted recent runs list from `localStorage`. This is done to have minimal impact on home page's performance - it doesn't create data, it just reads it. Signed-off-by: Jyrki Keisala <jyrki.keisala@doubleopen.io>
I realized this wasn't made too clear on the commits, so I have reworded |
3472aa1 to
2756594
Compare
To make the answer more explicit here for myself: No, that's not the case. Due to a missing endpoint to query recent runs per user and / or performance reasons, local browser storage is used to "collect" runs at the point they are triggered to build a list of (max. 10) runs being shown in the UI. |
Replace the minimal index route with a lightweight home dashboard that reads favorites and recently started runs through the home data provider abstraction. Show favorites grouped by resource type, locally tracked recent runs, and a link to `/organizations`. Resolves #1598. Signed-off-by: Jyrki Keisala <jyrki.keisala@doubleopen.io>
This PR implements a new user-tailored home page. It is now possible to mark organizations, products, repositories and runs as "favorite", and the favorite entities are shown in home page, along with recent runs created by the user.
Please see the commits for details. For reviewers, it is encouraged to take the PR branch to local for testing - the first implementation is front-end only, so that can easily be done without recompiling the back-end / building docker images.