mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-29 02:22:16 +00:00
feat: console feature api (#1480)
This commit is contained in:
@@ -75,7 +75,6 @@ export class ChangesComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
public scrollHandler(e: any): void {
|
||||
console.log('bottom');
|
||||
if (e === 'bottom') {
|
||||
this.more();
|
||||
}
|
||||
@@ -107,7 +106,6 @@ export class ChangesComponent implements OnInit, OnDestroy {
|
||||
|
||||
private more(): void {
|
||||
const cursor = this.getCursor();
|
||||
console.log('cursor' + cursor);
|
||||
|
||||
let more: Promise<ListChanges>;
|
||||
|
||||
@@ -152,7 +150,6 @@ export class ChangesComponent implements OnInit, OnDestroy {
|
||||
take(1),
|
||||
tap((res: ListChanges) => {
|
||||
const values = res.resultList;
|
||||
console.log(values);
|
||||
const mapped = this.mapChanges(values);
|
||||
// update source with new values, done loading
|
||||
// this._data.next(values);
|
||||
@@ -226,7 +223,6 @@ export class ChangesComponent implements OnInit, OnDestroy {
|
||||
return parseFloat(b.key) - parseFloat(a.key);
|
||||
});
|
||||
|
||||
// console.log(arr);
|
||||
return arr;
|
||||
}
|
||||
|
||||
@@ -237,7 +233,6 @@ export class ChangesComponent implements OnInit, OnDestroy {
|
||||
|
||||
getTimestampIndex(date: any): number {
|
||||
const ts: Date = new Date(date.seconds * 1000 + date.nanos / 1000 / 1000);
|
||||
console.log(ts);
|
||||
return ts.getTime();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,14 +36,14 @@
|
||||
<ng-container matColumnDef="creationDate">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MACHINE.CREATIONDATE' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let key">
|
||||
{{key.details.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'}}
|
||||
{{key.details.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM YYYY, HH:mm'}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="expirationDate">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MACHINE.EXPIRATIONDATE' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let key">
|
||||
{{key.expirationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'}}
|
||||
{{key.expirationDate | timestampToDate | localizedDate: 'EEE dd. MMM YYYY, HH:mm'}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ export class ClientKeysComponent implements OnInit {
|
||||
|
||||
if (resp.date as Moment) {
|
||||
const ts = new Timestamp();
|
||||
console.log(resp.date.toDate());
|
||||
const milliseconds = resp.date.toDate().getTime();
|
||||
const seconds = Math.abs(milliseconds / 1000);
|
||||
const nanos = (milliseconds - seconds * 1000) * 1000 * 1000;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { FeaturesComponent } from './features.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: FeaturesComponent,
|
||||
data: {
|
||||
animation: 'DetailPage',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class FeaturesRoutingModule { }
|
||||
@@ -0,0 +1,86 @@
|
||||
<app-detail-layout [backRouterLink]="[ serviceType === FeatureServiceType.ADMIN ? '/iam/policies' : '/org']"
|
||||
[title]="'FEATURES.TITLE' | translate" [description]="'FEATURES.DESCRIPTION' | translate">
|
||||
<p class="default" *ngIf="isDefault"> {{'POLICY.DEFAULTLABEL' | translate}}</p>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['iam.features.delete']">
|
||||
<button *ngIf="serviceType === FeatureServiceType.MGMT && !isDefault"
|
||||
matTooltip="{{'POLICY.RESET' | translate}}" color="warn" (click)="resetFeatures()" mat-stroked-button>
|
||||
{{'POLICY.RESET' | translate}}
|
||||
</button>
|
||||
</ng-template>
|
||||
|
||||
<div class="content" *ngIf="features">
|
||||
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'FEATURES.DATA.AUDITLOGRETENTION' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<span>{{features.auditLogRetention | json }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'FEATURES.DATA.LOGINPOLICYUSERNAMELOGIN' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
|
||||
[(ngModel)]="features.loginPolicyUsernameLogin"
|
||||
[disabled]="(['iam.features.write'] | hasRole | async) == false">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'FEATURES.DATA.LOGINPOLICYREGISTRATION' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
|
||||
[(ngModel)]="features.loginPolicyRegistration"
|
||||
[disabled]="(['iam.features.write'] | hasRole | async) == false">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'FEATURES.DATA.LOGINPOLICYIDP' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl [(ngModel)]="features.loginPolicyIdp"
|
||||
[disabled]="(['iam.features.write'] | hasRole | async) == false">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'FEATURES.DATA.LOGINPOLICYFACTORS' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
|
||||
[(ngModel)]="features.loginPolicyFactors"
|
||||
[disabled]="(['iam.features.write'] | hasRole | async) == false">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'FEATURES.DATA.LOGINPOLICYPASSWORDLESS' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
|
||||
[(ngModel)]="features.loginPolicyPasswordless"
|
||||
[disabled]="(['iam.features.write'] | hasRole | async) == false">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'FEATURES.DATA.LOGINPOLICYCOMPLEXITYPOLICY' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
|
||||
[(ngModel)]="features.passwordComplexityPolicy"
|
||||
[disabled]="(['iam.features.write'] | hasRole | async) == false">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'FEATURES.DATA.LABELPOLICY' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl [(ngModel)]="features.labelPolicy"
|
||||
[disabled]="(['iam.features.write'] | hasRole | async) == false">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-container">
|
||||
<button (click)="savePolicy()" [disabled]="(['iam.features.write'] | hasRole | async) == false" color="primary"
|
||||
type="submit" mat-raised-button>{{ 'ACTIONS.SAVE' | translate
|
||||
}}</button>
|
||||
</div>
|
||||
</app-detail-layout>
|
||||
@@ -0,0 +1,41 @@
|
||||
.default {
|
||||
color: var(--color-main);
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .3rem 0;
|
||||
|
||||
.left-desc {
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.length-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
|
||||
button {
|
||||
margin-top: 3rem;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { FeaturesComponent } from './features.component';
|
||||
|
||||
describe('FeaturesComponent', () => {
|
||||
let component: FeaturesComponent;
|
||||
let fixture: ComponentFixture<FeaturesComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [FeaturesComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FeaturesComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,144 @@
|
||||
import { Component, Injector, OnDestroy, Type } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import {
|
||||
GetOrgFeaturesResponse,
|
||||
SetDefaultFeaturesRequest,
|
||||
SetOrgFeaturesRequest,
|
||||
} from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { Features } from 'src/app/proto/generated/zitadel/features_pb';
|
||||
import { GetFeaturesResponse } from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { Org } from 'src/app/proto/generated/zitadel/org_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { StorageService } from 'src/app/services/storage.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
export enum FeatureServiceType {
|
||||
MGMT,
|
||||
ADMIN,
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-features',
|
||||
templateUrl: './features.component.html',
|
||||
styleUrls: ['./features.component.scss'],
|
||||
})
|
||||
export class FeaturesComponent implements OnDestroy {
|
||||
private managementService!: ManagementService;
|
||||
public serviceType!: FeatureServiceType;
|
||||
|
||||
public features!: Features.AsObject;
|
||||
|
||||
private sub: Subscription = new Subscription();
|
||||
private org!: Org.AsObject;
|
||||
|
||||
public FeatureServiceType: any = FeatureServiceType;
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private toast: ToastService,
|
||||
private sessionStorage: StorageService,
|
||||
private injector: Injector,
|
||||
private adminService: AdminService,
|
||||
) {
|
||||
const temporg = this.sessionStorage.getItem('organization') as Org.AsObject;
|
||||
if (temporg) {
|
||||
this.org = temporg;
|
||||
}
|
||||
this.sub = this.route.data.pipe(switchMap(data => {
|
||||
this.serviceType = data.serviceType;
|
||||
if (this.serviceType === FeatureServiceType.MGMT) {
|
||||
this.managementService = this.injector.get(ManagementService as Type<ManagementService>);
|
||||
}
|
||||
return this.route.params;
|
||||
})).subscribe(_ => {
|
||||
this.fetchData();
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
|
||||
public fetchData(): void {
|
||||
this.getData().then(resp => {
|
||||
if (resp?.features) {
|
||||
this.features = resp.features;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async getData(): Promise<GetFeaturesResponse.AsObject | GetOrgFeaturesResponse.AsObject | undefined> {
|
||||
switch (this.serviceType) {
|
||||
case FeatureServiceType.MGMT:
|
||||
return this.managementService.getFeatures();
|
||||
case FeatureServiceType.ADMIN:
|
||||
if (this.org?.id) {
|
||||
return this.adminService.getDefaultFeatures();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public savePolicy(): void {
|
||||
switch (this.serviceType) {
|
||||
case FeatureServiceType.MGMT:
|
||||
const req = new SetOrgFeaturesRequest();
|
||||
req.setOrgId(this.org.id);
|
||||
|
||||
req.setLoginPolicyUsernameLogin(this.features.loginPolicyUsernameLogin);
|
||||
req.setLoginPolicyRegistration(this.features.loginPolicyRegistration);
|
||||
req.setLoginPolicyIdp(this.features.loginPolicyIdp);
|
||||
req.setLoginPolicyFactors(this.features.loginPolicyFactors);
|
||||
req.setLoginPolicyPasswordless(this.features.loginPolicyPasswordless);
|
||||
req.setPasswordComplexityPolicy(this.features.passwordComplexityPolicy);
|
||||
req.setLabelPolicy(this.features.labelPolicy);
|
||||
|
||||
this.adminService.setOrgFeatures(req).then(() => {
|
||||
this.toast.showInfo('POLICY.TOAST.SET', true);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
break;
|
||||
case FeatureServiceType.ADMIN:
|
||||
// update Default org iam policy?
|
||||
const dreq = new SetDefaultFeaturesRequest();
|
||||
dreq.setLoginPolicyUsernameLogin(this.features.loginPolicyUsernameLogin);
|
||||
dreq.setLoginPolicyRegistration(this.features.loginPolicyRegistration);
|
||||
dreq.setLoginPolicyIdp(this.features.loginPolicyIdp);
|
||||
dreq.setLoginPolicyFactors(this.features.loginPolicyFactors);
|
||||
dreq.setLoginPolicyPasswordless(this.features.loginPolicyPasswordless);
|
||||
dreq.setPasswordComplexityPolicy(this.features.passwordComplexityPolicy);
|
||||
dreq.setLabelPolicy(this.features.labelPolicy);
|
||||
|
||||
this.adminService.setDefaultFeatures(dreq).then(() => {
|
||||
this.toast.showInfo('POLICY.TOAST.SET', true);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public resetFeatures(): void {
|
||||
if (this.serviceType === FeatureServiceType.MGMT) {
|
||||
this.adminService.resetOrgFeatures(this.org.id).then(() => {
|
||||
this.toast.showInfo('POLICY.TOAST.RESETSUCCESS', true);
|
||||
setTimeout(() => {
|
||||
this.fetchData();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public get isDefault(): boolean {
|
||||
if (this.features && this.serviceType === FeatureServiceType.MGMT) {
|
||||
return this.features.isDefault;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { InfoSectionModule } from '../info-section/info-section.module';
|
||||
import { FeaturesRoutingModule } from './features-routing.module';
|
||||
import { FeaturesComponent } from './features.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
FeaturesComponent
|
||||
],
|
||||
imports: [
|
||||
FeaturesRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
HasRoleModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
HasRoleModule,
|
||||
HasRolePipeModule,
|
||||
MatTooltipModule,
|
||||
InfoSectionModule,
|
||||
TranslateModule,
|
||||
DetailLayoutModule,
|
||||
],
|
||||
exports: [
|
||||
FeaturesComponent,
|
||||
]
|
||||
})
|
||||
export class FeaturesModule { }
|
||||
@@ -80,7 +80,6 @@ export class CnslFormFieldComponent extends CnslFormFieldBase implements OnDestr
|
||||
|
||||
@HostListener('blur', ['false'])
|
||||
_focusChanged(isFocused: boolean): void {
|
||||
console.log('blur1');
|
||||
if (isFocused !== this.focused && (!isFocused)) {
|
||||
this.focused = isFocused;
|
||||
this.stateChanges.next();
|
||||
|
||||
@@ -153,7 +153,6 @@ export class IdpTableComponent implements OnInit {
|
||||
(this.service as ManagementService).listOrgIDPs(limit, offset).then(resp => {
|
||||
this.idpResult = resp;
|
||||
this.dataSource.data = resp.resultList;
|
||||
console.log(resp.resultList);
|
||||
this.loadingSubject.next(false);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
@@ -163,7 +162,6 @@ export class IdpTableComponent implements OnInit {
|
||||
(this.service as AdminService).listIDPs(limit, offset).then(resp => {
|
||||
this.idpResult = resp;
|
||||
this.dataSource.data = resp.resultList;
|
||||
console.log(resp.resultList);
|
||||
|
||||
this.loadingSubject.next(false);
|
||||
}).catch(error => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="info-section-row" [ngClass]="{'info': type == 'INFO', 'warn': type == 'WARN'}">
|
||||
<i *ngIf="type == 'INFO'" class="icon las la-info"></i>
|
||||
<i *ngIf="type == 'WARN'" class="las la-exclamation"></i>
|
||||
<i *ngIf="type == 'WARN'" class="icon las la-exclamation"></i>
|
||||
|
||||
<div class="info-section-content">
|
||||
<ng-content></ng-content>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
||||
|
||||
.info-section-content {
|
||||
flex: 1;
|
||||
}
|
||||
@@ -37,6 +36,10 @@
|
||||
&.warn {
|
||||
background-color: if($is-dark-theme, #4f566b, #ffc1c1);
|
||||
color: if($is-dark-theme, #ffc1c1, #620e0e);
|
||||
|
||||
.icon {
|
||||
color: if($is-dark-theme, #ffc1c1, #620e0e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,14 +36,14 @@
|
||||
<ng-container matColumnDef="creationDate">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MACHINE.CREATIONDATE' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let key">
|
||||
{{key.details?.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'}}
|
||||
{{key.details?.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM YYYY, HH:mm'}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="expirationDate">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MACHINE.EXPIRATIONDATE' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let key">
|
||||
{{key.expirationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'}}
|
||||
{{key.expirationDate | timestampToDate | localizedDate: 'EEE dd. MMM YYYY, HH:mm'}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
@@ -85,7 +85,6 @@ export class MachineKeysComponent implements OnInit {
|
||||
|
||||
if (resp.date as Moment) {
|
||||
const ts = new Timestamp();
|
||||
console.log(resp.date.toDate());
|
||||
const milliseconds = resp.date.toDate().getTime();
|
||||
const seconds = Math.abs(milliseconds / 1000);
|
||||
const nanos = (milliseconds - seconds * 1000) * 1000 * 1000;
|
||||
@@ -123,7 +122,6 @@ export class MachineKeysComponent implements OnInit {
|
||||
if (this.userId) {
|
||||
this.mgmtService.listMachineKeys(this.userId, limit, offset).then(resp => {
|
||||
this.keyResult = resp;
|
||||
console.log(resp);
|
||||
if (resp.resultList) {
|
||||
this.dataSource.data = resp.resultList;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
{{(componentType == LoginMethodComponentType.SecondFactor ? 'MFA.SECONDFACTORTYPES.':
|
||||
LoginMethodComponentType.MultiFactor ? 'MFA.MULTIFACTORTYPES.': '')+mfa | translate}}
|
||||
</div>
|
||||
<div class="new-mfa" (click)="addMfa()" matRipple>
|
||||
<div class="new-mfa" [ngClass]="{'disabled': disabled}" (click)="!disabled ? addMfa(): null" matRipple>
|
||||
<mat-icon>add</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
@@ -49,5 +49,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: .5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,8 +214,6 @@ export class MfaTableComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log(this.mfas);
|
||||
}
|
||||
|
||||
public refreshPageAfterTimout(to: number): void {
|
||||
|
||||
-1
@@ -63,7 +63,6 @@ export class AddIdpDialogComponent {
|
||||
case IDPOwnerType.IDP_OWNER_TYPE_SYSTEM:
|
||||
this.adminService.listIDPs().then(resp => {
|
||||
this.availableIdps = resp.resultList;
|
||||
console.log(resp);
|
||||
});
|
||||
break;
|
||||
|
||||
|
||||
@@ -37,9 +37,17 @@
|
||||
[(ngModel)]="loginData.allowRegister">
|
||||
{{'POLICY.DATA.ALLOWREGISTER' | translate}}
|
||||
</mat-slide-toggle>
|
||||
<cnsl-info-section class="info">
|
||||
{{'POLICY.DATA.ALLOWREGISTER_DESC' | translate}}
|
||||
</cnsl-info-section>
|
||||
|
||||
<ng-container *ngIf="(['login_policy.registration'] | hasFeature | async) == false; else regInfo">
|
||||
<cnsl-info-section type="WARN">{{'FEATURES.NOTAVAILABLE' | translate: ({value:
|
||||
'login_policy.registration'})}}
|
||||
</cnsl-info-section>
|
||||
</ng-container>
|
||||
<ng-template #regInfo>
|
||||
<cnsl-info-section class="info">
|
||||
{{'POLICY.DATA.ALLOWREGISTER_DESC' | translate}}
|
||||
</cnsl-info-section>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div class="row">
|
||||
<mat-slide-toggle class="toggle" color="primary" [disabled]="disabled" ngDefaultControl
|
||||
@@ -60,14 +68,21 @@
|
||||
</cnsl-info-section>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
<cnsl-form-field class="form-field" label="Access Code" required="true">
|
||||
<cnsl-label>{{'LOGINPOLICY.PASSWORDLESS' | translate}}</cnsl-label>
|
||||
<mat-select [(ngModel)]="loginData.passwordlessType">
|
||||
<mat-select [(ngModel)]="loginData.passwordlessType"
|
||||
[disabled]="disabled || (['login_policy.passwordless'] | hasFeature | async) == false">
|
||||
<mat-option *ngFor="let pt of passwordlessTypes" [value]="pt">
|
||||
{{'LOGINPOLICY.PASSWORDLESSTYPE.'+pt | translate}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
<ng-container *ngIf="(['login_policy.passwordless'] | hasFeature | async) == false">
|
||||
<cnsl-info-section type="WARN">{{'FEATURES.NOTAVAILABLE' | translate: ({value:
|
||||
'login_policy.passwordless'})}}
|
||||
</cnsl-info-section>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -79,24 +94,40 @@
|
||||
<ng-container *ngIf="!isDefault">
|
||||
<h3 class="subheader">{{ 'MFA.LIST.MULTIFACTORTITLE' | translate }}</h3>
|
||||
<p class="subdesc">{{ 'MFA.LIST.MULTIFACTORDESCRIPTION' | translate }}</p>
|
||||
<ng-container *ngIf="(['login_policy.factors'] | hasFeature | async) == false">
|
||||
<cnsl-info-section type="WARN">{{'FEATURES.NOTAVAILABLE' | translate: ({value: 'login_policy.factors'})}}
|
||||
</cnsl-info-section>
|
||||
</ng-container>
|
||||
<app-mfa-table [service]="service" [serviceType]="serviceType"
|
||||
[componentType]="LoginMethodComponentType.MultiFactor"
|
||||
[disabled]="([serviceType == PolicyComponentServiceType.ADMIN ? 'iam.policy.write' : serviceType == PolicyComponentServiceType.MGMT ? 'policy.write' : ''] | hasRole | async) == false">
|
||||
[disabled]="(([serviceType == PolicyComponentServiceType.ADMIN ? 'iam.policy.write' : serviceType == PolicyComponentServiceType.MGMT ? 'policy.write' : ''] | hasRole | async) == false) || ((['login_policy.factors'] | hasFeature | async) == false)">
|
||||
</app-mfa-table>
|
||||
|
||||
<h3 class="subheader">{{ 'MFA.LIST.SECONDFACTORTITLE' | translate }}</h3>
|
||||
<p class="subdesc">{{ 'MFA.LIST.SECONDFACTORDESCRIPTION' | translate }}</p>
|
||||
<ng-container *ngIf="(['login_policy.factors'] | hasFeature | async) == false">
|
||||
<cnsl-info-section type="WARN">{{'FEATURES.NOTAVAILABLE' | translate: ({value: 'login_policy.factors'})}}
|
||||
</cnsl-info-section>
|
||||
</ng-container>
|
||||
<app-mfa-table [service]="service" [serviceType]="serviceType"
|
||||
[componentType]="LoginMethodComponentType.SecondFactor"
|
||||
[disabled]="([serviceType == PolicyComponentServiceType.ADMIN ? 'iam.policy.write' : serviceType == PolicyComponentServiceType.MGMT ? 'policy.write' : ''] | hasRole | async) == false">
|
||||
[disabled]="([serviceType == PolicyComponentServiceType.ADMIN ? 'iam.policy.write' : serviceType == PolicyComponentServiceType.MGMT ? 'policy.write' : ''] | hasRole | async) == false || ((['login_policy.factors'] | hasFeature | async) == false)">
|
||||
</app-mfa-table>
|
||||
</ng-container>
|
||||
|
||||
<h3 class="subheader">{{'LOGINPOLICY.IDPS' | translate}}</h3>
|
||||
|
||||
<ng-container *ngIf="(['login_policy.idp'] | hasFeature | async) == false">
|
||||
<cnsl-info-section type="WARN">{{'FEATURES.NOTAVAILABLE' | translate: ({value:
|
||||
'login_policy.idp'})}}
|
||||
</cnsl-info-section>
|
||||
</ng-container>
|
||||
|
||||
<div class="idps">
|
||||
<div class="idp" [ngClass]="{'disabled': disabled}" *ngFor="let idp of idps">
|
||||
<button [disabled]="disabled" mat-icon-button (click)="removeIdp(idp)" class="rm">
|
||||
<div class="idp" [ngClass]="{'disabled': disabled || (['login_policy.idp'] | hasFeature | async) == false}"
|
||||
*ngFor="let idp of idps">
|
||||
<button [disabled]="disabled || (['login_policy.idp'] | hasFeature | async) == false" mat-icon-button
|
||||
(click)="removeIdp(idp)" class="rm">
|
||||
<mat-icon matTooltip="{{'ACTIONS.REMOVE' | translate}}">
|
||||
remove_circle</mat-icon>
|
||||
</button>
|
||||
@@ -105,13 +136,15 @@
|
||||
*ngIf="idp.stylingType == IDPStylingType.STYLING_TYPE_GOOGLE" alt="google" />
|
||||
<div>
|
||||
<span class="name">{{idp.name}}</span>
|
||||
<span class="meta-info">{{ 'IDP.TYPE' | translate }}: {{ 'IDP.OWNERTYPES.'+idp.idpType | translate
|
||||
<span class="meta-info">{{ 'IDP.TYPE' | translate }}: {{ 'IDP.OWNERTYPES.'+idp.idpType |
|
||||
translate
|
||||
}}</span>
|
||||
<span class="meta-info">{{ 'IDP.ID' | translate }}: {{idp.idpId}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="!disabled" class="new-idp" (click)="openDialog()" matRipple>
|
||||
<div *ngIf="!disabled && (['login_policy.idp'] | hasFeature | async)" class="new-idp" (click)="openDialog()"
|
||||
matRipple>
|
||||
<mat-icon>add</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
@@ -127,7 +160,7 @@
|
||||
<i class="lab la-gitlab"></i>
|
||||
</div>
|
||||
<app-idp-table [service]="service" [serviceType]="serviceType"
|
||||
[disabled]="([serviceType == PolicyComponentServiceType.ADMIN ? 'iam.idp.write' : serviceType == PolicyComponentServiceType.MGMT ? 'org.idp.write' : ''] | hasRole | async) == false">
|
||||
[disabled]="([serviceType == PolicyComponentServiceType.ADMIN ? 'iam.idp.write' : serviceType == PolicyComponentServiceType.MGMT ? 'org.idp.write' : ''] | hasRole | async) == false || (['login_policy.idp'] | hasFeature | async) == false">
|
||||
</app-idp-table>
|
||||
</app-card>
|
||||
</ng-template>
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
padding-top: 1rem;
|
||||
|
||||
.row {
|
||||
padding-bottom: 1.5rem;
|
||||
|
||||
.toggle {
|
||||
margin: .3rem 0;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-bottom: 1rem;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,6 @@ export class LoginPolicyComponent implements OnDestroy {
|
||||
});
|
||||
this.getIdps().then(resp => {
|
||||
this.idps = resp;
|
||||
console.log(resp);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -144,7 +143,6 @@ export class LoginPolicyComponent implements OnDestroy {
|
||||
mgmtreq.setAllowUsernamePassword(this.loginData.allowUsernamePassword);
|
||||
mgmtreq.setForceMfa(this.loginData.forceMfa);
|
||||
mgmtreq.setPasswordlessType(this.loginData.passwordlessType);
|
||||
// console.log(mgmtreq.toObject());
|
||||
if ((this.loginData as LoginPolicy.AsObject).isDefault) {
|
||||
return (this.service as ManagementService).addCustomLoginPolicy(mgmtreq);
|
||||
} else {
|
||||
@@ -158,8 +156,6 @@ export class LoginPolicyComponent implements OnDestroy {
|
||||
adminreq.setForceMfa(this.loginData.forceMfa);
|
||||
adminreq.setPasswordlessType(this.loginData.passwordlessType);
|
||||
|
||||
// console.log(adminreq.toObject());
|
||||
|
||||
return (this.service as AdminService).updateLoginPolicy(adminreq);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,11 @@ import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.
|
||||
import { IdpTableModule } from 'src/app/modules/idp-table/idp-table.module';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { MfaTableModule } from 'src/app/modules/mfa-table/mfa-table.module';
|
||||
import { HasFeaturePipeModule } from 'src/app/pipes/has-feature-pipe/has-feature-pipe.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { InfoSectionModule } from '../../info-section/info-section.module';
|
||||
import { LinksModule } from '../../links/links.module';
|
||||
|
||||
import { AddIdpDialogModule } from './add-idp-dialog/add-idp-dialog.module';
|
||||
import { LoginPolicyRoutingModule } from './login-policy-routing.module';
|
||||
import { LoginPolicyComponent } from './login-policy.component';
|
||||
@@ -33,6 +34,7 @@ import { LoginPolicyComponent } from './login-policy.component';
|
||||
CardModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
HasFeaturePipeModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
HasRoleModule,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, Injector, Input, OnDestroy, Type } from '@angular/core';
|
||||
import { Component, Injector, OnDestroy, Type } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
@@ -10,6 +10,7 @@ import { AdminService } from 'src/app/services/admin.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { StorageService } from 'src/app/services/storage.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { CnslLinks } from '../../links/links.component';
|
||||
import {
|
||||
IAM_COMPLEXITY_LINK,
|
||||
@@ -26,7 +27,6 @@ import { PolicyComponentServiceType } from '../policy-component-types.enum';
|
||||
styleUrls: ['./org-iam-policy.component.scss'],
|
||||
})
|
||||
export class OrgIamPolicyComponent implements OnDestroy {
|
||||
@Input() service!: AdminService;
|
||||
private managementService!: ManagementService;
|
||||
public serviceType!: PolicyComponentServiceType;
|
||||
|
||||
|
||||
-1
@@ -77,7 +77,6 @@ export class PasswordComplexityPolicyComponent implements OnDestroy {
|
||||
this.getData().then(data => {
|
||||
if (data.policy) {
|
||||
this.complexityData = data.policy;
|
||||
console.log(data.policy);
|
||||
this.loading = false;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -57,10 +57,16 @@
|
||||
<p class="desc">
|
||||
{{'POLICY.IAM_POLICY.DESCRIPTION' | translate}}</p>
|
||||
|
||||
<cnsl-info-section class="warn" *ngIf="(['password_complexity_policy'] | hasFeature | async) == false"
|
||||
type="WARN">
|
||||
{{'FEATURES.NOTAVAILABLE' | translate: ({value:
|
||||
'password_complexity_policy'})}}
|
||||
</cnsl-info-section>
|
||||
|
||||
<span class="fill-space"></span>
|
||||
<div class="btn-wrapper">
|
||||
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
|
||||
<button
|
||||
<button [disabled]="(['password_complexity_policy'] | hasFeature | async) == false"
|
||||
[routerLink]="[type == PolicyGridType.IAM ? '/iam' : type == PolicyGridType.ORG ? '/org' : '','policy', PolicyComponentType.IAM ]"
|
||||
mat-stroked-button>{{'POLICY.BTN_EDIT' | translate}}</button>
|
||||
</ng-template>
|
||||
@@ -111,12 +117,18 @@
|
||||
<p class="desc">
|
||||
{{'POLICY.LABEL.DESCRIPTION' | translate}}</p>
|
||||
|
||||
<cnsl-info-section class="warn" *ngIf="(['label_policy'] | hasFeature | async) == false" type="WARN">
|
||||
{{'FEATURES.NOTAVAILABLE' | translate: ({value:
|
||||
'label_policy'})}}
|
||||
</cnsl-info-section>
|
||||
|
||||
<span class="fill-space"></span>
|
||||
<div class="btn-wrapper">
|
||||
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
|
||||
<button
|
||||
[routerLink]="[type == PolicyGridType.IAM ? '/iam' : type == PolicyGridType.ORG ? '/org' : '','policy', PolicyComponentType.LABEL ]"
|
||||
mat-stroked-button>{{'POLICY.BTN_EDIT' | translate}}</button>
|
||||
mat-stroked-button [disabled]="(['label_policy'] | hasFeature | async) == false">
|
||||
{{'POLICY.BTN_EDIT' | translate}}</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@ h2 {
|
||||
|
||||
.top-desc {
|
||||
color: var(--grey);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.row-lyt {
|
||||
@@ -65,6 +66,10 @@ h2 {
|
||||
color: var(--grey);
|
||||
}
|
||||
|
||||
.warn {
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
.icons {
|
||||
margin-bottom: 1rem;
|
||||
.icon {
|
||||
|
||||
@@ -6,8 +6,10 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { HasFeaturePipeModule } from 'src/app/pipes/has-feature-pipe/has-feature-pipe.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { InfoSectionModule } from '../info-section/info-section.module';
|
||||
import { PolicyGridComponent } from './policy-grid.component';
|
||||
|
||||
@NgModule({
|
||||
@@ -21,6 +23,8 @@ import { PolicyGridComponent } from './policy-grid.component';
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatTooltipModule,
|
||||
InfoSectionModule,
|
||||
HasFeaturePipeModule,
|
||||
],
|
||||
exports: [
|
||||
PolicyGridComponent,
|
||||
|
||||
@@ -62,7 +62,6 @@ export class SearchUserAutocompleteComponent implements OnInit, AfterContentChec
|
||||
} else if (this.target === UserTarget.SELF) {
|
||||
this.getFilteredResults(); // new subscription
|
||||
}
|
||||
console.log(this.users);
|
||||
}
|
||||
|
||||
public ngAfterContentChecked(): void {
|
||||
@@ -90,7 +89,6 @@ export class SearchUserAutocompleteComponent implements OnInit, AfterContentChec
|
||||
}),
|
||||
).subscribe((userresp: ListUsersResponse.AsObject | unknown) => {
|
||||
this.isLoading = false;
|
||||
console.log(userresp);
|
||||
if (this.target === UserTarget.SELF && userresp) {
|
||||
this.filteredUsers = (userresp as ListUsersResponse.AsObject).resultList;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,6 @@ export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> {
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(grants => {
|
||||
console.log(grants);
|
||||
this.grantsSubject.next(grants);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -182,7 +182,6 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
|
||||
private getGrantRoleOptions(id: string, projectId: string): void {
|
||||
console.log(projectId, id);
|
||||
this.mgmtService.getGrantedProjectByID(projectId, id).then(resp => {
|
||||
if (resp.grantedProject) {
|
||||
this.loadedId = id;
|
||||
|
||||
Reference in New Issue
Block a user