fix(console): prompted login (#659)

* fix partial authconfig prompt, domain c perm

* membership read check

* contributor refresh trigger, observe org write

* fix: lint
This commit is contained in:
Max Peintner 2020-08-29 11:39:55 +02:00 committed by GitHub
parent eeea1f1c4b
commit 1089193faf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 101 additions and 53 deletions

View File

@ -27,6 +27,11 @@
aria-label="Edit contributors"> aria-label="Edit contributors">
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
</button> </button>
<span class="fill-space"></span>
<button class="refresh-img" (click)="emitRefresh()" [disabled]="disabled" mat-icon-button
aria-label="refresh contributors">
<mat-icon>refresh</mat-icon>
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -39,6 +39,15 @@
margin: 0 8px 0 -15px; margin: 0 8px 0 -15px;
} }
.fill-space {
flex: 1;
}
.refresh-img {
float: left;
margin: 0 8px 0 -15px;
}
.avatar-circle { .avatar-circle {
float: left; float: left;
margin: 0 8px 0 -15px; margin: 0 8px 0 -15px;

View File

@ -32,6 +32,7 @@ export class ContributorsComponent {
@Input() membersSubject!: BehaviorSubject<any[]>; @Input() membersSubject!: BehaviorSubject<any[]>;
@Output() addClicked: EventEmitter<void> = new EventEmitter(); @Output() addClicked: EventEmitter<void> = new EventEmitter();
@Output() showDetailClicked: EventEmitter<void> = new EventEmitter(); @Output() showDetailClicked: EventEmitter<void> = new EventEmitter();
@Output() refreshClicked: EventEmitter<void> = new EventEmitter();
public emitAddMember(): void { public emitAddMember(): void {
this.addClicked.emit(); this.addClicked.emit();
@ -40,4 +41,8 @@ export class ContributorsComponent {
public emitShowDetail(): void { public emitShowDetail(): void {
this.showDetailClicked.emit(); this.showDetailClicked.emit();
} }
public emitRefresh(): void {
this.refreshClicked.emit();
}
} }

View File

@ -17,7 +17,7 @@
<app-contributors [totalResult]="totalMemberResult" [loading]="loading$ | async" <app-contributors [totalResult]="totalMemberResult" [loading]="loading$ | async"
[membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}" [membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()" description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
(showDetailClicked)="showDetail()" [disabled]="false"> (showDetailClicked)="showDetail()" (refreshClicked)="loadMembers()" [disabled]="false">
</app-contributors> </app-contributors>
</div> </div>
</app-meta-layout> </app-meta-layout>

View File

@ -22,6 +22,10 @@ export class IamComponent {
constructor(private adminService: AdminService, private dialog: MatDialog, private toast: ToastService, constructor(private adminService: AdminService, private dialog: MatDialog, private toast: ToastService,
private router: Router) { private router: Router) {
this.loadMembers();
}
public loadMembers(): void {
this.loadingSubject.next(true); this.loadingSubject.next(true);
from(this.adminService.SearchIamMembers(100, 0)).pipe( from(this.adminService.SearchIamMembers(100, 0)).pipe(
map(resp => { map(resp => {

View File

@ -2,22 +2,28 @@
<div class="enlarged-container"> <div class="enlarged-container">
<h1 class="h1">{{org?.name}}</h1> <h1 class="h1">{{org?.name}}</h1>
<p class="sub">{{'ORG_DETAIL.DESCRIPTION' | translate}}</p> <p class="sub">{{'ORG_DETAIL.DESCRIPTION' | translate}}</p>
<app-card title="{{ 'ORG.DOMAINS.TITLE' | translate }}" <ng-container *ngIf="(['org.write'] | hasRole) as canwrite$">
description="{{ 'ORG.DOMAINS.DESCRIPTION' | translate }}"> <app-card title="{{ 'ORG.DOMAINS.TITLE' | translate }}"
<div *ngFor="let domain of domains" class="domain"> description="{{ 'ORG.DOMAINS.DESCRIPTION' | translate }}">
<span (click)="verifyDomain(domain)" class="title">{{domain.domain}}</span>
<i matTooltip="verified" *ngIf="domain.verified" class="verified las la-check-circle"></i>
<i matTooltip="primary" *ngIf="domain.primary" class="primary las la-star"></i>
<span class="fill-space"></span> <div *ngFor="let domain of domains" class="domain">
<button matTooltip="Remove domain" color="warn" mat-icon-button (click)="removeDomain(domain.domain)"><i <span *ngIf="canwrite$ | async" (click)="verifyDomain(domain )"
class="las la-trash"></i></button> class="title">{{domain.domain}}</span>
</div> <span *ngIf="(canwrite$ | async) == false" class="title disabled">{{domain.domain}}</span>
<p class="new-desc">{{'ORG.PAGES.ORGDOMAIN_VERIFICATION' | translate}}</p> <i matTooltip="verified" *ngIf="domain.verified" class="verified las la-check-circle"></i>
<button class="add-button" matTooltip="Add domain" mat-raised-button color="primary" <i matTooltip="primary" *ngIf="domain.primary" class="primary las la-star"></i>
(click)="addNewDomain()">{{'ORG.DOMAINS.NEW' | translate}} </button>
</app-card> <span class="fill-space"></span>
<button [disabled]="(canwrite$ | async) == false" matTooltip="Remove domain" color="warn"
mat-icon-button (click)="removeDomain(domain.domain)"><i class="las la-trash"></i></button>
</div>
<p class="new-desc">{{'ORG.PAGES.ORGDOMAIN_VERIFICATION' | translate}}</p>
<button [disabled]="(canwrite$ | async) == false" class="add-button" matTooltip="Add domain"
mat-raised-button color="primary" (click)="addNewDomain()">{{'ORG.DOMAINS.NEW' | translate}}
</button>
</app-card>
</ng-container>
<ng-template appHasRole [appHasRole]="['policy.read']"> <ng-template appHasRole [appHasRole]="['policy.read']">
<app-policy-grid></app-policy-grid> <app-policy-grid></app-policy-grid>
@ -42,7 +48,7 @@
<app-contributors [totalResult]="totalMemberResult" [loading]="loading$ | async" <app-contributors [totalResult]="totalMemberResult" [loading]="loading$ | async"
[membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}" [membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()" description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
(showDetailClicked)="showDetail()" [disabled]="false"> (showDetailClicked)="showDetail()" (refreshClicked)="loadMembers()" [disabled]="false">
</app-contributors> </app-contributors>
</mat-tab> </mat-tab>
<mat-tab label="{{ 'CHANGES.ORG.TITLE' | translate }}" class="flex-col"> <mat-tab label="{{ 'CHANGES.ORG.TITLE' | translate }}" class="flex-col">

View File

@ -18,8 +18,10 @@
margin-right: 1rem; margin-right: 1rem;
cursor: pointer; cursor: pointer;
&:hover { &:not(.disabled) {
text-decoration: underline; &:hover {
text-decoration: underline;
}
} }
} }

View File

@ -76,17 +76,7 @@ export class OrgDetailComponent implements OnInit, OnDestroy {
this.toast.showError(error); this.toast.showError(error);
}); });
this.loadingSubject.next(true); this.loadMembers();
from(this.mgmtService.SearchMyOrgMembers(100, 0)).pipe(
map(resp => {
this.totalMemberResult = resp.toObject().totalResult;
return resp.toObject().resultList;
}),
catchError(() => of([])),
finalize(() => this.loadingSubject.next(false)),
).subscribe(members => {
this.membersSubject.next(members);
});
this.mgmtService.SearchMyOrgDomains(0, 100).then(result => { this.mgmtService.SearchMyOrgDomains(0, 100).then(result => {
this.domains = result.toObject().resultList; this.domains = result.toObject().resultList;
@ -200,4 +190,18 @@ export class OrgDetailComponent implements OnInit, OnDestroy {
}, },
}); });
} }
public loadMembers(): void {
this.loadingSubject.next(true);
from(this.mgmtService.SearchMyOrgMembers(100, 0)).pipe(
map(resp => {
this.totalMemberResult = resp.toObject().totalResult;
return resp.toObject().resultList;
}),
catchError(() => of([])),
finalize(() => this.loadingSubject.next(false)),
).subscribe(members => {
this.membersSubject.next(members);
});
}
} }

View File

@ -19,6 +19,7 @@ import { ContributorsModule } from 'src/app/modules/contributors/contributors.mo
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module'; import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
import { SharedModule } from 'src/app/modules/shared/shared.module'; import { SharedModule } from 'src/app/modules/shared/shared.module';
import { WarnDialogModule } from 'src/app/modules/warn-dialog/warn-dialog.module'; import { WarnDialogModule } from 'src/app/modules/warn-dialog/warn-dialog.module';
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module';
import { ChangesModule } from '../../modules/changes/changes.module'; import { ChangesModule } from '../../modules/changes/changes.module';
import { AddDomainDialogModule } from './org-detail/add-domain-dialog/add-domain-dialog.module'; import { AddDomainDialogModule } from './org-detail/add-domain-dialog/add-domain-dialog.module';
@ -32,6 +33,7 @@ import { PolicyGridComponent } from './policy-grid/policy-grid.component';
declarations: [OrgDetailComponent, OrgGridComponent, PolicyGridComponent, DomainVerificationComponent], declarations: [OrgDetailComponent, OrgGridComponent, PolicyGridComponent, DomainVerificationComponent],
imports: [ imports: [
CommonModule, CommonModule,
HasRolePipeModule,
OrgsRoutingModule, OrgsRoutingModule,
FormsModule, FormsModule,
HasRoleModule, HasRoleModule,

View File

@ -38,7 +38,7 @@
<app-contributors [totalResult]="totalMemberResult" [loading]="loading$ | async" <app-contributors [totalResult]="totalMemberResult" [loading]="loading$ | async"
[membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}" [membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()" description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
(showDetailClicked)="showDetail()" [disabled]="false"> (showDetailClicked)="showDetail()" (refreshClicked)="loadMembers()" [disabled]="false">
</app-contributors> </app-contributors>
</mat-tab> </mat-tab>
<mat-tab label="{{ 'CHANGES.PROJECT.TITLE' | translate }}" class="flex-col"> <mat-tab label="{{ 'CHANGES.PROJECT.TITLE' | translate }}" class="flex-col">

View File

@ -107,20 +107,25 @@ export class GrantedProjectDetailComponent implements OnInit, OnDestroy {
this.toast.showError(error); this.toast.showError(error);
}); });
from(this.mgmtService.SearchProjectGrantMembers(this.projectId, this.loadMembers();
this.grantId, 100, 0)).pipe(
map(resp => {
this.totalMemberResult = resp.toObject().totalResult;
return resp.toObject().resultList;
}),
catchError(() => of([])),
finalize(() => this.loadingSubject.next(false)),
).subscribe(members => {
this.membersSubject.next(members);
});
} }
} }
public loadMembers(): void {
this.loadingSubject.next(true);
from(this.mgmtService.SearchProjectGrantMembers(this.projectId,
this.grantId, 100, 0)).pipe(
map(resp => {
this.totalMemberResult = resp.toObject().totalResult;
return resp.toObject().resultList;
}),
catchError(() => of([])),
finalize(() => this.loadingSubject.next(false)),
).subscribe(members => {
this.membersSubject.next(members);
});
}
public navigateBack(): void { public navigateBack(): void {
this._location.back(); this._location.back();
} }

View File

@ -110,7 +110,7 @@
<app-contributors [loading]="loading$ | async" [totalResult]="totalMemberResult" <app-contributors [loading]="loading$ | async" [totalResult]="totalMemberResult"
[membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}" [membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()" description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
(showDetailClicked)="showDetail()" [disabled]="false"> (showDetailClicked)="showDetail()" (refreshClicked)="loadMembers()" [disabled]="false">
</app-contributors> </app-contributors>
</mat-tab> </mat-tab>
<mat-tab label="{{ 'CHANGES.PROJECT.TITLE' | translate }}" class="flex-col"> <mat-tab label="{{ 'CHANGES.PROJECT.TITLE' | translate }}" class="flex-col">

View File

@ -22,8 +22,8 @@ import {
ProjectState, ProjectState,
ProjectType, ProjectType,
ProjectView, ProjectView,
UserView,
UserGrantSearchKey, UserGrantSearchKey,
UserView,
} from 'src/app/proto/generated/management_pb'; } from 'src/app/proto/generated/management_pb';
import { ManagementService } from 'src/app/services/mgmt.service'; import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
@ -82,8 +82,7 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
private _location: Location, private _location: Location,
private dialog: MatDialog, private dialog: MatDialog,
private router: Router, private router: Router,
) { ) { }
}
public ngOnInit(): void { public ngOnInit(): void {
this.subscription = this.route.params.subscribe(params => this.getData(params)); this.subscription = this.route.params.subscribe(params => this.getData(params));
@ -107,6 +106,11 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
this.toast.showError(error); this.toast.showError(error);
}); });
this.loadMembers();
}
public loadMembers(): void {
this.loadingSubject.next(true);
from(this.mgmtService.SearchProjectMembers(this.projectId, 100, 0)).pipe( from(this.mgmtService.SearchProjectMembers(this.projectId, 100, 0)).pipe(
map(resp => { map(resp => {
this.totalMemberResult = resp.toObject().totalResult; this.totalMemberResult = resp.toObject().totalResult;

View File

@ -138,8 +138,9 @@
<span class="second"><span style="display: block;">{{user.preferredLoginName}}</span></span> <span class="second"><span style="display: block;">{{user.preferredLoginName}}</span></span>
</div> </div>
</div> </div>
<ng-template appHasRole [appHasRole]="['user.membership.read']">
<app-memberships [user]="user"></app-memberships> <app-memberships [user]="user"></app-memberships>
</ng-template>
<app-changes class="changes" [changeType]="ChangeType.MYUSER" [id]="user.id"></app-changes> <app-changes class="changes" [changeType]="ChangeType.MYUSER" [id]="user.id"></app-changes>
</div> </div>

View File

@ -158,7 +158,9 @@
</div> </div>
</div> </div>
<app-memberships [user]="user"></app-memberships> <ng-template appHasRole [appHasRole]="['user.membership.read']">
<app-memberships [user]="user"></app-memberships>
</ng-template>
<app-changes class="changes" [changeType]="ChangeType.USER" [id]="user.id"></app-changes> <app-changes class="changes" [changeType]="ChangeType.USER" [id]="user.id"></app-changes>
</div> </div>

View File

@ -36,14 +36,13 @@ export class AuthenticationService {
} }
public async authenticate( public async authenticate(
config?: Partial<AuthConfig>, partialConfig?: Partial<AuthConfig>,
setState: boolean = true, setState: boolean = true,
force: boolean = false, force: boolean = false,
): Promise<boolean> { ): Promise<boolean> {
if (config) { if (partialConfig) {
this.authConfig = config; Object.assign(this.authConfig, partialConfig);
} }
console.log(this.authConfig);
this.oauthService.configure(this.authConfig); this.oauthService.configure(this.authConfig);
this.oauthService.strictDiscoveryDocumentValidation = false; this.oauthService.strictDiscoveryDocumentValidation = false;
@ -51,7 +50,7 @@ export class AuthenticationService {
this._authenticated = this.oauthService.hasValidAccessToken(); this._authenticated = this.oauthService.hasValidAccessToken();
if (!this.oauthService.hasValidIdToken() || !this.authenticated || config || force) { if (!this.oauthService.hasValidIdToken() || !this.authenticated || partialConfig || force) {
const newState = setState ? await this.statehandler.createState().toPromise() : undefined; const newState = setState ? await this.statehandler.createState().toPromise() : undefined;
this.oauthService.initCodeFlow(newState); this.oauthService.initCodeFlow(newState);
} }