mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 17:48:07 +00:00
fix some e2e tests and handle default org
This commit is contained in:
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
@@ -86,9 +86,9 @@ jobs:
|
||||
with:
|
||||
build_image_name: "ghcr.io/zitadel/zitadel-build"
|
||||
|
||||
# e2e:
|
||||
# uses: ./.github/workflows/e2e.yml
|
||||
# needs: [compile]
|
||||
e2e:
|
||||
uses: ./.github/workflows/e2e.yml
|
||||
needs: [compile]
|
||||
|
||||
release:
|
||||
uses: ./.github/workflows/release.yml
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
needs:
|
||||
[version, core-unit-test, core-integration-test, lint, container] #, e2e]
|
||||
[version, core-unit-test, core-integration-test, lint, container, e2e]
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
secrets:
|
||||
GCR_JSON_KEY_BASE64: ${{ secrets.GCR_JSON_KEY_BASE64 }}
|
||||
|
@@ -5,7 +5,7 @@
|
||||
[cdkConnectedOverlayOrigin]="trigger"
|
||||
[cdkConnectedOverlayOpen]="isOpen"
|
||||
[cdkConnectedOverlayPositionStrategy]="positionStrategy()"
|
||||
[cdkConnectedOverlayScrollStrategy]="scrollStrategy()"
|
||||
[cdkConnectedOverlayScrollStrategy]="scrollStrategy"
|
||||
[cdkConnectedOverlayHasBackdrop]="isHandset()"
|
||||
(overlayOutsideClick)="closed.emit()"
|
||||
>
|
||||
|
@@ -12,13 +12,7 @@ import {
|
||||
Signal,
|
||||
untracked,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
CdkConnectedOverlay,
|
||||
CdkOverlayOrigin,
|
||||
FlexibleConnectedPositionStrategy,
|
||||
Overlay,
|
||||
ScrollStrategy,
|
||||
} from '@angular/cdk/overlay';
|
||||
import { CdkConnectedOverlay, CdkOverlayOrigin, FlexibleConnectedPositionStrategy, Overlay } from '@angular/cdk/overlay';
|
||||
import { BreakpointObserver } from '@angular/cdk/layout';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { toSignal } from '@angular/core/rxjs-interop';
|
||||
@@ -48,7 +42,7 @@ export class HeaderDropdownComponent implements OnInit {
|
||||
protected readonly isOpen$ = new ReplaySubject<boolean>(1);
|
||||
protected readonly isHandset: Signal<boolean>;
|
||||
protected readonly positionStrategy: Signal<FlexibleConnectedPositionStrategy>;
|
||||
protected readonly scrollStrategy: Signal<ScrollStrategy>;
|
||||
protected readonly scrollStrategy = this.overlay.scrollStrategies.block();
|
||||
|
||||
constructor(
|
||||
private readonly overlay: Overlay,
|
||||
@@ -57,7 +51,6 @@ export class HeaderDropdownComponent implements OnInit {
|
||||
) {
|
||||
this.isHandset = this.getIsHandset();
|
||||
this.positionStrategy = this.getPositionStrategy(this.isHandset);
|
||||
this.scrollStrategy = this.getScrollStrategy(this.isHandset);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
@@ -101,8 +94,4 @@ export class HeaderDropdownComponent implements OnInit {
|
||||
: undefined!,
|
||||
);
|
||||
}
|
||||
|
||||
private getScrollStrategy(isHandset: Signal<boolean>): Signal<ScrollStrategy> {
|
||||
return computed(() => (isHandset() ? this.overlay.scrollStrategies.block() : undefined!));
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<div class="new-header-wrapper">
|
||||
<ng-container *ngIf="(['iam.read$', 'iam.write$'] | hasRole | async) && myInstanceQuery.data()?.instance as instance">
|
||||
<ng-container *ngIf="myInstanceQuery.data()?.instance as instance">
|
||||
<ng-container *ngTemplateOutlet="slash"></ng-container>
|
||||
<cnsl-header-button
|
||||
cdkOverlayOrigin
|
||||
@@ -26,19 +26,13 @@
|
||||
></cnsl-organization-selector>
|
||||
</cnsl-header-dropdown>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="activeOrganizationQuery.data() as org">
|
||||
<ng-container *ngTemplateOutlet="slash"></ng-container>
|
||||
<cnsl-header-button
|
||||
cdkOverlayOrigin
|
||||
#orgTrigger="cdkOverlayOrigin"
|
||||
(click)="isOrgDropdownOpen.set(!isOrgDropdownOpen())"
|
||||
>
|
||||
{{ org.name }}
|
||||
</cnsl-header-button>
|
||||
<cnsl-header-dropdown [trigger]="orgTrigger" [isOpen]="isOrgDropdownOpen()" (closed)="isOrgDropdownOpen.set(false)">
|
||||
<cnsl-organization-selector (orgChanged)="isOrgDropdownOpen.set(false)"></cnsl-organization-selector>
|
||||
</cnsl-header-dropdown>
|
||||
</ng-container>
|
||||
<ng-container *ngTemplateOutlet="slash"></ng-container>
|
||||
<cnsl-header-button cdkOverlayOrigin #orgTrigger="cdkOverlayOrigin" (click)="isOrgDropdownOpen.set(!isOrgDropdownOpen())">
|
||||
<ng-container *ngIf="activeOrganizationQuery.data() as org">{{ org.name }}</ng-container>
|
||||
</cnsl-header-button>
|
||||
<cnsl-header-dropdown [trigger]="orgTrigger" [isOpen]="isOrgDropdownOpen()" (closed)="isOrgDropdownOpen.set(false)">
|
||||
<cnsl-organization-selector (orgChanged)="isOrgDropdownOpen.set(false)"></cnsl-organization-selector>
|
||||
</cnsl-header-dropdown>
|
||||
</div>
|
||||
|
||||
<ng-template #slash>
|
||||
|
@@ -16,6 +16,7 @@ import { map } from 'rxjs/operators';
|
||||
import { toSignal } from '@angular/core/rxjs-interop';
|
||||
import { BreakpointObserver } from '@angular/cdk/layout';
|
||||
import { NewAdminService } from '../../services/new-admin.service';
|
||||
import { NewAuthService } from '../../services/new-auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-new-header',
|
||||
@@ -39,8 +40,12 @@ import { NewAdminService } from '../../services/new-admin.service';
|
||||
],
|
||||
})
|
||||
export class NewHeaderComponent {
|
||||
protected readonly listMyZitadelPermissionsQuery = this.newAuthService.listMyZitadelPermissionsQuery();
|
||||
protected readonly myInstanceQuery = this.adminService.getMyInstanceQuery();
|
||||
protected readonly organizationsQuery = injectQuery(() => this.newOrganizationService.listOrganizationsQueryOptions());
|
||||
protected readonly organizationsQuery = injectQuery(() => ({
|
||||
...this.newOrganizationService.listOrganizationsQueryOptions(),
|
||||
enabled: (this.listMyZitadelPermissionsQuery.data() ?? []).includes('org.read'),
|
||||
}));
|
||||
protected readonly isInstanceDropdownOpen = signal(false);
|
||||
protected readonly isOrgDropdownOpen = signal(false);
|
||||
protected readonly instanceSelectorSecondStep = signal(false);
|
||||
@@ -52,8 +57,16 @@ export class NewHeaderComponent {
|
||||
private readonly toastService: ToastService,
|
||||
private readonly breakpointObserver: BreakpointObserver,
|
||||
private readonly adminService: NewAdminService,
|
||||
private readonly newAuthService: NewAuthService,
|
||||
) {
|
||||
this.isHandset = this.getIsHandset();
|
||||
|
||||
effect(() => {
|
||||
if (this.listMyZitadelPermissionsQuery.isError()) {
|
||||
this.toastService.showError(this.listMyZitadelPermissionsQuery.error());
|
||||
}
|
||||
});
|
||||
|
||||
effect(() => {
|
||||
if (this.organizationsQuery.isError()) {
|
||||
this.toastService.showError(this.organizationsQuery.error());
|
||||
|
@@ -91,6 +91,15 @@ export class OrganizationSelectorComponent {
|
||||
toast.showError(this.activeOrg.error());
|
||||
}
|
||||
});
|
||||
|
||||
effect(() => {
|
||||
const orgId = newOrganizationService.orgId();
|
||||
const orgs = this.organizationsQuery.data()?.pages[0]?.result;
|
||||
if (orgId || !orgs || orgs.length === 0) {
|
||||
return;
|
||||
}
|
||||
const _ = newOrganizationService.setOrgId(orgs[0].id);
|
||||
});
|
||||
}
|
||||
|
||||
private buildForm() {
|
||||
@@ -123,7 +132,7 @@ export class OrganizationSelectorComponent {
|
||||
return injectInfiniteQuery(() => {
|
||||
const query = nameQuery();
|
||||
return {
|
||||
queryKey: ['listOrganizationsInfinite', query],
|
||||
queryKey: ['organization', 'listOrganizationsInfinite', query],
|
||||
queryFn: ({ pageParam, signal }) => this.newOrganizationService.listOrganizations(pageParam, signal),
|
||||
initialPageParam: {
|
||||
query: {
|
||||
|
@@ -39,7 +39,6 @@ export class DomainPolicyComponent implements OnInit, OnDestroy {
|
||||
private toast: ToastService,
|
||||
private injector: Injector,
|
||||
private adminService: AdminService,
|
||||
private storageService: StorageService,
|
||||
private readonly newOrganizationService: NewOrganizationService,
|
||||
) {}
|
||||
|
||||
|
@@ -2,7 +2,7 @@ import { ChangeDetectorRef, Component, effect, OnInit, signal } from '@angular/c
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Router } from '@angular/router';
|
||||
import { BehaviorSubject, from, lastValueFrom, Observable, of } from 'rxjs';
|
||||
import { catchError, distinctUntilChanged, finalize, map } from 'rxjs/operators';
|
||||
import { catchError, finalize, map } from 'rxjs/operators';
|
||||
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
|
||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||
import { InfoSectionType } from 'src/app/modules/info-section/info-section.component';
|
||||
@@ -159,6 +159,7 @@ export class OrgDetailComponent implements OnInit {
|
||||
|
||||
try {
|
||||
await this.deleteOrgMutation.mutateAsync();
|
||||
this.toast.showInfo('ORG.TOAST.DELETED', true);
|
||||
await this.router.navigate(['/orgs']);
|
||||
} catch (error) {
|
||||
this.toast.showError(error);
|
||||
|
@@ -37,7 +37,6 @@ import {
|
||||
combineLatestWith,
|
||||
defer,
|
||||
EMPTY,
|
||||
identity,
|
||||
mergeWith,
|
||||
Observable,
|
||||
ObservedValueOf,
|
||||
|
@@ -41,10 +41,8 @@ import { Type, UserFieldName } from '@zitadel/proto/zitadel/user/v2/query_pb';
|
||||
import { UserState, User } from '@zitadel/proto/zitadel/user/v2/user_pb';
|
||||
import { MessageInitShape } from '@bufbuild/protobuf';
|
||||
import { ListUsersRequestSchema, ListUsersResponse } from '@zitadel/proto/zitadel/user/v2/user_service_pb';
|
||||
import { AuthenticationService } from 'src/app/services/authentication.service';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { UserState as UserStateV1 } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import { NewOrganizationService } from '../../../../services/new-organization.service';
|
||||
import { NewOrganizationService } from 'src/app/services/new-organization.service';
|
||||
|
||||
type Query = Exclude<
|
||||
Exclude<MessageInitShape<typeof ListUsersRequestSchema>['queries'], undefined>[number]['query'],
|
||||
@@ -124,8 +122,6 @@ export class UserTableComponent implements OnInit {
|
||||
private readonly dialog: MatDialog,
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly destroyRef: DestroyRef,
|
||||
private readonly authenticationService: AuthenticationService,
|
||||
private readonly authService: GrpcAuthService,
|
||||
private readonly newOrganizationService: NewOrganizationService,
|
||||
) {
|
||||
this.type$ = this.getType$().pipe(shareReplay({ refCount: true, bufferSize: 1 }));
|
||||
@@ -232,9 +228,10 @@ export class UserTableComponent implements OnInit {
|
||||
}
|
||||
|
||||
private getQueries(type$: Observable<Type>): Observable<Query[]> {
|
||||
const orgId$ = toObservable(this.newOrganizationService.orgId).pipe(filter(Boolean));
|
||||
return this.searchQueries$.pipe(
|
||||
startWith([]),
|
||||
combineLatestWith(type$, toObservable(this.newOrganizationService.getOrgId())),
|
||||
combineLatestWith(type$, orgId$),
|
||||
map(([queries, type, organizationId]) => {
|
||||
const mappedQueries = queries.map((q) => this.searchQueryToV2(q.toObject()));
|
||||
|
||||
|
@@ -8,12 +8,16 @@ import {
|
||||
SetUpOrgResponse,
|
||||
} from '@zitadel/proto/zitadel/admin_pb';
|
||||
import { injectQuery } from '@tanstack/angular-query-experimental';
|
||||
import { NewAuthService } from './new-auth.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class NewAdminService {
|
||||
constructor(private readonly grpcService: GrpcService) {}
|
||||
constructor(
|
||||
private readonly grpcService: GrpcService,
|
||||
private readonly authService: NewAuthService,
|
||||
) {}
|
||||
|
||||
public setupOrg(req: MessageInitShape<typeof SetUpOrgRequestSchema>): Promise<SetUpOrgResponse> {
|
||||
return this.grpcService.adminNew.setupOrg(req);
|
||||
@@ -28,9 +32,11 @@ export class NewAdminService {
|
||||
}
|
||||
|
||||
public getMyInstanceQuery() {
|
||||
const listMyZitadelPermissionsQuery = this.authService.listMyZitadelPermissionsQuery();
|
||||
return injectQuery(() => ({
|
||||
queryKey: ['admin', 'getMyInstance'],
|
||||
queryFn: ({ signal }) => this.getMyInstance(signal),
|
||||
queryFn: async () => this.getMyInstance(),
|
||||
enabled: (listMyZitadelPermissionsQuery.data() ?? []).includes('iam.write'),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,9 @@ import {
|
||||
RemoveMyAuthFactorOTPSMSResponse,
|
||||
ListMyMetadataResponse,
|
||||
VerifyMyPhoneResponse,
|
||||
ListMyZitadelPermissionsResponse,
|
||||
} from '@zitadel/proto/zitadel/auth_pb';
|
||||
import { injectQuery } from '@tanstack/angular-query-experimental';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -65,4 +67,15 @@ export class NewAuthService {
|
||||
public getMyPasswordComplexityPolicy(): Promise<GetMyPasswordComplexityPolicyResponse> {
|
||||
return this.grpcService.authNew.getMyPasswordComplexityPolicy({});
|
||||
}
|
||||
|
||||
public listMyZitadelPermissions(): Promise<ListMyZitadelPermissionsResponse> {
|
||||
return this.grpcService.authNew.listMyZitadelPermissions({});
|
||||
}
|
||||
|
||||
public listMyZitadelPermissionsQuery() {
|
||||
return injectQuery(() => ({
|
||||
queryKey: ['auth', 'listMyZitadelPermissions'],
|
||||
queryFn: () => this.listMyZitadelPermissions().then(({ result }) => result),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@@ -44,6 +44,8 @@ export class NewOrganizationService {
|
||||
}
|
||||
|
||||
public async setOrgId(orgId?: string) {
|
||||
console.log('beboop', orgId);
|
||||
console.trace(orgId);
|
||||
const organization = await this.queryClient.fetchQuery(this.organizationByIdQueryOptions(orgId ?? this.getOrgId()()));
|
||||
if (organization) {
|
||||
this.storage.setItem(StorageKey.organizationId, orgId, StorageLocation.session);
|
||||
@@ -73,7 +75,7 @@ export class NewOrganizationService {
|
||||
};
|
||||
|
||||
return queryOptions({
|
||||
queryKey: ['listOrganizations', req],
|
||||
queryKey: ['organization', 'listOrganizations', req],
|
||||
queryFn: organizationId
|
||||
? () => this.listOrganizations(req).then((resp) => resp.result.find(Boolean) ?? null)
|
||||
: skipToken,
|
||||
@@ -93,7 +95,7 @@ export class NewOrganizationService {
|
||||
|
||||
public listOrganizationsQueryKey(req?: MessageInitShape<typeof ListOrganizationsRequestSchema>) {
|
||||
if (!req) {
|
||||
return ['listOrganizations'];
|
||||
return ['organization', 'listOrganizations'];
|
||||
}
|
||||
|
||||
// needed because angular query isn't able to serialize a bigint key
|
||||
@@ -103,7 +105,7 @@ export class NewOrganizationService {
|
||||
...(query ? { query } : {}),
|
||||
};
|
||||
|
||||
return ['listOrganizations', queryKey];
|
||||
return ['organization', 'listOrganizations', queryKey];
|
||||
}
|
||||
|
||||
public listOrganizations(
|
||||
|
Reference in New Issue
Block a user