mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-13 17:35:12 +00:00
feat(console): identity providers and login policies (#722)
* idp list, idp create route * idp modules, lazy import, i18n, routing * generic service, i18n * seperate lockout, age policy component * seperate component modules * routing * enum class * login policy * iam policy grid * login policy providers * idps login policy * add idp dialog component * add idp to loginpolicy * delete idp config, iam policy grid * remove idp from loginpolicy * idp detail component, generic idp create * lint * idp detail clientid-secrets, issuer, scopes * hide clientsecret on update * rm background style, idp config * app tooltip fix * lint * dont refresh on idp select * Update console/src/app/modules/idp-create/idp-create.component.html Co-authored-by: Fabiennne <[email protected]> Co-authored-by: Fabi <[email protected]>
This commit is contained in:
co-authored by
Fabiennne
Fabi
parent
845026e43f
commit
58b01cdf3f
@@ -2,7 +2,7 @@
|
||||
<app-refresh-table *ngIf="eventDataSource" (refreshed)="loadEvents()" [dataSize]="eventDataSource.data.length"
|
||||
[loading]="loading$ | async">
|
||||
|
||||
<table [dataSource]="eventDataSource" mat-table class="table background-style" aria-label="Elements">
|
||||
<table [dataSource]="eventDataSource" mat-table class="table " aria-label="Elements">
|
||||
<ng-container matColumnDef="viewName">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.FAILEDEVENTS.VIEWNAME' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let event"> {{event.viewName}} </td>
|
||||
@@ -47,8 +47,7 @@
|
||||
<tr mat-header-row *matHeaderRowDef="eventDisplayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: eventDisplayedColumns;"></tr>
|
||||
</table>
|
||||
<mat-paginator class="paginator background-style" [pageSize]="10" #paginator
|
||||
[pageSizeOptions]="[10, 20, 100, 250]">
|
||||
<mat-paginator class="paginator" [pageSize]="10" #paginator [pageSizeOptions]="[10, 20, 100, 250]">
|
||||
</mat-paginator>
|
||||
</app-refresh-table>
|
||||
</div>
|
||||
@@ -19,7 +19,7 @@
|
||||
</ng-template>
|
||||
|
||||
<div class="table-wrapper">
|
||||
<table mat-table class="background-style table" aria-label="Elements" [dataSource]="dataSource">
|
||||
<table mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="select">
|
||||
<th class="selection" mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
||||
@@ -80,8 +80,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<mat-paginator class="background-style paginator" #paginator [pageSize]="50"
|
||||
[pageSizeOptions]="[25, 50, 100, 250]">
|
||||
<mat-paginator class="paginator" #paginator [pageSize]="50" [pageSizeOptions]="[25, 50, 100, 250]">
|
||||
</mat-paginator>
|
||||
</div>
|
||||
</app-refresh-table>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<h1>{{'ORG.POLICY.TITLE' | translate}}</h1>
|
||||
|
||||
<p class="top-desc">{{'ORG.POLICY.DESCRIPTION' | translate}}</p>
|
||||
|
||||
<div class="row-lyt">
|
||||
<ng-template appHasRole [appHasRole]="['policy.read']">
|
||||
<div class="p-item card">
|
||||
<div class="avatar">
|
||||
<i class="icon las la-gem"></i>
|
||||
</div>
|
||||
<div class="title">
|
||||
<span>{{'ORG.POLICY.LOGIN_POLICY.TITLE' | translate}}</span>
|
||||
<button mat-icon-button disabled>
|
||||
<i *ngIf="loginPolicy" class="icon las la-check-circle"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p class="desc">
|
||||
{{'ORG.POLICY.LOGIN_POLICY.DESCRIPTION' | translate}}</p>
|
||||
|
||||
<span class="fill-space"></span>
|
||||
<div class="btn-wrapper">
|
||||
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
|
||||
<button [disabled]="!loginPolicy" [routerLink]="[ 'policy', PolicyComponentType.LOGIN ]"
|
||||
mat-stroked-button>{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
@@ -0,0 +1,76 @@
|
||||
h1 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.top-desc {
|
||||
color: #8795a1;
|
||||
}
|
||||
|
||||
.row-lyt {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -1rem;
|
||||
|
||||
.p-item {
|
||||
flex-basis: 300px;
|
||||
margin: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 200px;
|
||||
padding: 1rem;
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(40deg, rgb(129, 85, 185) 30%, #8983f7);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: .5rem;
|
||||
|
||||
.icon,
|
||||
i {
|
||||
font-size: 2.5rem;
|
||||
height: 2.5rem;
|
||||
line-height: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: .9rem;
|
||||
color: #8795a1;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.btn-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-right: 1rem;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -1,20 +1,20 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PasswordPolicyComponent } from './password-policy.component';
|
||||
import { IamPolicyGridComponent } from './iam-policy-grid.component';
|
||||
|
||||
describe('PasswordPolicyComponent', () => {
|
||||
let component: PasswordPolicyComponent;
|
||||
let fixture: ComponentFixture<PasswordPolicyComponent>;
|
||||
describe('IamPolicyGridComponent', () => {
|
||||
let component: IamPolicyGridComponent;
|
||||
let fixture: ComponentFixture<IamPolicyGridComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PasswordPolicyComponent],
|
||||
declarations: [IamPolicyGridComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PasswordPolicyComponent);
|
||||
fixture = TestBed.createComponent(IamPolicyGridComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { PolicyComponentType } from 'src/app/modules/policies/policy-component-types.enum';
|
||||
import { DefaultLoginPolicy } from 'src/app/proto/generated/admin_pb';
|
||||
import { PolicyState } from 'src/app/proto/generated/management_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-iam-policy-grid',
|
||||
templateUrl: './iam-policy-grid.component.html',
|
||||
styleUrls: ['./iam-policy-grid.component.scss'],
|
||||
})
|
||||
export class IamPolicyGridComponent {
|
||||
public loginPolicy!: DefaultLoginPolicy.AsObject;
|
||||
|
||||
public PolicyState: any = PolicyState;
|
||||
public PolicyComponentType: any = PolicyComponentType;
|
||||
|
||||
constructor(
|
||||
private adminService: AdminService,
|
||||
) {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
private getData(): void {
|
||||
this.adminService.GetDefaultLoginPolicy().then(data => this.loginPolicy = data.toObject());
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { AuthGuard } from 'src/app/guards/auth.guard';
|
||||
import { RoleGuard } from 'src/app/guards/role.guard';
|
||||
import { PolicyComponentServiceType, PolicyComponentType } from 'src/app/modules/policies/policy-component-types.enum';
|
||||
|
||||
import { IamComponent } from './iam.component';
|
||||
|
||||
@@ -22,6 +23,32 @@ const routes: Routes = [
|
||||
roles: ['iam.member.read'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'idp/create',
|
||||
loadChildren: () => import('src/app/modules/idp-create/idp-create.module').then(m => m.IdpCreateModule),
|
||||
canActivate: [AuthGuard, RoleGuard],
|
||||
data: {
|
||||
roles: ['iam.idp.write'],
|
||||
serviceType: PolicyComponentServiceType.ADMIN,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'idp/:id',
|
||||
loadChildren: () => import('src/app/modules/idp/idp.module').then(m => m.IdpModule),
|
||||
canActivate: [AuthGuard, RoleGuard],
|
||||
data: {
|
||||
roles: ['iam.idp.read'],
|
||||
serviceType: PolicyComponentServiceType.ADMIN,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: `policy/${PolicyComponentType.LOGIN}`,
|
||||
data: {
|
||||
serviceType: PolicyComponentServiceType.ADMIN,
|
||||
},
|
||||
loadChildren: () => import('src/app/modules/policies/login-policy/login-policy.module')
|
||||
.then(m => m.LoginPolicyModule),
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<app-refresh-table *ngIf="dataSource" (refreshed)="loadViews()" [dataSize]="dataSource.data.length"
|
||||
[loading]="loading$ | async">
|
||||
|
||||
<table [dataSource]="dataSource" mat-table class="table background-style" aria-label="Elements">
|
||||
<table [dataSource]="dataSource" mat-table class="table" aria-label="Elements">
|
||||
<ng-container matColumnDef="viewName">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.VIEWS.VIEWNAME' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let view"> {{view.viewName}} </td>
|
||||
@@ -40,8 +40,7 @@
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
<mat-paginator class="paginator background-style" [pageSize]="10" #paginator
|
||||
[pageSizeOptions]="[10, 20, 100, 250]">
|
||||
<mat-paginator class="paginator" [pageSize]="10" #paginator [pageSizeOptions]="[10, 20, 100, 250]">
|
||||
</mat-paginator>
|
||||
</app-refresh-table>
|
||||
</div>
|
||||
@@ -3,6 +3,16 @@
|
||||
<h1 class="h1">{{'IAM.DETAIL.TITLE' | translate}}</h1>
|
||||
<p class="sub">{{'IAM.DETAIL.DESCRIPTION' | translate}} </p>
|
||||
|
||||
<app-iam-policy-grid></app-iam-policy-grid>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['iam.idp.read']">
|
||||
<app-card title="{{ 'IDP.LIST.TITLE' | translate }}" description="{{ 'IDP.LIST.DESCRIPTION' | translate }}">
|
||||
<app-idp-table [service]="adminService" [serviceType]="PolicyComponentServiceType.ADMIN"
|
||||
[disabled]="(['org.idp.write'] | hasRole | async) == false">
|
||||
</app-idp-table>
|
||||
</app-card>
|
||||
</ng-template>
|
||||
|
||||
<app-card title="{{ 'IAM.VIEWS.TITLE' | translate }}" description="{{ 'IAM.VIEWS.DESCRIPTION' | translate }}">
|
||||
<app-iam-views></app-iam-views>
|
||||
</app-card>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Router } from '@angular/router';
|
||||
import { BehaviorSubject, from, Observable, of } from 'rxjs';
|
||||
import { catchError, finalize, map } from 'rxjs/operators';
|
||||
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
|
||||
import { PolicyComponentServiceType } from 'src/app/modules/policies/policy-component-types.enum';
|
||||
import { OrgMemberView, UserView } from 'src/app/proto/generated/management_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
@@ -14,13 +15,14 @@ import { ToastService } from 'src/app/services/toast.service';
|
||||
styleUrls: ['./iam.component.scss'],
|
||||
})
|
||||
export class IamComponent {
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
public totalMemberResult: number = 0;
|
||||
public membersSubject: BehaviorSubject<OrgMemberView.AsObject[]>
|
||||
= new BehaviorSubject<OrgMemberView.AsObject[]>([]);
|
||||
|
||||
constructor(private adminService: AdminService, private dialog: MatDialog, private toast: ToastService,
|
||||
constructor(public adminService: AdminService, private dialog: MatDialog, private toast: ToastService,
|
||||
private router: Router) {
|
||||
this.loadMembers();
|
||||
}
|
||||
|
||||
@@ -22,20 +22,23 @@ import { ContributorsModule } from 'src/app/modules/contributors/contributors.mo
|
||||
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
|
||||
import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.module';
|
||||
import { SharedModule } from 'src/app/modules/shared/shared.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module';
|
||||
import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe.module';
|
||||
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe.module';
|
||||
|
||||
import { IdpTableModule } from '../../modules/idp-table/idp-table.module';
|
||||
import { FailedEventsComponent } from './failed-events/failed-events.component';
|
||||
import { IamPolicyGridComponent } from './iam-policy-grid/iam-policy-grid.component';
|
||||
import { IamRoutingModule } from './iam-routing.module';
|
||||
import { IamViewsComponent } from './iam-views/iam-views.component';
|
||||
import { IamComponent } from './iam.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [IamComponent, IamViewsComponent, FailedEventsComponent],
|
||||
declarations: [IamComponent, IamViewsComponent, FailedEventsComponent, IamPolicyGridComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
IamRoutingModule,
|
||||
IdpTableModule,
|
||||
ChangesModule,
|
||||
CardModule,
|
||||
MatAutocompleteModule,
|
||||
@@ -61,6 +64,7 @@ import { IamComponent } from './iam.component';
|
||||
TimestampToDatePipeModule,
|
||||
SharedModule,
|
||||
RefreshTableModule,
|
||||
HasRolePipeModule,
|
||||
],
|
||||
})
|
||||
export class IamModule { }
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
<button (click)="close()" mat-icon-button>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<span class="abort">{{ 'ORG.PAGES.CREATE' | translate }}</span><span class="abort-2">Step
|
||||
{{ currentCreateStep }} of
|
||||
{{ createSteps }}</span>
|
||||
</div>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['iam.write']">
|
||||
|
||||
@@ -27,6 +27,14 @@
|
||||
</app-card>
|
||||
</ng-container>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['org.idp.read']">
|
||||
<app-card title="{{ 'IDP.LIST.TITLE' | translate }}" description="{{ 'IDP.LIST.DESCRIPTION' | translate }}">
|
||||
<app-idp-table [service]="mgmtService" [serviceType]="PolicyComponentServiceType.MGMT"
|
||||
[disabled]="(['iam.idp.write'] | hasRole | async) == false">
|
||||
</app-idp-table>
|
||||
</app-card>
|
||||
</ng-template>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['policy.read']">
|
||||
<app-policy-grid></app-policy-grid>
|
||||
</ng-template>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { BehaviorSubject, from, Observable, of, Subscription } from 'rxjs';
|
||||
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 { PolicyComponentServiceType } from 'src/app/modules/policies/policy-component-types.enum';
|
||||
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
|
||||
import {
|
||||
Org,
|
||||
@@ -33,6 +34,7 @@ import { DomainVerificationComponent } from './domain-verification/domain-verifi
|
||||
})
|
||||
export class OrgDetailComponent implements OnInit, OnDestroy {
|
||||
public org!: Org.AsObject;
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
|
||||
public dataSource: MatTableDataSource<OrgMember.AsObject> = new MatTableDataSource<OrgMember.AsObject>();
|
||||
public memberResult!: OrgMemberSearchResponse.AsObject;
|
||||
@@ -56,7 +58,7 @@ export class OrgDetailComponent implements OnInit, OnDestroy {
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
public translate: TranslateService,
|
||||
private mgmtService: ManagementService,
|
||||
public mgmtService: ManagementService,
|
||||
private toast: ToastService,
|
||||
private router: Router,
|
||||
) { }
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</ng-template>
|
||||
|
||||
<div class="table-wrapper">
|
||||
<table mat-table class="background-style table" aria-label="Elements" [dataSource]="dataSource">
|
||||
<table mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="select">
|
||||
<th class="selection" mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
||||
@@ -77,8 +77,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<mat-paginator class="paginator background-style" #paginator [pageSize]="50"
|
||||
[pageSizeOptions]="[25, 50, 100, 250]">
|
||||
<mat-paginator class="paginator" #paginator [pageSize]="50" [pageSizeOptions]="[25, 50, 100, 250]">
|
||||
</mat-paginator>
|
||||
</div>
|
||||
</app-refresh-table>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { RoleGuard } from 'src/app/guards/role.guard';
|
||||
import { PolicyComponentServiceType, PolicyComponentType } from 'src/app/modules/policies/policy-component-types.enum';
|
||||
|
||||
import { OrgCreateComponent } from './org-create/org-create.component';
|
||||
import { OrgDetailComponent } from './org-detail/org-detail.component';
|
||||
import { OrgGridComponent } from './org-grid/org-grid.component';
|
||||
import { PasswordPolicyComponent, PolicyComponentAction } from './password-policy/password-policy.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -18,20 +18,60 @@ const routes: Routes = [
|
||||
loadChildren: () => import('./org-create/org-create.module').then(m => m.OrgCreateModule),
|
||||
},
|
||||
{
|
||||
path: 'policy/:policytype/create',
|
||||
component: PasswordPolicyComponent,
|
||||
data: {
|
||||
action: PolicyComponentAction.CREATE,
|
||||
},
|
||||
path: 'idp',
|
||||
children: [
|
||||
{
|
||||
path: 'create',
|
||||
loadChildren: () => import('src/app/modules/idp-create/idp-create.module').then(m => m.IdpCreateModule),
|
||||
canActivate: [RoleGuard],
|
||||
data: {
|
||||
roles: ['org.idp.write'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadChildren: () => import('src/app/modules/idp/idp.module').then(m => m.IdpModule),
|
||||
canActivate: [RoleGuard],
|
||||
data: {
|
||||
roles: ['iam.idp.read'],
|
||||
serviceType: PolicyComponentServiceType.ADMIN,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
/// TODO: add roleguard for iam policy
|
||||
|
||||
{
|
||||
path: 'policy/:policytype',
|
||||
component: PasswordPolicyComponent,
|
||||
data: {
|
||||
action: PolicyComponentAction.MODIFY,
|
||||
},
|
||||
loadChildren: () => import('./password-policy/password-policy.module').then(m => m.PasswordPolicyModule),
|
||||
path: 'policy',
|
||||
children: [
|
||||
{
|
||||
path: PolicyComponentType.AGE,
|
||||
loadChildren: () => import('src/app/modules/policies/password-age-policy/password-age-policy.module')
|
||||
.then(m => m.PasswordAgePolicyModule),
|
||||
},
|
||||
{
|
||||
path: PolicyComponentType.LOCKOUT,
|
||||
loadChildren: () => import('src/app/modules/policies/password-lockout-policy/password-lockout-policy.module')
|
||||
.then(m => m.PasswordLockoutPolicyModule),
|
||||
},
|
||||
{
|
||||
path: PolicyComponentType.COMPLEXITY,
|
||||
loadChildren: () => import('src/app/modules/policies/password-complexity-policy/password-complexity-policy.module')
|
||||
.then(m => m.PasswordComplexityPolicyModule),
|
||||
},
|
||||
{
|
||||
path: PolicyComponentType.IAM,
|
||||
loadChildren: () => import('src/app/modules/policies/password-iam-policy/password-iam-policy.module')
|
||||
.then(m => m.PasswordIamPolicyModule),
|
||||
},
|
||||
{
|
||||
path: PolicyComponentType.LOGIN,
|
||||
data: {
|
||||
serviceType: PolicyComponentServiceType.MGMT,
|
||||
},
|
||||
loadChildren: () => import('src/app/modules/policies/login-policy/login-policy.module')
|
||||
.then(m => m.LoginPolicyModule),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'members',
|
||||
|
||||
@@ -16,6 +16,7 @@ import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { MemberCreateDialogModule } from 'src/app/modules/add-member-dialog/member-create-dialog.module';
|
||||
import { CardModule } from 'src/app/modules/card/card.module';
|
||||
import { ContributorsModule } from 'src/app/modules/contributors/contributors.module';
|
||||
import { IdpTableModule } from 'src/app/modules/idp-table/idp-table.module';
|
||||
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
|
||||
import { SharedModule } from 'src/app/modules/shared/shared.module';
|
||||
import { WarnDialogModule } from 'src/app/modules/warn-dialog/warn-dialog.module';
|
||||
@@ -40,6 +41,7 @@ import { PolicyGridComponent } from './policy-grid/policy-grid.component';
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatButtonModule,
|
||||
IdpTableModule,
|
||||
MatDialogModule,
|
||||
CardModule,
|
||||
MatIconModule,
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { PasswordPolicyComponent } from './password-policy.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: PasswordPolicyComponent,
|
||||
data: { animation: 'DetailPage' },
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class PasswordPolicyRoutingModule { }
|
||||
@@ -1,136 +0,0 @@
|
||||
<app-detail-layout [backRouterLink]="[ '/org']" [title]="title ? (title | translate) : ''"
|
||||
[description]="desc ? (desc | translate) : ''">
|
||||
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
|
||||
<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
|
||||
mat-stroked-button>
|
||||
{{'ORG.POLICY.DELETE' | translate}}
|
||||
</button>
|
||||
</ng-template>
|
||||
|
||||
<div class="content" *ngIf="policyType === PolicyComponentType?.LOCKOUT && lockoutData">
|
||||
<mat-form-field class="description-formfield" appearance="outline">
|
||||
<mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
|
||||
<input matInput name="description" ngDefaultControl [(ngModel)]="lockoutData.description" required />
|
||||
</mat-form-field>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.MAXATTEMPTS' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<div class="length-wrapper">
|
||||
<button mat-icon-button (click)="incrementMaxAttempts()">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
<span>{{lockoutData?.maxAttempts}}</span>
|
||||
<button mat-icon-button (click)="decrementMaxAttempts()">
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.SHOWLOCKOUTFAILURES' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="showLockOutFailures" ngDefaultControl
|
||||
[(ngModel)]="lockoutData.showLockOutFailures">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="policyType === PolicyComponentType?.COMPLEXITY && complexityData" class="content">
|
||||
<mat-form-field class="description-formfield" appearance="outline">
|
||||
<mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
|
||||
<input matInput name="description" ngDefaultControl [(ngModel)]="complexityData.description" required />
|
||||
</mat-form-field>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.MINLENGTH' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<div class="length-wrapper">
|
||||
<button mat-icon-button (click)="decrementLength()">
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
<span>{{complexityData?.minLength}}</span>
|
||||
<button mat-icon-button (click)="incrementLength()">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.HASNUMBER' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl [(ngModel)]="complexityData.hasNumber">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.HASSYMBOL' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasSymbol" ngDefaultControl [(ngModel)]="complexityData.hasSymbol">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.HASLOWERCASE' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasLowercase" ngDefaultControl
|
||||
[(ngModel)]="complexityData.hasLowercase">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.HASUPPERCASE' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasUppercase" ngDefaultControl
|
||||
[(ngModel)]="complexityData.hasUppercase">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content" *ngIf="policyType === PolicyComponentType?.AGE && ageData">
|
||||
<mat-form-field class="description-formfield" appearance="outline">
|
||||
<mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
|
||||
<input matInput name="description" ngDefaultControl [(ngModel)]="ageData.description" required />
|
||||
</mat-form-field>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.EXPIREWARNDAYS' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<div class="length-wrapper">
|
||||
<button mat-icon-button (click)="incrementExpireWarnDays()">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
<span>{{ageData?.expireWarnDays}}</span>
|
||||
<button mat-icon-button (click)="decrementExpireWarnDays()">
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.MAXAGEDAYS' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<div class="length-wrapper">
|
||||
<button mat-icon-button (click)="incrementMaxAgeDays()">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
<span>{{ageData?.maxAgeDays}}</span>
|
||||
<button mat-icon-button (click)="decrementMaxAgeDays()">
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content" *ngIf="policyType === PolicyComponentType?.IAM_POLICY && iamData">
|
||||
<mat-form-field class="description-formfield" appearance="outline">
|
||||
<mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
|
||||
<input matInput name="description" ngDefaultControl [(ngModel)]="iamData.description" required />
|
||||
</mat-form-field>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.USERLOGINMUSTBEDOMAIN' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
|
||||
[(ngModel)]="iamData.userLoginMustBeDomain">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-container">
|
||||
<button (click)="savePolicy()" color="primary" type="submit"
|
||||
[disabled]="(policyType === PolicyComponentType?.COMPLEXITY && !complexityData?.description) || (policyType === PolicyComponentType?.IAM_POLICY && !iamData?.description)"
|
||||
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
||||
</div>
|
||||
</app-detail-layout>
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .5rem 0;
|
||||
|
||||
.left-desc {
|
||||
color: #8795a1;
|
||||
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;
|
||||
padding: .5rem 4rem;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
||||
@@ -1,329 +0,0 @@
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import {
|
||||
OrgIamPolicy,
|
||||
PasswordAgePolicy,
|
||||
PasswordComplexityPolicy,
|
||||
PasswordLockoutPolicy,
|
||||
} from 'src/app/proto/generated/management_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 PolicyComponentAction {
|
||||
CREATE = 'create',
|
||||
MODIFY = 'modify',
|
||||
}
|
||||
|
||||
export enum PolicyComponentType {
|
||||
LOCKOUT = 'lockout',
|
||||
AGE = 'age',
|
||||
COMPLEXITY = 'complexity',
|
||||
IAM_POLICY = 'iam_policy',
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-password-policy',
|
||||
templateUrl: './password-policy.component.html',
|
||||
styleUrls: ['./password-policy.component.scss'],
|
||||
})
|
||||
export class PasswordPolicyComponent implements OnInit, OnDestroy {
|
||||
public title: string = '';
|
||||
public desc: string = '';
|
||||
|
||||
componentAction: PolicyComponentAction = PolicyComponentAction.CREATE;
|
||||
|
||||
public policyType: PolicyComponentType = PolicyComponentType.COMPLEXITY;
|
||||
|
||||
public PolicyComponentType: any = PolicyComponentType;
|
||||
public PolicyComponentAction: any = PolicyComponentAction;
|
||||
|
||||
public lockoutForm!: FormGroup;
|
||||
public ageForm!: FormGroup;
|
||||
|
||||
public complexityData!: PasswordComplexityPolicy.AsObject;
|
||||
public lockoutData!: PasswordLockoutPolicy.AsObject;
|
||||
public ageData!: PasswordAgePolicy.AsObject;
|
||||
public iamData!: OrgIamPolicy.AsObject;
|
||||
|
||||
private sub: Subscription = new Subscription();
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private adminService: AdminService,
|
||||
private mgmtService: ManagementService,
|
||||
private router: Router,
|
||||
private toast: ToastService,
|
||||
private sessionStorage: StorageService,
|
||||
) {
|
||||
this.sub = this.route.data.pipe(switchMap(data => {
|
||||
this.componentAction = data.action;
|
||||
return this.route.params;
|
||||
})).subscribe(params => {
|
||||
this.policyType = params.policytype;
|
||||
|
||||
switch (params.policytype) {
|
||||
case PolicyComponentType.LOCKOUT:
|
||||
this.title = 'ORG.POLICY.PWD_LOCKOUT.TITLECREATE';
|
||||
this.desc = 'ORG.POLICY.PWD_LOCKOUT.DESCRIPTIONCREATE';
|
||||
break;
|
||||
case PolicyComponentType.AGE:
|
||||
this.title = 'ORG.POLICY.PWD_AGE.TITLECREATE';
|
||||
this.desc = 'ORG.POLICY.PWD_AGE.DESCRIPTIONCREATE';
|
||||
break;
|
||||
case PolicyComponentType.COMPLEXITY:
|
||||
this.title = 'ORG.POLICY.PWD_COMPLEXITY.TITLECREATE';
|
||||
this.desc = 'ORG.POLICY.PWD_COMPLEXITY.DESCRIPTIONCREATE';
|
||||
break;
|
||||
case PolicyComponentType.IAM_POLICY:
|
||||
this.title = 'ORG.POLICY.IAM_POLICY.TITLECREATE';
|
||||
this.desc = 'ORG.POLICY.IAM_POLICY.DESCRIPTIONCREATE';
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.componentAction === PolicyComponentAction.MODIFY) {
|
||||
this.getData(params).then(data => {
|
||||
if (data) {
|
||||
switch (this.policyType) {
|
||||
case PolicyComponentType.LOCKOUT:
|
||||
this.lockoutData = data.toObject() as PasswordLockoutPolicy.AsObject;
|
||||
break;
|
||||
case PolicyComponentType.AGE:
|
||||
this.ageData = data.toObject() as PasswordAgePolicy.AsObject;
|
||||
break;
|
||||
case PolicyComponentType.COMPLEXITY:
|
||||
this.complexityData = data.toObject() as PasswordComplexityPolicy.AsObject;
|
||||
break;
|
||||
case PolicyComponentType.IAM_POLICY:
|
||||
this.iamData = data.toObject() as OrgIamPolicy.AsObject;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
|
||||
private async getData(params: any):
|
||||
Promise<PasswordLockoutPolicy | PasswordAgePolicy | PasswordComplexityPolicy | OrgIamPolicy | undefined> {
|
||||
switch (params.policytype) {
|
||||
case PolicyComponentType.LOCKOUT:
|
||||
this.title = 'ORG.POLICY.PWD_LOCKOUT.TITLE';
|
||||
this.desc = 'ORG.POLICY.PWD_LOCKOUT.DESCRIPTION';
|
||||
return this.mgmtService.GetPasswordLockoutPolicy();
|
||||
case PolicyComponentType.AGE:
|
||||
this.title = 'ORG.POLICY.PWD_AGE.TITLE';
|
||||
this.desc = 'ORG.POLICY.PWD_AGE.DESCRIPTION';
|
||||
return this.mgmtService.GetPasswordAgePolicy();
|
||||
case PolicyComponentType.COMPLEXITY:
|
||||
this.title = 'ORG.POLICY.PWD_COMPLEXITY.TITLE';
|
||||
this.desc = 'ORG.POLICY.PWD_COMPLEXITY.DESCRIPTION';
|
||||
return this.mgmtService.GetPasswordComplexityPolicy();
|
||||
case PolicyComponentType.IAM_POLICY:
|
||||
this.title = 'ORG.POLICY.IAM_POLICY.TITLECREATE';
|
||||
this.desc = 'ORG.POLICY.IAM_POLICY.DESCRIPTIONCREATE';
|
||||
return this.mgmtService.GetMyOrgIamPolicy();
|
||||
}
|
||||
}
|
||||
|
||||
public deletePolicy(): void {
|
||||
switch (this.policyType) {
|
||||
case PolicyComponentType.LOCKOUT:
|
||||
this.mgmtService.DeletePasswordLockoutPolicy(this.lockoutData.id).then(() => {
|
||||
this.toast.showInfo('Successfully deleted');
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
break;
|
||||
case PolicyComponentType.AGE:
|
||||
this.mgmtService.DeletePasswordAgePolicy(this.ageData.id).then(() => {
|
||||
this.toast.showInfo('Successfully deleted');
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
break;
|
||||
case PolicyComponentType.COMPLEXITY:
|
||||
this.mgmtService.DeletePasswordComplexityPolicy(this.complexityData.id).then(() => {
|
||||
this.toast.showInfo('Successfully deleted');
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public incrementLength(): void {
|
||||
if (this.complexityData?.minLength !== undefined && this.complexityData?.minLength <= 72) {
|
||||
this.complexityData.minLength++;
|
||||
}
|
||||
}
|
||||
|
||||
public decrementLength(): void {
|
||||
if (this.complexityData?.minLength && this.complexityData?.minLength > 1) {
|
||||
this.complexityData.minLength--;
|
||||
}
|
||||
}
|
||||
|
||||
public incrementMaxAttempts(): void {
|
||||
if (this.lockoutData?.maxAttempts !== undefined) {
|
||||
this.lockoutData.maxAttempts++;
|
||||
}
|
||||
}
|
||||
|
||||
public decrementMaxAttempts(): void {
|
||||
if (this.lockoutData?.maxAttempts && this.lockoutData?.maxAttempts > 0) {
|
||||
this.lockoutData.maxAttempts--;
|
||||
}
|
||||
}
|
||||
|
||||
public incrementExpireWarnDays(): void {
|
||||
if (this.ageData?.expireWarnDays !== undefined) {
|
||||
this.ageData.expireWarnDays++;
|
||||
}
|
||||
}
|
||||
|
||||
public decrementExpireWarnDays(): void {
|
||||
if (this.ageData?.expireWarnDays && this.ageData?.expireWarnDays > 0) {
|
||||
this.ageData.expireWarnDays--;
|
||||
}
|
||||
}
|
||||
|
||||
public incrementMaxAgeDays(): void {
|
||||
if (this.ageData?.maxAgeDays !== undefined) {
|
||||
this.ageData.maxAgeDays++;
|
||||
}
|
||||
}
|
||||
|
||||
public decrementMaxAgeDays(): void {
|
||||
if (this.ageData?.maxAgeDays && this.ageData?.maxAgeDays > 0) {
|
||||
this.ageData.maxAgeDays--;
|
||||
}
|
||||
}
|
||||
|
||||
public savePolicy(): void {
|
||||
if (this.componentAction === PolicyComponentAction.CREATE) {
|
||||
switch (this.policyType) {
|
||||
case PolicyComponentType.LOCKOUT:
|
||||
this.mgmtService.CreatePasswordLockoutPolicy(
|
||||
this.lockoutData.description,
|
||||
this.lockoutData.maxAttempts,
|
||||
this.lockoutData.showLockOutFailures,
|
||||
).then(() => {
|
||||
this.router.navigate(['org']);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
|
||||
break;
|
||||
case PolicyComponentType.AGE:
|
||||
this.mgmtService.CreatePasswordAgePolicy(
|
||||
this.ageData.description,
|
||||
this.ageData.maxAgeDays,
|
||||
this.ageData.expireWarnDays,
|
||||
).then(() => {
|
||||
this.router.navigate(['org']);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
|
||||
break;
|
||||
case PolicyComponentType.COMPLEXITY:
|
||||
this.mgmtService.CreatePasswordComplexityPolicy(
|
||||
this.complexityData.description,
|
||||
this.complexityData.hasLowercase,
|
||||
this.complexityData.hasUppercase,
|
||||
this.complexityData.hasNumber,
|
||||
this.complexityData.hasSymbol,
|
||||
this.complexityData.minLength,
|
||||
).then(() => {
|
||||
this.router.navigate(['org']);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
break;
|
||||
|
||||
case PolicyComponentType.IAM_POLICY:
|
||||
const orgId = this.sessionStorage.getItem('organization');
|
||||
if (orgId) {
|
||||
this.adminService.CreateOrgIamPolicy(
|
||||
orgId,
|
||||
this.iamData.description,
|
||||
this.iamData.userLoginMustBeDomain,
|
||||
).then(() => {
|
||||
this.router.navigate(['org']);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (this.componentAction === PolicyComponentAction.MODIFY) {
|
||||
switch (this.policyType) {
|
||||
case PolicyComponentType.LOCKOUT:
|
||||
this.mgmtService.UpdatePasswordLockoutPolicy(
|
||||
this.lockoutData.description,
|
||||
this.lockoutData.maxAttempts,
|
||||
this.lockoutData.showLockOutFailures,
|
||||
).then(() => {
|
||||
this.router.navigate(['org']);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
|
||||
break;
|
||||
case PolicyComponentType.AGE:
|
||||
this.mgmtService.UpdatePasswordAgePolicy(
|
||||
this.ageData.description,
|
||||
this.ageData.maxAgeDays,
|
||||
this.ageData.expireWarnDays,
|
||||
).then(() => {
|
||||
this.router.navigate(['org']);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
|
||||
break;
|
||||
case PolicyComponentType.COMPLEXITY:
|
||||
this.mgmtService.UpdatePasswordComplexityPolicy(
|
||||
this.complexityData.description,
|
||||
this.complexityData.hasLowercase,
|
||||
this.complexityData.hasUppercase,
|
||||
this.complexityData.hasNumber,
|
||||
this.complexityData.hasSymbol,
|
||||
this.complexityData.minLength,
|
||||
).then(() => {
|
||||
this.router.navigate(['org']);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
break;
|
||||
|
||||
case PolicyComponentType.IAM_POLICY:
|
||||
const orgId = this.sessionStorage.getItem('organization');
|
||||
if (orgId) {
|
||||
this.adminService.UpdateOrgIamPolicy(
|
||||
orgId,
|
||||
this.iamData.description,
|
||||
this.iamData.userLoginMustBeDomain,
|
||||
).then(() => {
|
||||
this.router.navigate(['org']);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
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 { PasswordPolicyRoutingModule } from './password-policy-routing.module';
|
||||
import { PasswordPolicyComponent } from './password-policy.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [PasswordPolicyComponent],
|
||||
imports: [
|
||||
PasswordPolicyRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
MatButtonModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
HasRoleModule,
|
||||
MatTooltipModule,
|
||||
TranslateModule,
|
||||
DetailLayoutModule,
|
||||
],
|
||||
})
|
||||
export class PasswordPolicyModule { }
|
||||
@@ -52,9 +52,39 @@
|
||||
<span class="fill-space"></span>
|
||||
<div class="btn-wrapper">
|
||||
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
|
||||
<button [disabled]="iamPolicy" [routerLink]="[ 'policy', PolicyComponentType.IAM_POLICY,'create' ]"
|
||||
<button [disabled]="iamPolicy" [routerLink]="[ 'policy', PolicyComponentType.IAM,'create' ]"
|
||||
color="primary" mat-raised-button>{{'ORG.POLICY.BTN_INSTALL' | translate}}</button>
|
||||
<button [disabled]="!iamPolicy" [routerLink]="[ 'policy', PolicyComponentType.IAM_POLICY ]"
|
||||
<button [disabled]="!iamPolicy" [routerLink]="[ 'policy', PolicyComponentType.IAM ]"
|
||||
mat-stroked-button>{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['policy.read']">
|
||||
<div class="p-item card">
|
||||
<div class="avatar">
|
||||
<i class="icon las la-gem"></i>
|
||||
</div>
|
||||
<div class="title">
|
||||
<span>{{'ORG.POLICY.LOGIN_POLICY.TITLE' | translate}}</span>
|
||||
<button mat-icon-button disabled>
|
||||
<i *ngIf="loginPolicy" class="icon las la-check-circle"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<ng-template #showDescIAM>
|
||||
<p class="desc">
|
||||
{{'ORG.POLICY.LOGIN_POLICY.DESCRIPTION' | translate}}</p>
|
||||
</ng-template>
|
||||
|
||||
<span class="fill-space"></span>
|
||||
<div class="btn-wrapper">
|
||||
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
|
||||
<button [disabled]="loginPolicy" [routerLink]="[ 'policy', PolicyComponentType.LOGIN,'create' ]"
|
||||
color="primary" mat-raised-button>{{'ORG.POLICY.BTN_INSTALL' | translate}}</button>
|
||||
<button [disabled]="!loginPolicy" [routerLink]="[ 'policy', PolicyComponentType.LOGIN ]"
|
||||
mat-stroked-button>{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@ h1 {
|
||||
margin: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 250px;
|
||||
min-height: 200px;
|
||||
padding: 1rem;
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
@@ -57,6 +57,7 @@ h1 {
|
||||
|
||||
.desc {
|
||||
font-size: .9rem;
|
||||
color: #8795a1;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
|
||||
@@ -1,33 +1,23 @@
|
||||
import { Component } from '@angular/core';
|
||||
import {
|
||||
OrgIamPolicy,
|
||||
PasswordAgePolicy,
|
||||
PasswordComplexityPolicy,
|
||||
PasswordLockoutPolicy,
|
||||
PolicyState,
|
||||
} from 'src/app/proto/generated/management_pb';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { PolicyComponentType } from 'src/app/modules/policies/policy-component-types.enum';
|
||||
import { LoginPolicy, OrgIamPolicy, PasswordComplexityPolicy, PolicyState } from 'src/app/proto/generated/management_pb';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
|
||||
import { PolicyComponentType } from '../password-policy/password-policy.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-policy-grid',
|
||||
templateUrl: './policy-grid.component.html',
|
||||
styleUrls: ['./policy-grid.component.scss'],
|
||||
})
|
||||
export class PolicyGridComponent {
|
||||
public lockoutPolicy!: PasswordLockoutPolicy.AsObject;
|
||||
public agePolicy!: PasswordAgePolicy.AsObject;
|
||||
public complexityPolicy!: PasswordComplexityPolicy.AsObject;
|
||||
public iamPolicy!: OrgIamPolicy.AsObject;
|
||||
public loginPolicy!: LoginPolicy.AsObject;
|
||||
|
||||
public PolicyState: any = PolicyState;
|
||||
public PolicyComponentType: any = PolicyComponentType;
|
||||
|
||||
constructor(
|
||||
private mgmtService: ManagementService,
|
||||
public authUserService: GrpcAuthService,
|
||||
) {
|
||||
this.getData();
|
||||
}
|
||||
@@ -35,5 +25,8 @@ export class PolicyGridComponent {
|
||||
private getData(): void {
|
||||
this.mgmtService.GetPasswordComplexityPolicy().then(data => this.complexityPolicy = data.toObject());
|
||||
this.mgmtService.GetMyOrgIamPolicy().then(data => this.iamPolicy = data.toObject());
|
||||
this.mgmtService.GetLoginPolicy().then(data => {
|
||||
this.loginPolicy = data.toObject();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
<form>
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Organization</mat-label>
|
||||
<mat-chip-list #chipList aria-label="org selection">
|
||||
<mat-chip class="chip" *ngFor="let selectedOrg of orgs" [selectable]="selectable" [removable]="removable"
|
||||
(removed)="remove(selectedOrg)">
|
||||
{{selectedOrg.name}}
|
||||
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input placeholder="{{'ORG_DETAIL.DETAIL.DOMAIN' | translate}}" #domainInput [formControl]="myControl"
|
||||
[matAutocomplete]="auto" [matChipInputFor]="chipList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
|
||||
(matChipInputTokenEnd)="add($event)" />
|
||||
</mat-chip-list>
|
||||
|
||||
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)" [displayWith]="displayFn">
|
||||
<mat-option *ngIf="isLoading" class="is-loading">
|
||||
<mat-spinner diameter="30"></mat-spinner>
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let org of filteredOrgs" [value]="org">
|
||||
{{org.name}}
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import {
|
||||
SearchProjectAutocompleteComponent,
|
||||
} from '../../../modules/search-project-autocomplete/search-project-autocomplete.component';
|
||||
|
||||
describe('SearchProjectComponent', () => {
|
||||
let component: SearchProjectAutocompleteComponent;
|
||||
let fixture: ComponentFixture<SearchProjectAutocompleteComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [SearchProjectAutocompleteComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SearchProjectAutocompleteComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
-99
@@ -1,99 +0,0 @@
|
||||
import { COMMA, ENTER } from '@angular/cdk/keycodes';
|
||||
import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
|
||||
import { MatChipInputEvent } from '@angular/material/chips';
|
||||
import { debounceTime, tap } from 'rxjs/operators';
|
||||
import { Org } from 'src/app/proto/generated/management_pb';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-search-org-autocomplete',
|
||||
templateUrl: './search-org-autocomplete.component.html',
|
||||
styleUrls: ['./search-org-autocomplete.component.scss'],
|
||||
})
|
||||
export class SearchOrgAutocompleteComponent {
|
||||
public selectable: boolean = true;
|
||||
public removable: boolean = true;
|
||||
public addOnBlur: boolean = true;
|
||||
public separatorKeysCodes: number[] = [ENTER, COMMA];
|
||||
public myControl: FormControl = new FormControl();
|
||||
public names: string[] = [];
|
||||
public orgs: Array<Org.AsObject> = [];
|
||||
public filteredOrgs: Array<Org.AsObject> = [];
|
||||
public isLoading: boolean = false;
|
||||
@ViewChild('domainInput') public domainInput!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
|
||||
@Input() public singleOutput: boolean = false;
|
||||
@Output() public selectionChanged: EventEmitter<Org.AsObject | Org.AsObject[]> = new EventEmitter();
|
||||
constructor(private mgmtService: ManagementService, private toast: ToastService) {
|
||||
this.myControl.valueChanges.pipe(debounceTime(200), tap(() => this.isLoading = true)).subscribe(value => {
|
||||
return this.mgmtService.getOrgByDomainGlobal(value).then((org) => {
|
||||
this.isLoading = false;
|
||||
if (org) {
|
||||
this.filteredOrgs = [org.toObject()];
|
||||
}
|
||||
}).catch(error => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public displayFn(org?: Org.AsObject): string | undefined {
|
||||
return org ? `${org.name}` : undefined;
|
||||
}
|
||||
|
||||
public add(event: MatChipInputEvent): void {
|
||||
if (!this.matAutocomplete.isOpen) {
|
||||
const input = event.input;
|
||||
const value = event.value;
|
||||
|
||||
if ((value || '').trim()) {
|
||||
const index = this.filteredOrgs.findIndex((org) => {
|
||||
if (org.name) {
|
||||
return org.name === value;
|
||||
}
|
||||
});
|
||||
if (index > -1) {
|
||||
if (this.orgs && this.orgs.length > 0) {
|
||||
this.orgs.push(this.filteredOrgs[index]);
|
||||
} else {
|
||||
this.orgs = [this.filteredOrgs[index]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public remove(org: Org.AsObject): void {
|
||||
const index = this.orgs.indexOf(org);
|
||||
|
||||
if (index >= 0) {
|
||||
this.orgs.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public selected(event: MatAutocompleteSelectedEvent): void {
|
||||
const index = this.filteredOrgs.findIndex((org) => org === event.option.value);
|
||||
if (index !== -1) {
|
||||
if (this.singleOutput) {
|
||||
this.selectionChanged.emit(this.filteredOrgs[index]);
|
||||
} else {
|
||||
if (this.orgs && this.orgs.length > 0) {
|
||||
this.orgs.push(this.orgs[index]);
|
||||
this.selectionChanged.emit(this.orgs);
|
||||
} else {
|
||||
this.orgs = [this.filteredOrgs[index]];
|
||||
}
|
||||
|
||||
this.domainInput.nativeElement.value = '';
|
||||
this.myControl.setValue(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { SearchOrgAutocompleteComponent } from './search-org-autocomplete.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SearchOrgAutocompleteComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatAutocompleteModule,
|
||||
MatChipsModule,
|
||||
MatButtonModule,
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
ReactiveFormsModule,
|
||||
MatProgressSpinnerModule,
|
||||
FormsModule,
|
||||
TranslateModule,
|
||||
],
|
||||
exports: [
|
||||
SearchOrgAutocompleteComponent,
|
||||
],
|
||||
})
|
||||
export class SearchOrgAutocompleteModule { }
|
||||
@@ -15,10 +15,12 @@
|
||||
<form [formGroup]="appNameForm" (ngSubmit)="saveOIDCApp()">
|
||||
<div class="content">
|
||||
<mat-button-toggle-group formControlName="state" class="toggle" (change)="changeState($event)">
|
||||
<mat-button-toggle [value]="AppState.APPSTATE_INACTIVE" matTooltip="Deactivate Org">
|
||||
<mat-button-toggle [value]="AppState.APPSTATE_INACTIVE"
|
||||
matTooltip="{{ 'ACTIONS.DEACTIVATE' | translate}}">
|
||||
{{'APP.PAGES.DETAIL.STATE.'+AppState.APPSTATE_INACTIVE | translate}}
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle [value]="AppState.APPSTATE_ACTIVE" matTooltip="Activate Org">
|
||||
<mat-button-toggle [value]="AppState.APPSTATE_ACTIVE"
|
||||
matTooltip="{{ 'ACTIONS.REACTIVATE' | translate}}">
|
||||
{{'APP.PAGES.DETAIL.STATE.'+AppState.APPSTATE_ACTIVE | translate}}
|
||||
</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
@@ -41,7 +43,7 @@
|
||||
|
||||
<app-card title="{{ 'APP.OIDC.TITLE' | translate }}" *ngIf="app && app.oidcConfig">
|
||||
<div class="card-actions" card-actions
|
||||
*ngIf="app?.oidcConfig.authMethodType !== OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE">
|
||||
*ngIf="app?.oidcConfig?.authMethodType !== OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE">
|
||||
<button mat-stroked-button
|
||||
(click)="regenerateOIDCClientSecret()">{{'APP.OIDC.REGENERATESECRET' | translate}}</button>
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@
|
||||
[selection]="selection" [loading]="loading$ | async">
|
||||
|
||||
<div class="table-wrapper">
|
||||
<table class="table background-style" mat-table [dataSource]="dataSource">
|
||||
<table class="table" mat-table [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="select">
|
||||
<th class="selection" mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
||||
@@ -67,7 +67,7 @@
|
||||
[routerLink]="['/granted-projects', row.projectId, 'grant', row.id]"></tr>
|
||||
|
||||
</table>
|
||||
<mat-paginator class="paginator background-style" #paginator [length]="totalResult" [pageSize]="10"
|
||||
<mat-paginator class="paginator" #paginator [length]="totalResult" [pageSize]="10"
|
||||
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
|
||||
</div>
|
||||
</app-refresh-table>
|
||||
|
||||
+4
-4
@@ -17,7 +17,7 @@
|
||||
</a>
|
||||
</ng-template>
|
||||
<div class="table-wrapper">
|
||||
<table class="table background-style" mat-table [dataSource]="dataSource">
|
||||
<table class="table" mat-table [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="select">
|
||||
<th class="selection" mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
||||
@@ -66,8 +66,8 @@
|
||||
[routerLink]="['/projects', row.projectId]"></tr>
|
||||
|
||||
</table>
|
||||
<mat-paginator class="paginator background-style" [length]="totalResult" [pageSize]="10"
|
||||
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
|
||||
<mat-paginator class="paginator" [length]="totalResult" [pageSize]="10" [pageSizeOptions]="[5, 10, 20]"
|
||||
(page)="changePage($event)"></mat-paginator>
|
||||
</div>
|
||||
</app-refresh-table>
|
||||
</div>
|
||||
</div>
|
||||
+3
-4
@@ -16,8 +16,7 @@
|
||||
<div class="spinner-container" *ngIf="dataSource?.loading$ | async">
|
||||
<mat-spinner diameter="50"></mat-spinner>
|
||||
</div>
|
||||
<table mat-table class="table" aria-label="Elements"
|
||||
[ngClass]="{'background-style': type == ProjectType.PROJECTTYPE_OWNED}" [dataSource]="dataSource">
|
||||
<table mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="select">
|
||||
<th class="selection" mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
||||
@@ -78,8 +77,8 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<mat-paginator class="paginator" [ngClass]="{'background-style': type == ProjectType.PROJECTTYPE_OWNED}"
|
||||
#paginator [pageSize]="50" [pageSizeOptions]="[25, 50, 100, 250]">
|
||||
<mat-paginator class="paginator" [ngClass]="{'': type == ProjectType.PROJECTTYPE_OWNED}" #paginator
|
||||
[pageSize]="50" [pageSizeOptions]="[25, 50, 100, 250]">
|
||||
</mat-paginator>
|
||||
</div>
|
||||
</app-refresh-table>
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<app-card title="{{'USER.MFA.TITLE' | translate}}" description="{{'USER.MFA.DESCRIPTION' | translate}}">
|
||||
<app-refresh-table [loading]="loading$ | async" (refreshed)="getOTP()" [dataSize]="dataSource?.data?.length">
|
||||
<table class="table background-style" mat-table [dataSource]="dataSource">
|
||||
<table class="table" mat-table [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MFA.TABLETYPE' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let mfa"> {{'USER.MFA.TYPE.'+ mfa.type | translate}} </td>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</ng-template>
|
||||
|
||||
<div class="table-wrapper">
|
||||
<table class="table background-style" mat-table [dataSource]="dataSource">
|
||||
<table class="table" mat-table [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
||||
@@ -59,7 +59,7 @@
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<mat-paginator #paginator class="paginator background-style" [length]="keyResult?.totalResult || 0"
|
||||
[pageSize]="10" [pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
|
||||
<mat-paginator #paginator class="paginator" [length]="keyResult?.totalResult || 0" [pageSize]="10"
|
||||
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
|
||||
</div>
|
||||
</app-refresh-table>
|
||||
+2
-3
@@ -9,7 +9,7 @@
|
||||
</a>
|
||||
|
||||
<div class="table-wrapper">
|
||||
<table mat-table class="background-style table" aria-label="Elements" [dataSource]="dataSource">
|
||||
<table mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="select">
|
||||
<th class="selection" mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
||||
@@ -61,8 +61,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<mat-paginator class="paginator background-style" #paginator [pageSize]="50"
|
||||
[pageSizeOptions]="[25, 50, 100, 250]">
|
||||
<mat-paginator class="paginator" #paginator [pageSize]="50" [pageSizeOptions]="[25, 50, 100, 250]">
|
||||
</mat-paginator>
|
||||
</div>
|
||||
</app-refresh-table>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<app-card title="{{'USER.MFA.TITLE' | translate}}" description="{{'USER.MFA.DESCRIPTION' | translate}}">
|
||||
<app-refresh-table [loading]="loading$ | async" (refreshed)="getOTP()" [dataSize]="dataSource?.data?.length">
|
||||
<table class="table background-style" mat-table [dataSource]="dataSource">
|
||||
<table class="table" mat-table [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MFA.TABLETYPE' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let mfa"> {{'USER.MFA.TYPE.'+ mfa.type | translate}} </td>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</ng-template>
|
||||
|
||||
<div class="table-wrapper">
|
||||
<table class="table background-style" mat-table [dataSource]="dataSource">
|
||||
<table class="table" mat-table [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
||||
@@ -75,7 +75,7 @@
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<mat-paginator #paginator class="paginator background-style" [length]="userResult?.totalResult || 0"
|
||||
[pageSize]="10" [pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
|
||||
<mat-paginator #paginator class="paginator" [length]="userResult?.totalResult || 0" [pageSize]="10"
|
||||
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
|
||||
</div>
|
||||
</app-refresh-table>
|
||||
Reference in New Issue
Block a user