feat(console): rehauled navigation for instances including breadcrumb (#10283)

This PR significantly improves user navigation by introducing a new
instance-level navigation bar. This new bar, positioned above the
existing organization navigation, provides quick access to key sections:
Home, Organizations, Actions, and Settings.

Additionally, the breadcrumb component has been refined for more
consistent behavior, reintroducing intuitive breadcrumb buttons to
easily navigate up the hierarchy. These changes also include design
improvements for a cleaner and more streamlined appearance across the
interface.

<img width="423" height="138" alt="Screenshot 2025-07-17 at 14 55 46"
src="https://github.com/user-attachments/assets/ba9e40a1-1077-4cb6-8735-ac7ab637abe7"
/>
<img width="562" height="132" alt="Screenshot 2025-07-17 at 14 56 41"
src="https://github.com/user-attachments/assets/d85dc673-0df8-4677-9d2b-dc031dde42c3"
/>
<img width="545" height="254" alt="Screenshot 2025-07-17 at 14 56 10"
src="https://github.com/user-attachments/assets/eaf10117-079e-4181-8dbb-60c89b24556a"
/>
<img width="689" height="261" alt="Screenshot 2025-07-17 at 14 56 20"
src="https://github.com/user-attachments/assets/510ad550-1d9a-4c6a-8af1-66cb0b23619c"
/>

---------

Co-authored-by: conblem <[email protected]>
Co-authored-by: Stefan Benz <[email protected]>
Co-authored-by: Florian Forster <[email protected]>
This commit is contained in:
Max Peintner
2025-08-28 11:23:14 +02:00
committed by GitHub
co-authored by conblem Stefan Benz Florian Forster
parent cccba3f8f3
commit f963ea9f86
117 changed files with 3286 additions and 2360 deletions
@@ -7,7 +7,6 @@ import { Router } from '@angular/router';
import { tap } from 'rxjs/operators';
import { enterAnimations } from 'src/app/animations';
import { UserGrant as AuthUserGrant } from 'src/app/proto/generated/zitadel/auth_pb';
import { Role } from 'src/app/proto/generated/zitadel/project_pb';
import {
Type,
UserGrant as MgmtUserGrant,
@@ -24,7 +23,9 @@ import { PageEvent, PaginatorComponent } from '../paginator/paginator.component'
import { UserGrantRoleDialogComponent } from '../user-grant-role-dialog/user-grant-role-dialog.component';
import { WarnDialogComponent } from '../warn-dialog/warn-dialog.component';
import { UserGrantContext, UserGrantsDataSource } from './user-grants-datasource';
import { Org, OrgIDQuery, OrgQuery, OrgState } from 'src/app/proto/generated/zitadel/org_pb';
import { Org } from 'src/app/proto/generated/zitadel/org_pb';
import { QueryClient } from '@tanstack/angular-query-experimental';
import { NewOrganizationService } from '../../services/new-organization.service';
export enum UserGrantListSearchKey {
DISPLAY_NAME,
@@ -43,7 +44,6 @@ type UserGrantAsObject = AuthUserGrant.AsObject | MgmtUserGrant.AsObject;
})
export class UserGrantsComponent implements OnInit, AfterViewInit {
public userGrantListSearchKey: UserGrantListSearchKey | undefined = undefined;
public UserGrantListSearchKey: any = UserGrantListSearchKey;
public INITIAL_PAGE_SIZE: number = 50;
@Input() context: UserGrantContext = UserGrantContext.NONE;
@@ -62,27 +62,24 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
@Input() grantId: string = '';
@ViewChild('input') public filter!: MatInput;
public projectRoleOptions: Role.AsObject[] = [];
public routerLink: any = undefined;
public loadedId: string = '';
public loadedProjectId: string = '';
public grantToEdit: string = '';
public UserGrantContext: any = UserGrantContext;
public Type: any = Type;
public ActionKeysType: any = ActionKeysType;
public UserGrantState: any = UserGrantState;
public UserGrantContext = UserGrantContext;
public Type = Type;
public ActionKeysType = ActionKeysType;
public UserGrantState = UserGrantState;
@Input() public type: Type | undefined = undefined;
public filterOpen: boolean = false;
public myOrgs: Array<Org.AsObject> = [];
constructor(
private authService: GrpcAuthService,
private userService: ManagementService,
private toast: ToastService,
private dialog: MatDialog,
private router: Router,
private readonly authService: GrpcAuthService,
private readonly userService: ManagementService,
private readonly toast: ToastService,
private readonly dialog: MatDialog,
private readonly queryClient: QueryClient,
protected readonly router: Router,
private readonly newOrganizationService: NewOrganizationService,
) {}
@Input() public displayedColumns: string[] = [
@@ -149,10 +146,6 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
}
}
public gotoCreateLink(rL: any): void {
this.router.navigate(rL);
}
private loadGrantsPage(type: Type | undefined, searchQueries?: UserGrantQuery[]): void {
let queries: UserGrantQuery[] = [];
@@ -315,15 +308,12 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
}
public async showUser(grant: UserGrant.AsObject) {
const orgQuery = new OrgQuery();
const orgIdQuery = new OrgIDQuery();
orgIdQuery.setId(grant.grantedOrgId);
orgQuery.setIdQuery(orgIdQuery);
const orgs = (await this.authService.listMyProjectOrgs(1, 0, [orgQuery])).resultList;
if (orgs.length === 1) {
this.authService.setActiveOrg(orgs[0]);
this.router.navigate(['/users', grant.userId]);
const org = await this.queryClient.fetchQuery(
this.newOrganizationService.organizationByIdQueryOptions(grant.grantedOrgId),
);
if (org) {
this.newOrganizationService.setOrgId(grant.grantedOrgId);
await this.router.navigate(['/users', grant.userId]);
} else {
this.toast.showInfo('GRANTS.TOAST.CANTSHOWINFO', true);
}