[Backport release-1.6] feat(dashboard): rework the Marketplace entry point and the Admin portal - #3952
Merged
Conversation
Open the grouped application list right away instead of the "Choose a product to deploy" page and its Show-all-apps button. Category links keep filtering to a single category. Assisted-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]> (cherry picked from commit 5178e16)
Administration (Tenants, Modules, External IPs, per-tenant Info) leaves the Console sidebar for Admin, which is now always visible: those pages need no special permission. The two cluster-wide operator areas keep their own gates, so Capacity and Backup Classes still appear only for users who can open them. Resource routes become portal-aware through a shared base-path helper, so a detail, edit or order page opened from Admin stays under /admin instead of jumping back to /console. Assisted-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]> (cherry picked from commit ef73a0e)
The flat table becomes a tree built from TenantNamespaces, whose `tenant.cozystack.io/<ancestor-ns>` labels carry the full ancestry. A tenant whose parent is not accessible attaches to its nearest visible ancestor instead of disappearing, and rows are labelled relative to that parent, so a sub-tenant reads as `crpjxhwm` rather than `whmcs-crpjxhwm`. Subtrees collapse from the row itself. Each row also carries its own actions: Info opens that tenant's Info page, and Create Tenant orders a sub-tenant at any level of the tree. Editing a tenant switches to the namespace holding its Tenant CR — the parent's, or its own for the hierarchy root. Assisted-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]> (cherry picked from commit 7a48d45)
The Modules page listed the selected tenant's modules as Enabled or Disabled cards, so a module a parent tenant provides looked disabled and clicking it led to a Tenant CR that does not exist in the child's namespace — an endless spinner. It now covers every tenant the user can access, as the same hierarchy tree the Tenants page draws, with each tenant's modules as chips carrying the module icon, the namespace running it and its readiness. Availability comes from the `namespace.cozystack.io/<module>` label on each TenantNamespace, which names the providing namespace: the tenant itself for a local module, an ancestor for an inherited one. An inherited chip appears only when that ancestor is out of the user's reach, since otherwise its own chip already shows the module. Clicking any chip opens the module in whichever tenant runs it. Tenants whose whole subtree has no modules collapse into a "+ N tenants" branch, and the Info module is left out entirely as every tenant carries it. Assisted-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]> (cherry picked from commit 21b8a0e)
The page showed LoadBalancer services of the selected tenant only, so an operator had to switch tenants one by one to find an address. It now lists them for every visible TenantNamespace in a single table with a Namespace column. A namespace whose services the user cannot list contributes no rows instead of failing the page. Assisted-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]> (cherry picked from commit 1279652)
Detail pages offered a fixed tab set, so Info showed Workloads, Services and Ingresses tabs it never fills; tabs now appear only for resource groups the instance actually owns. The probes reuse the tabs' own list refs and label selector, so they share one cache entry and one watch. Back and the sidebar followed the plural instead of the entry point: a module page sent the user to a one-item list and lit nothing in the sidebar. Module pages now return to Modules and keep it highlighted, while Info returns to Tenants and highlights that, matching the trees they are reached from. Assisted-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]> (cherry picked from commit e755006)
Copying a secret key required revealing it on screen first, and the button gave no sign that anything reached the clipboard. The value the list already carries is enough to copy, so the button works while the key stays masked, and it briefly turns into a check mark to confirm. Assisted-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]> (cherry picked from commit cfd5444)
Opening the dashboard without a path sent the user to the catalog, and the header gave Marketplace the primary emphasis. The Console is the better entry point: it shows what the tenant already runs, which is what someone opening the dashboard almost always came for. The Marketplace stays one click away for when the intent is to add something new. The landing path becomes a named constant beside the portal helper, so the redirect and the tab emphasis cannot drift apart, and the library's own default tab set is reordered to match rather than contradict its only consumer. Assisted-By: Claude Signed-off-by: Andrei Kvapil <[email protected]> (cherry picked from commit bfd4ea0)
Four of the five findings share one root cause: a node in the tenant
tree can attach to its nearest *visible* ancestor when its real parent
is inaccessible, and per-row actions then derived their target from
that bridged ancestor.
The Edit action on a bridged tenant row pointed at a Tenant CR that
does not exist. The CR lives in the real parent's namespace, so the
target now comes from realParentNamespace — and Edit is offered only
when that namespace is readable, because otherwise there is no CR the
user could open and the button could only ever dead-end. The test that
asserted two Edit buttons had frozen the broken target as expected
behaviour; it now names the rows it expects, and the Edit button gained
a title so that assertion means something.
An inherited module chip is rendered only when the providing tenant is
NOT visible, yet it was a live button: clicking it denied the instance
GET and switched the active tenant to a namespace outside the visible
set, which the selector then bounced to an arbitrary fallback. It is
now an inert badge that states where the module comes from.
InfoRedirect's missing-definition branch hardcoded /console, throwing an
admin out of the portal its own docstring promises to preserve.
The sidebar's alsoMatch used a bare startsWith, so /admin/apps would
light up for /admin/apps-v2. It now matches whole path segments.
And SecretsTab let a rejected clipboard write escape as an unhandled
rejection, leaving the button silent — a denied permission or an
insecure context was indistinguishable from a no-op. It now reports the
failure.
Declined: CodeRabbit asked to split `import { useK8sList, type K8sResource }`
into a separate `import type`. The inline modifier is valid under
verbatimModuleSyntax and is what 26 other imports in this console use,
so the change would make the file the odd one out.
Reported-by: Ivan Okhotnikov <[email protected]>
Signed-off-by: Andrei Kvapil <[email protected]>
(cherry picked from commit 724354f)
11 tasks
Andrei Kvapil (kvaps)
approved these changes
Aug 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Backport of #3928 to
release-1.6.