From 215dbf0cf6a2532285302d538d72b0267ac858ad Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 22 Jul 2024 16:18:26 +0200 Subject: [PATCH] fix(console): reduce initial load time (#8273) This reduces the initial payload of the `listMyProjectOrgs` to get the active org by setting the limit of the initial orgs to 100. Partial of #8272 --------- Co-authored-by: Livio Spring --- .../search-user-autocomplete.component.ts | 8 +-- .../user-grants/user-grants.component.ts | 20 ++++---- .../project-grants.component.html | 6 +-- .../project-grants.component.ts | 23 ++++----- console/src/app/services/grpc-auth.service.ts | 49 ++++++++++++------- 5 files changed, 61 insertions(+), 45 deletions(-) diff --git a/console/src/app/modules/search-user-autocomplete/search-user-autocomplete.component.ts b/console/src/app/modules/search-user-autocomplete/search-user-autocomplete.component.ts index aec06a0416..958c457d16 100644 --- a/console/src/app/modules/search-user-autocomplete/search-user-autocomplete.component.ts +++ b/console/src/app/modules/search-user-autocomplete/search-user-autocomplete.component.ts @@ -26,6 +26,8 @@ export enum UserTarget { EXTERNAL = 'external', } +const USER_LIMIT = 25; + @Component({ selector: 'cnsl-search-user-autocomplete', templateUrl: './search-user-autocomplete.component.html', @@ -67,9 +69,9 @@ export class SearchUserAutocompleteComponent implements OnInit, AfterContentChec // feat-3916 show users as soon as I am in the input field of the user const query = new SearchQuery(); const lnQuery = new LoginNameQuery(); - lnQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE); + lnQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_STARTS_WITH_IGNORE_CASE); query.setLoginNameQuery(lnQuery); - this.userService.listUsers(10, 0, [query]).then((users) => { + this.userService.listUsers(USER_LIMIT, 0, [query]).then((users) => { this.filteredUsers = users.resultList; }); @@ -97,7 +99,7 @@ export class SearchUserAutocompleteComponent implements OnInit, AfterContentChec query.setLoginNameQuery(lnQuery); if (this.target === UserTarget.SELF) { - return from(this.userService.listUsers(10, 0, [query])); + return from(this.userService.listUsers(USER_LIMIT, 0, [query])); } else { return of(); } diff --git a/console/src/app/modules/user-grants/user-grants.component.ts b/console/src/app/modules/user-grants/user-grants.component.ts index 4b65eb99bf..a25055d336 100644 --- a/console/src/app/modules/user-grants/user-grants.component.ts +++ b/console/src/app/modules/user-grants/user-grants.component.ts @@ -18,7 +18,7 @@ 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, OrgState } from 'src/app/proto/generated/zitadel/org_pb'; +import { Org, OrgIDQuery, OrgQuery, OrgState } from 'src/app/proto/generated/zitadel/org_pb'; export enum UserGrantListSearchKey { DISPLAY_NAME, @@ -306,17 +306,15 @@ export class UserGrantsComponent implements OnInit, AfterViewInit { } } - public showUser(grant: UserGrant.AsObject) { - const org: Org.AsObject = { - id: grant.grantedOrgId, - name: grant.grantedOrgName, - state: OrgState.ORG_STATE_ACTIVE, - primaryDomain: grant.grantedOrgDomain, - }; + public async showUser(grant: UserGrant.AsObject) { + const orgQuery = new OrgQuery(); + const orgIdQuery = new OrgIDQuery(); + orgIdQuery.setId(grant.grantedOrgId); + orgQuery.setIdQuery(orgIdQuery); - // Check if user has permissions for that org before changing active org - if (this.myOrgs.find((org) => org.id === grant.grantedOrgId)) { - this.authService.setActiveOrg(org); + 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]); } else { this.toast.showInfo('GRANTS.TOAST.CANTSHOWINFO', true); diff --git a/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.html b/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.html index adfe2bb161..92d4459525 100644 --- a/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.html +++ b/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.html @@ -4,7 +4,7 @@ diff --git a/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.ts b/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.ts index 7030c8d25a..707e9c9eb6 100644 --- a/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.ts +++ b/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.ts @@ -6,7 +6,7 @@ import { MatSelectChange } from '@angular/material/select'; import { MatTable } from '@angular/material/table'; import { Router } from '@angular/router'; import { tap } from 'rxjs/operators'; -import { PaginatorComponent } from 'src/app/modules/paginator/paginator.component'; +import { PageEvent, PaginatorComponent } from 'src/app/modules/paginator/paginator.component'; import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component'; import { GrantedProject, ProjectGrantState, Role } from 'src/app/proto/generated/zitadel/project_pb'; import { ManagementService } from 'src/app/services/mgmt.service'; @@ -14,8 +14,6 @@ import { ToastService } from 'src/app/services/toast.service'; import { ProjectGrantsDataSource } from './project-grants-datasource'; -const ROUTEPARAM = 'projectid'; - @Component({ selector: 'cnsl-project-grants', templateUrl: './project-grants.component.html', @@ -28,7 +26,9 @@ const ROUTEPARAM = 'projectid'; ]), ], }) -export class ProjectGrantsComponent implements OnInit, AfterViewInit { +export class ProjectGrantsComponent implements OnInit { + public INITIAL_PAGESIZE: number = 10; + @Input() public projectId: string = ''; @ViewChild(PaginatorComponent) public paginator!: PaginatorComponent; @ViewChild(MatTable) public table!: MatTable; @@ -51,16 +51,12 @@ export class ProjectGrantsComponent implements OnInit, AfterViewInit { } public ngOnInit(): void { - this.dataSource.loadGrants(this.projectId, 0, 25, 'asc'); + this.dataSource.loadGrants(this.projectId, 0, this.INITIAL_PAGESIZE); this.getRoleOptions(this.projectId); } - public ngAfterViewInit(): void { - this.paginator.page.pipe(tap(() => this.loadGrantsPage())).subscribe(); - } - - public loadGrantsPage(pageIndex?: number, pageSize?: number): void { - this.dataSource.loadGrants(this.projectId, pageIndex ?? this.paginator.pageIndex, pageSize ?? this.paginator.pageSize); + public loadGrantsPage(event: PageEvent): void { + this.dataSource.loadGrants(this.projectId, event.pageIndex, event.pageSize); } public isAllSelected(): boolean { @@ -92,6 +88,11 @@ export class ProjectGrantsComponent implements OnInit, AfterViewInit { }); } + public refreshPage(): void { + this.selection.clear(); + this.dataSource.loadGrants(this.projectId, this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize); + } + public deleteGrant(grant: GrantedProject.AsObject): void { const dialogRef = this.dialog.open(WarnDialogComponent, { data: { diff --git a/console/src/app/services/grpc-auth.service.ts b/console/src/app/services/grpc-auth.service.ts index f6e48f694d..c7e379c84f 100644 --- a/console/src/app/services/grpc-auth.service.ts +++ b/console/src/app/services/grpc-auth.service.ts @@ -97,12 +97,14 @@ import { import { ChangeQuery } from '../proto/generated/zitadel/change_pb'; import { MetadataQuery } from '../proto/generated/zitadel/metadata_pb'; import { ListQuery } from '../proto/generated/zitadel/object_pb'; -import { Org, OrgFieldName, OrgQuery } from '../proto/generated/zitadel/org_pb'; +import { Org, OrgFieldName, OrgIDQuery, OrgQuery } from '../proto/generated/zitadel/org_pb'; import { LabelPolicy, PrivacyPolicy } from '../proto/generated/zitadel/policy_pb'; import { Gender, MembershipQuery, User, WebAuthNVerification } from '../proto/generated/zitadel/user_pb'; import { GrpcService } from './grpc.service'; import { StorageKey, StorageLocation, StorageService } from './storage.service'; +const ORG_LIMIT = 10; + @Injectable({ providedIn: 'root', }) @@ -249,36 +251,49 @@ export class GrpcAuthService { this.setActiveOrg(find); return Promise.resolve(find); } else { - const orgs = (await this.listMyProjectOrgs(10, 0)).resultList; - this.cachedOrgs.next(orgs); - const toFind = orgs.find((tmp) => tmp.id === id); - if (toFind) { - this.setActiveOrg(toFind); - return Promise.resolve(toFind); + const orgQuery = new OrgQuery(); + const orgIdQuery = new OrgIDQuery(); + orgIdQuery.setId(id); + orgQuery.setIdQuery(orgIdQuery); + + const orgs = (await this.listMyProjectOrgs(ORG_LIMIT, 0, [orgQuery])).resultList; + if (orgs.length === 1) { + this.setActiveOrg(orgs[0]); + return Promise.resolve(orgs[0]); } else { return Promise.reject(new Error('requested organization not found')); } } } else { let orgs = this.cachedOrgs.getValue(); - if (orgs.length === 0) { - orgs = (await this.listMyProjectOrgs()).resultList; - this.cachedOrgs.next(orgs); - } const org = this.storage.getItem(StorageKey.organization, StorageLocation.local); - if (org && orgs.find((tmp) => tmp.id === org.id)) { - this.storage.setItem(StorageKey.organization, org, StorageLocation.session); - this.setActiveOrg(org); - return Promise.resolve(org); + + if (org) { + const orgQuery = new OrgQuery(); + const orgIdQuery = new OrgIDQuery(); + orgIdQuery.setId(org.id); + orgQuery.setIdQuery(orgIdQuery); + + const specificOrg = (await this.listMyProjectOrgs(ORG_LIMIT, 0, [orgQuery])).resultList; + if (specificOrg.length === 1) { + this.setActiveOrg(specificOrg[0]); + return Promise.resolve(specificOrg[0]); + } else { + orgs = (await this.listMyProjectOrgs(ORG_LIMIT, 0)).resultList; + this.cachedOrgs.next(orgs); + } + } else { + orgs = (await this.listMyProjectOrgs(ORG_LIMIT, 0)).resultList; + this.cachedOrgs.next(orgs); } if (orgs.length === 0) { this._activeOrgChanged.next(undefined); return Promise.reject(new Error('No organizations found!')); } - const orgToSet = orgs.find((element) => element.id !== '0' && element.name !== ''); + const orgToSet = orgs.find((element) => element.id !== '0' && element.name !== ''); if (orgToSet) { this.setActiveOrg(orgToSet); return Promise.resolve(orgToSet); @@ -396,7 +411,7 @@ export class GrpcAuthService { } public async revalidateOrgs() { - const orgs = (await this.listMyProjectOrgs()).resultList; + const orgs = (await this.listMyProjectOrgs(ORG_LIMIT, 0)).resultList; this.cachedOrgs.next(orgs); }