mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-30 19:12:16 +00:00
fix(console): formfield changes and ux (#1020)
* cnsl-formfield, cnsl-label, cnsl-input, ch prefix * create user cnsl-fields, add cnsl-error * replace user forms with cnsl-fields * replace all other occurrences of mat-form-field with cnsl-fields * improve hover, active, focus behavior, headlin styling * user-grant refactor * style cleanup * stylelint * fix detail layout flexstart, user table header * input dir * error, input directives instead components, on blur handler * error directive, formfield content children * formfield control directive * use new field for new contact dialog * formfield hint, error directive, scss * hint or error binding, animation after view init * avatar changes, policy header * style lint * lint * input control within formfield, errorstatematcher * use matformcontrol to merge with selects * member table min width, lint * lint * implement from matformcontrol insteat custom, add selector * find error * add focus listener * labelfloat * fix input directive * renaming * rm logs * user search overflow, org create i18n, meta cleanup * sidenav shadow * redirect to org table * lint * lint test files * remove usage of formfieldmodule, use input module, layout optim * replace formfieldmodule usage with inputmodule * lint input dir, scss * user grant, user table optimisations * reorganize sidenav, project table empty, tooltips, avatar ch * user grant tooltips, form field error directive accessor * checkbox overflow fix, table dateblock, i18n tooltips * app placeholder, i18n, optimize mobile layout * change refresh table order, i18n, redirect chips * stylelint * chore(deps-dev): bump stylelint from 13.7.2 to 13.8.0 in /console (#1007) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump stylelint from 13.7.2 to 13.8.0 in /console Bumps [stylelint](https://github.com/stylelint/stylelint) from 13.7.2 to 13.8.0. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/master/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/13.7.2...13.8.0) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular/cli from 11.0.1 to 11.0.2 in /console (#1006) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump @angular/cli from 11.0.1 to 11.0.2 in /console Bumps [@angular/cli](https://github.com/angular/angular-cli) from 11.0.1 to 11.0.2. - [Release notes](https://github.com/angular/angular-cli/releases) - [Commits](https://github.com/angular/angular-cli/compare/v11.0.1...v11.0.2) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump google-proto-files from 2.2.0 to 2.3.0 in /console (#1005) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps): bump google-proto-files from 2.2.0 to 2.3.0 in /console Bumps [google-proto-files](https://github.com/googleapis/nodejs-proto-files) from 2.2.0 to 2.3.0. - [Release notes](https://github.com/googleapis/nodejs-proto-files/releases) - [Changelog](https://github.com/googleapis/nodejs-proto-files/blob/master/CHANGELOG.md) - [Commits](https://github.com/googleapis/nodejs-proto-files/compare/v2.2.0...v2.3.0) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @types/node from 14.14.6 to 14.14.9 in /console (#1004) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump @types/node from 14.14.6 to 14.14.9 in /console Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 14.14.6 to 14.14.9. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular/language-service from 11.0.0 to 11.0.2 in /console (#999) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump @angular/language-service in /console Bumps [@angular/language-service](https://github.com/angular/angular/tree/HEAD/packages/language-service) from 11.0.0 to 11.0.2. - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/11.0.2/packages/language-service) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular-devkit/build-angular from 0.1100.1 to 0.1100.2 in /console (#1003) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump @angular-devkit/build-angular in /console Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.1100.1 to 0.1100.2. - [Release notes](https://github.com/angular/angular-cli/releases) - [Commits](https://github.com/angular/angular-cli/commits) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <[email protected]> * chore(deps-dev): bump prettier from 2.1.2 to 2.2.0 in /console (#1002) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump prettier from 2.1.2 to 2.2.0 in /console Bumps [prettier](https://github.com/prettier/prettier) from 2.1.2 to 2.2.0. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/master/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/2.1.2...2.2.0) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @types/jasmine from 3.6.1 to 3.6.2 in /console (#1001) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump @types/jasmine from 3.6.1 to 3.6.2 in /console Bumps [@types/jasmine](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jasmine) from 3.6.1 to 3.6.2. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jasmine) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <[email protected]> * chore(deps): bump file-saver from 2.0.2 to 2.0.5 in /console (#1000) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps): bump file-saver from 2.0.2 to 2.0.5 in /console Bumps [file-saver](https://github.com/eligrey/FileSaver.js) from 2.0.2 to 2.0.5. - [Release notes](https://github.com/eligrey/FileSaver.js/releases) - [Changelog](https://github.com/eligrey/FileSaver.js/blob/master/CHANGELOG.md) - [Commits](https://github.com/eligrey/FileSaver.js/commits) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <[email protected]> * chore(deps-dev): bump jasmine-spec-reporter in /console (#974) Bumps [jasmine-spec-reporter](https://github.com/bcaudan/jasmine-spec-reporter) from 5.0.2 to 6.0.0. - [Release notes](https://github.com/bcaudan/jasmine-spec-reporter/releases) - [Changelog](https://github.com/bcaudan/jasmine-spec-reporter/blob/master/CHANGELOG.md) - [Commits](https://github.com/bcaudan/jasmine-spec-reporter/compare/v5.0.2...v6.0.0) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * input field border improvements, primary color * redirect form, conventional ux * redirects inputs on app create * fix dynamic suffix padding, user grant layout, lint * input style accessor, contact view optim, ext idp, card fixes * hide error on untouched formfield, border red on error touched * fix change detector * change, user, form validation, delete refresh * safari font weight adjustment, change refresh emitter * key validation * remove tabls layout from projects * app changes, refactor project, app state, meta layout * add key dialog validation, startdate, rever change tabs * stylelint * Update console/src/assets/i18n/en.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/en.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/en.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/en.json Co-authored-by: Florian Forster <[email protected]> * finnaly fix fckntimestamp picker * optional key expiry * small state badge * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Silvan <[email protected]> Co-authored-by: Florian Forster <[email protected]>
This commit is contained in:
co-authored by
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Florian Forster
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Silvan
parent
42f50de790
commit
ae26999834
@@ -6,15 +6,15 @@
|
||||
<div mat-dialog-content>
|
||||
<!-- if no context -->
|
||||
<ng-container *ngIf="showCreationTypeSelector">
|
||||
<mat-form-field class="full-width" appearance="outline">
|
||||
<mat-label>{{ 'MEMBER.CREATIONTYPE' | translate }}</mat-label>
|
||||
<cnsl-form-field class="full-width" appearance="outline">
|
||||
<cnsl-label>{{ 'MEMBER.CREATIONTYPE' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="creationType" (selectionChange)="loadRoles()">
|
||||
<mat-option *ngFor="let type of creationTypes" [value]="type.type"
|
||||
[disabled]="(type.disabled$ | async) == false">
|
||||
{{ 'MEMBER.CREATIONTYPES.'+type.type | translate}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
<ng-container
|
||||
*ngIf="creationType === CreationType.PROJECT_OWNED || creationType === CreationType.PROJECT_GRANTED">
|
||||
@@ -30,15 +30,15 @@
|
||||
<app-search-user-autocomplete [users]="preselectedUsers" (selectionChanged)="users = $event">
|
||||
</app-search-user-autocomplete>
|
||||
|
||||
<mat-form-field class="full-width" appearance="outline"
|
||||
<cnsl-form-field class="full-width" appearance="outline"
|
||||
*ngIf="creationType === CreationType.PROJECT_OWNED || creationType === CreationType.PROJECT_GRANTED || creationType === CreationType.IAM">
|
||||
<mat-label>{{ 'ROLESLABEL' | translate }}</mat-label>
|
||||
<cnsl-label>{{ 'ROLESLABEL' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="roles" multiple>
|
||||
<mat-option *ngFor="let role of memberRoleOptions" [value]="role">
|
||||
{{ role }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
<ng-container *ngIf="creationType === CreationType.ORG">
|
||||
<app-org-member-roles-autocomplete (selectionChanged)="setOrgMemberRoles($event)">
|
||||
|
||||
@@ -4,10 +4,9 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { SearchUserAutocompleteModule } from 'src/app/modules/search-user-autocomplete/search-user-autocomplete.module';
|
||||
|
||||
import {
|
||||
@@ -24,9 +23,8 @@ import { MemberCreateDialogComponent } from './member-create-dialog.component';
|
||||
MatDialogModule,
|
||||
MatButtonModule,
|
||||
MatChipsModule,
|
||||
MatInputModule,
|
||||
TranslateModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatSelectModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="avatar-circle dontcloseonclick" matRipple [matRippleColor]="'#ffffff20'" matRippleUnbounded="true"
|
||||
matRippleCentered="true"
|
||||
[ngStyle]="{'height': size+'px', 'width': size+'px', 'fontSize': (fontSize-1)+'px', 'background-color': color}"
|
||||
[ngStyle]="{'height': size+'px', 'width': size+'px', 'fontSize': (fontSize-1)+'px', 'background': color}"
|
||||
[ngClass]="{'active': active}">
|
||||
{{credentials}}
|
||||
</div>
|
||||
@@ -13,7 +13,10 @@
|
||||
text-transform: uppercase;
|
||||
background-color: $primary-color;
|
||||
box-sizing: border-box;
|
||||
letter-spacing: .05em;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export class AvatarComponent implements OnInit {
|
||||
@Input() name: string = '';
|
||||
@Input() credentials: string = '';
|
||||
@Input() size: number = 24;
|
||||
@Input() fontSize: number = 16;
|
||||
@Input() fontSize: number = 14;
|
||||
@Input() active: boolean = false;
|
||||
@Input() color: string = '';
|
||||
constructor() { }
|
||||
@@ -30,22 +30,22 @@ export class AvatarComponent implements OnInit {
|
||||
|
||||
getColor(userName: string): string {
|
||||
const colors = [
|
||||
'#B44D51',
|
||||
'#B75073',
|
||||
'#84498E',
|
||||
'#705998',
|
||||
'#5C6598',
|
||||
'#7F90D3',
|
||||
'#3E93B9',
|
||||
'#3494A0',
|
||||
'#25716A',
|
||||
'#427E41',
|
||||
'#89A568',
|
||||
'#90924D',
|
||||
'#E2B032',
|
||||
'#C97358',
|
||||
'#6D5B54',
|
||||
'#6B7980',
|
||||
'linear-gradient(40deg, #B44D51 30%, rgb(241,138,138))',
|
||||
'linear-gradient(40deg, #B75073 30%, rgb(234,96,143))',
|
||||
'linear-gradient(40deg, #84498E 30%, rgb(214,116,230))',
|
||||
'linear-gradient(40deg, #705998 30%, rgb(163,131,220))',
|
||||
'linear-gradient(40deg, #5C6598 30%, rgb(135,148,222))',
|
||||
'linear-gradient(40deg, #7F90D3 30%, rgb(181,196,247))',
|
||||
'linear-gradient(40deg, #3E93B9 30%, rgb(150,215,245))',
|
||||
'linear-gradient(40deg, #3494A0 30%, rgb(71,205,222))',
|
||||
'linear-gradient(40deg, #25716A 30%, rgb(58,185,173))',
|
||||
'linear-gradient(40deg, #427E41 30%, rgb(97,185,96))',
|
||||
'linear-gradient(40deg, #89A568 30%, rgb(176,212,133))',
|
||||
'linear-gradient(40deg, #90924D 30%, rgb(187,189,98))',
|
||||
'linear-gradient(40deg, #E2B032 30%, rgb(245,203,99))',
|
||||
'linear-gradient(40deg, #C97358 30%, rgb(245,148,118))',
|
||||
'linear-gradient(40deg, #6D5B54 30%, rgb(152,121,108))',
|
||||
'linear-gradient(40deg, #6B7980 30%, rgb(134,163,177))',
|
||||
];
|
||||
|
||||
let hash = 0;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
padding: 1.5rem;
|
||||
border-radius: .5rem;
|
||||
padding-top: 1rem;
|
||||
min-width: 350px;
|
||||
min-width: 300px;
|
||||
|
||||
.header {
|
||||
margin-top: 0;
|
||||
@@ -21,7 +21,9 @@
|
||||
.title {
|
||||
margin: 0;
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
font-size: 16px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .05em;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
@@ -45,4 +47,9 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 500px) {
|
||||
margin: .5rem 0;
|
||||
padding: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
<span class="header">{{ 'CHANGES.LISTTITLE' | translate }}</span>
|
||||
<div class="change-header">
|
||||
<span class="ch-header">{{ 'CHANGES.LISTTITLE' | translate }}</span>
|
||||
<button matTooltip="{{'ACTIONS.REFRESH' | translate}}" (click)="init()" mat-icon-button>
|
||||
<mat-icon class="icon">refresh</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="scroll-container" appScrollable (scrollPosition)="scrollHandler($event)">
|
||||
<li class="item change-item-back" *ngFor="let event of data | async">
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
.header {
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 400;
|
||||
margin-top: 1rem;
|
||||
font-size: 14px;
|
||||
.change-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.ch-header {
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 400;
|
||||
margin-top: 1rem;
|
||||
font-size: 14px;
|
||||
letter-spacing: .05em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin changes-theme($theme) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { BehaviorSubject, from, Observable, of } from 'rxjs';
|
||||
import { catchError, scan, take, tap } from 'rxjs/operators';
|
||||
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { BehaviorSubject, from, Observable, of, Subject } from 'rxjs';
|
||||
import { catchError, debounceTime, scan, take, takeUntil, tap } from 'rxjs/operators';
|
||||
import { Change, Changes } from 'src/app/proto/generated/management_pb';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
@@ -10,6 +10,7 @@ export enum ChangeType {
|
||||
USER = 'user',
|
||||
ORG = 'org',
|
||||
PROJECT = 'project',
|
||||
APP = 'app',
|
||||
}
|
||||
|
||||
@Component({
|
||||
@@ -17,10 +18,12 @@ export enum ChangeType {
|
||||
templateUrl: './changes.component.html',
|
||||
styleUrls: ['./changes.component.scss'],
|
||||
})
|
||||
export class ChangesComponent implements OnInit {
|
||||
export class ChangesComponent implements OnInit, OnDestroy {
|
||||
@Input() public changeType: ChangeType = ChangeType.USER;
|
||||
@Input() public id: string = '';
|
||||
@Input() public secId: string = '';
|
||||
@Input() public sortDirectionAsc: boolean = true;
|
||||
@Input() public refresh!: Observable<void>;
|
||||
public bottom: boolean = false;
|
||||
|
||||
private _done: BehaviorSubject<any> = new BehaviorSubject(false);
|
||||
@@ -30,10 +33,23 @@ export class ChangesComponent implements OnInit {
|
||||
loading: Observable<boolean> = this._loading.asObservable();
|
||||
public data!: Observable<Change.AsObject[]>;
|
||||
public changes!: Changes.AsObject;
|
||||
constructor(private mgmtUserService: ManagementService, private authUserService: GrpcAuthService) { }
|
||||
private destroyed$: Subject<void> = new Subject();
|
||||
constructor(private mgmtUserService: ManagementService, private authUserService: GrpcAuthService) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.init();
|
||||
if (this.refresh) {
|
||||
this.refresh.pipe(takeUntil(this.destroyed$), debounceTime(2000)).subscribe(() => {
|
||||
console.log('asdf');
|
||||
this.init();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroyed$.next();
|
||||
}
|
||||
|
||||
public scrollHandler(e: any): void {
|
||||
@@ -42,7 +58,7 @@ export class ChangesComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private init(): void {
|
||||
public init(): void {
|
||||
let first: Promise<Changes>;
|
||||
switch (this.changeType) {
|
||||
case ChangeType.MYUSER: first = this.authUserService.GetMyUserChanges(20, 0);
|
||||
@@ -53,6 +69,8 @@ export class ChangesComponent implements OnInit {
|
||||
break;
|
||||
case ChangeType.ORG: first = this.mgmtUserService.OrgChanges(this.id, 20, 0);
|
||||
break;
|
||||
case ChangeType.APP: first = this.mgmtUserService.ApplicationChanges(this.id, this.secId, 20, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
this.mapAndUpdate(first);
|
||||
@@ -78,6 +96,8 @@ export class ChangesComponent implements OnInit {
|
||||
break;
|
||||
case ChangeType.ORG: more = this.mgmtUserService.OrgChanges(this.id, 20, cursor);
|
||||
break;
|
||||
case ChangeType.APP: more = this.mgmtUserService.ApplicationChanges(this.id, this.secId, 20, cursor);
|
||||
break;
|
||||
}
|
||||
|
||||
this.mapAndUpdate(more);
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ScrollableModule } from 'src/app/directives/scrollable/scrollable.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
@@ -20,10 +23,13 @@ import { ChangesComponent } from './changes.component';
|
||||
ScrollableModule,
|
||||
MatProgressSpinnerModule,
|
||||
TranslateModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
HasRolePipeModule,
|
||||
ScrollingModule,
|
||||
LocalizedDatePipeModule,
|
||||
TimestampToDatePipeModule,
|
||||
MatTooltipModule,
|
||||
],
|
||||
exports: [
|
||||
ChangesComponent,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="groups">
|
||||
<span class="header">{{ title }}</span>
|
||||
<span class="co-header">{{ title }}</span>
|
||||
<span class="sub-header">{{ description }}</span>
|
||||
<div class="people">
|
||||
<div class="img-list" [@cardAnimation]="totalResult">
|
||||
@@ -34,9 +34,9 @@
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
<span class="fill-space"></span>
|
||||
<button class="refresh-img" (click)="emitRefresh()" [disabled]="disabled" mat-icon-button
|
||||
aria-label="refresh contributors">
|
||||
<mat-icon>refresh</mat-icon>
|
||||
<button matTooltip="{{'ACTIONS.REFRESH' | translate}}" class="refresh-img" (click)="emitRefresh()"
|
||||
[disabled]="disabled" mat-icon-button aria-label="refresh contributors">
|
||||
<mat-icon class="icon">refresh</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
.groups {
|
||||
padding-top: 1rem;
|
||||
|
||||
.header {
|
||||
.co-header {
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
letter-spacing: .05em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.sub-header {
|
||||
@@ -45,7 +48,11 @@
|
||||
|
||||
.refresh-img {
|
||||
float: left;
|
||||
margin: 0 8px 0 -15px;
|
||||
margin: 0 0 0 -15px;
|
||||
|
||||
.icon {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-circle {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { AvatarModule } from '../avatar/avatar.module';
|
||||
import { ContributorsComponent } from './contributors.component';
|
||||
@@ -19,6 +20,7 @@ import { ContributorsComponent } from './contributors.component';
|
||||
MatTooltipModule,
|
||||
MatButtonModule,
|
||||
MatProgressSpinnerModule,
|
||||
TranslateModule,
|
||||
],
|
||||
exports: [
|
||||
ContributorsComponent,
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
padding-bottom: 3rem;
|
||||
|
||||
.detail-left {
|
||||
align-self: flex-start;
|
||||
width: 100px;
|
||||
display: flex;
|
||||
padding: 1rem;
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { animate, AnimationTriggerMetadata, state, style, transition, trigger } from '@angular/animations';
|
||||
|
||||
/**
|
||||
* Animations used by the CnslFormFieldComponent.
|
||||
*/
|
||||
export const cnslFormFieldAnimations: {
|
||||
readonly transitionMessages: AnimationTriggerMetadata;
|
||||
} = {
|
||||
/** Animation that transitions the form field's error and hint messages. */
|
||||
transitionMessages: trigger('transitionMessages', [
|
||||
// TODO(mmalerba): Use angular animations for label animation as well.
|
||||
state('enter', style({ opacity: 1, transform: 'translateY(0%)' })),
|
||||
transition('void => enter', [
|
||||
style({ opacity: 0, transform: 'translateY(-100%)' }),
|
||||
animate('3000ms cubic-bezier(0.55, 0, 0.55, 0.2)'),
|
||||
]),
|
||||
]),
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Directive, InjectionToken, Input } from '@angular/core';
|
||||
|
||||
let nextUniqueId = 0;
|
||||
|
||||
export const CNSL_ERROR = new InjectionToken<CnslErrorDirective>('CnslError');
|
||||
|
||||
@Directive({
|
||||
selector: '[cnsl-error]',
|
||||
host: {
|
||||
'class': 'cnsl-error',
|
||||
'role': 'alert',
|
||||
'[attr.id]': 'id',
|
||||
},
|
||||
providers: [{ provide: CNSL_ERROR, useExisting: CnslErrorDirective }],
|
||||
})
|
||||
export class CnslErrorDirective {
|
||||
@Input() id: string = `cnsl-error-${nextUniqueId++}`;
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<div class="cnsl-form-field-wrapper" (click)="_control.onContainerClick && _control.onContainerClick($event)">
|
||||
<ng-content select="cnsl-label"></ng-content>
|
||||
<div class="cnsl-rel" #inputContainer>
|
||||
<ng-content></ng-content>
|
||||
<ng-content select="cnslSuffix"></ng-content>
|
||||
</div>
|
||||
<div class="cnsl-form-field-subscript-wrapper" [ngSwitch]="_getDisplayedMessages()">
|
||||
<div *ngSwitchCase="'error'" class="cnsl-form-field-error-wrapper"
|
||||
[@transitionMessages]="_subscriptAnimationState">
|
||||
<ng-content select="cnsl-error"></ng-content>
|
||||
</div>
|
||||
<div *ngSwitchCase="'hint'" class="cnsl-form-field-hint-wrapper"
|
||||
[@transitionMessages]="_subscriptAnimationState">
|
||||
<ng-content select="cnsl-hint"></ng-content>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
@mixin cnsl-form-field-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
$primary-color: mat-color($primary, 500);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
|
||||
.ng-untouched {
|
||||
.cnsl-error {
|
||||
visibility: hidden;
|
||||
transition: visibility .2 ease;
|
||||
}
|
||||
}
|
||||
|
||||
.cnsl-form-field-wrapper {
|
||||
width: 100%;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.cnsl-rel {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[cnslSuffix] {
|
||||
position: absolute;
|
||||
right: .5rem;
|
||||
top: 9px;
|
||||
height: inherit;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
// Wrapper for the hints and error messages.
|
||||
.cnsl-form-field-subscript-wrapper {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
overflow: hidden; // prevents multi-line errors from overlapping the control
|
||||
}
|
||||
|
||||
.cnsl-form-field-hint-wrapper,
|
||||
.cnsl-form-field-error-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { CnslFormFieldComponent } from './form-field.component';
|
||||
|
||||
describe('CnslFormFieldComponent', () => {
|
||||
let component: CnslFormFieldComponent;
|
||||
let fixture: ComponentFixture<CnslFormFieldComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [CnslFormFieldComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CnslFormFieldComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,164 @@
|
||||
import {
|
||||
AfterContentInit,
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ContentChild,
|
||||
ContentChildren,
|
||||
ElementRef,
|
||||
HostListener,
|
||||
Inject,
|
||||
InjectionToken,
|
||||
OnDestroy,
|
||||
QueryList,
|
||||
ViewChild,
|
||||
ViewEncapsulation,
|
||||
} from '@angular/core';
|
||||
import { NgControl } from '@angular/forms';
|
||||
import { MatFormFieldControl } from '@angular/material/form-field';
|
||||
import { Subject } from 'rxjs';
|
||||
import { startWith, takeUntil } from 'rxjs/operators';
|
||||
|
||||
import { cnslFormFieldAnimations } from './animations';
|
||||
import { CNSL_ERROR, CnslErrorDirective } from './error.directive';
|
||||
import { _CNSL_HINT, CnslHintDirective } from './hint.directive';
|
||||
|
||||
export const CNSL_FORM_FIELD = new InjectionToken<CnslFormFieldComponent>('CnslFormFieldComponent');
|
||||
|
||||
class CnslFormFieldBase {
|
||||
constructor(public _elementRef: ElementRef) { }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-form-field',
|
||||
templateUrl: './form-field.component.html',
|
||||
styleUrls: ['./form-field.component.scss'],
|
||||
providers: [
|
||||
{ provide: CNSL_FORM_FIELD, useExisting: CnslFormFieldComponent },
|
||||
],
|
||||
host: {
|
||||
'[class.ng-untouched]': '_shouldForward("untouched")',
|
||||
'[class.ng-touched]': '_shouldForward("touched")',
|
||||
'[class.ng-pristine]': '_shouldForward("pristine")',
|
||||
'[class.ng-dirty]': '_shouldForward("dirty")',
|
||||
'[class.ng-valid]': '_shouldForward("valid")',
|
||||
'[class.ng-invalid]': '_shouldForward("invalid")',
|
||||
'[class.ng-pending]': '_shouldForward("pending")',
|
||||
// '[class.cnsl-form-field-invalid]': '_control.errorState',
|
||||
},
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
animations: [cnslFormFieldAnimations.transitionMessages],
|
||||
})
|
||||
export class CnslFormFieldComponent extends CnslFormFieldBase implements OnDestroy, AfterContentInit, AfterViewInit {
|
||||
focused: boolean = false;
|
||||
private _destroyed: Subject<void> = new Subject<void>();
|
||||
|
||||
@ViewChild('connectionContainer', { static: true }) _connectionContainerRef!: ElementRef;
|
||||
@ViewChild('inputContainer') _inputContainerRef!: ElementRef;
|
||||
@ContentChild(MatFormFieldControl) _controlNonStatic!: MatFormFieldControl<any>;
|
||||
@ContentChild(MatFormFieldControl, { static: true }) _controlStatic!: MatFormFieldControl<any>;
|
||||
get _control(): MatFormFieldControl<any> {
|
||||
// TODO(crisbeto): we need this workaround in order to support both Ivy and ViewEngine.
|
||||
// We should clean this up once Ivy is the default renderer.
|
||||
return this._explicitFormFieldControl || this._controlNonStatic || this._controlStatic;
|
||||
}
|
||||
set _control(value: MatFormFieldControl<any>) {
|
||||
this._explicitFormFieldControl = value;
|
||||
}
|
||||
private _explicitFormFieldControl!: MatFormFieldControl<any>;
|
||||
readonly stateChanges: Subject<void> = new Subject<void>();
|
||||
|
||||
_subscriptAnimationState: string = '';
|
||||
|
||||
@ContentChildren(CNSL_ERROR as any, { descendants: true }) _errorChildren!: QueryList<CnslErrorDirective>;
|
||||
@ContentChildren(_CNSL_HINT, { descendants: true }) _hintChildren!: QueryList<CnslHintDirective>;
|
||||
|
||||
@HostListener('blur', ['false'])
|
||||
_focusChanged(isFocused: boolean): void {
|
||||
console.log('blur1');
|
||||
if (isFocused !== this.focused && (!isFocused)) {
|
||||
this.focused = isFocused;
|
||||
this.stateChanges.next();
|
||||
}
|
||||
}
|
||||
|
||||
constructor(public _elementRef: ElementRef, private _changeDetectorRef: ChangeDetectorRef,
|
||||
@Inject(ElementRef)
|
||||
// Use `ElementRef` here so Angular has something to inject.
|
||||
_labelOptions: any) {
|
||||
super(_elementRef);
|
||||
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
// Avoid animations on load.
|
||||
this._subscriptAnimationState = 'enter';
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this._destroyed.next();
|
||||
this._destroyed.complete();
|
||||
}
|
||||
|
||||
public ngAfterContentInit(): void {
|
||||
this._validateControlChild();
|
||||
|
||||
const control = this._control;
|
||||
control.stateChanges.pipe(startWith(null)).subscribe(() => {
|
||||
this._syncDescribedByIds();
|
||||
this._changeDetectorRef.markForCheck();
|
||||
});
|
||||
|
||||
// Run change detection if the value changes.
|
||||
if (control.ngControl && control.ngControl.valueChanges) {
|
||||
control.ngControl.valueChanges
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.subscribe(() => this._changeDetectorRef.markForCheck());
|
||||
}
|
||||
|
||||
// Update the aria-described by when the number of errors changes.
|
||||
this._errorChildren.changes.pipe(startWith(null)).subscribe(() => {
|
||||
this._syncDescribedByIds();
|
||||
this._changeDetectorRef.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
/** Throws an error if the form field's control is missing. */
|
||||
protected _validateControlChild(): void {
|
||||
if (!this._control) {
|
||||
throw Error('cnsl-form-field must contain a MatFormFieldControl.');
|
||||
}
|
||||
}
|
||||
|
||||
private _syncDescribedByIds(): void {
|
||||
if (this._control) {
|
||||
const ids: string[] = [];
|
||||
|
||||
// TODO(wagnermaciel): Remove the type check when we find the root cause of this bug.
|
||||
if (this._control.userAriaDescribedBy &&
|
||||
typeof this._control.userAriaDescribedBy === 'string') {
|
||||
ids.push(...this._control.userAriaDescribedBy.split(' '));
|
||||
}
|
||||
|
||||
if (this._errorChildren) {
|
||||
ids.push(...this._errorChildren.map(error => error.id));
|
||||
}
|
||||
|
||||
this._control.setDescribedByIds(ids);
|
||||
}
|
||||
}
|
||||
|
||||
/** Determines whether a class from the NgControl should be forwarded to the host element. */
|
||||
_shouldForward(prop: keyof NgControl): boolean {
|
||||
const ngControl = this._control ? this._control.ngControl : null;
|
||||
return ngControl && ngControl[prop];
|
||||
}
|
||||
|
||||
/** Determines whether to display hints or errors. */
|
||||
_getDisplayedMessages(): 'error' | 'hint' {
|
||||
return (this._errorChildren && this._errorChildren.length > 0) ? 'error' : 'hint';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MatRippleModule } from '@angular/material/core';
|
||||
import { LabelModule } from 'src/app/modules/label/label.module';
|
||||
|
||||
import { LabelComponent } from '../label/label.component';
|
||||
import { CnslErrorDirective } from './error.directive';
|
||||
import { CnslFormFieldComponent } from './form-field.component';
|
||||
import { CnslHintDirective } from './hint.directive';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CnslFormFieldComponent,
|
||||
CnslErrorDirective,
|
||||
CnslHintDirective,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatRippleModule,
|
||||
LabelModule,
|
||||
],
|
||||
exports: [
|
||||
CnslFormFieldComponent,
|
||||
LabelComponent,
|
||||
CnslErrorDirective,
|
||||
CnslHintDirective,
|
||||
],
|
||||
})
|
||||
export class FormFieldModule { }
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Directive, InjectionToken, Input } from '@angular/core';
|
||||
|
||||
let nextUniqueId = 0;
|
||||
|
||||
/**
|
||||
* Injection token that can be used to reference instances of `MatHint`. It serves as
|
||||
* alternative token to the actual `MatHint` class which could cause unnecessary
|
||||
* retention of the class and its directive metadata.
|
||||
*
|
||||
* *Note*: This is not part of the public API as the MDC-based form-field will not
|
||||
* need a lightweight token for `MatHint` and we want to reduce breaking changes.
|
||||
*/
|
||||
export const _CNSL_HINT = new InjectionToken<CnslHintDirective>('CnslHintDirective');
|
||||
|
||||
/** Hint text to be shown underneath the form field control. */
|
||||
@Directive({
|
||||
selector: 'cnsl-hint',
|
||||
host: {
|
||||
'class': 'cnsl-hint',
|
||||
'[class.cnsl-form-field-hint-end]': 'align === "end"',
|
||||
'[attr.id]': 'id',
|
||||
// Remove align attribute to prevent it from interfering with layout.
|
||||
'[attr.align]': 'null',
|
||||
},
|
||||
providers: [{ provide: _CNSL_HINT, useExisting: CnslHintDirective }],
|
||||
})
|
||||
export class CnslHintDirective {
|
||||
/** Whether to align the hint label at the start or end of the line. */
|
||||
@Input() align: 'start' | 'end' = 'start';
|
||||
|
||||
/** Unique ID for the hint. Used for the aria-describedby on the form field control. */
|
||||
@Input() id: string = `mat-hint-${nextUniqueId++}`;
|
||||
}
|
||||
@@ -16,56 +16,57 @@
|
||||
<form (ngSubmit)="addIdp()">
|
||||
<ng-container [formGroup]="formGroup">
|
||||
<div class="content">
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'IDP.NAME' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" />
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'IDP.ISSUER' | translate }}</mat-label>
|
||||
<input matInput formControlName="issuer" />
|
||||
</mat-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="issuer" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p class="desc">Client Id / Client Secret</p>
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'IDP.CLIENTID' | translate }}</mat-label>
|
||||
<input matInput formControlName="clientId" />
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'IDP.CLIENTSECRET' | translate }}</mat-label>
|
||||
<input matInput formControlName="clientSecret" />
|
||||
</mat-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="content">
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'IDP.SCOPESLIST' | translate }}</mat-label>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.SCOPESLIST' | translate }}</cnsl-label>
|
||||
<mat-chip-list #chipScopesList aria-label="scope selection" *ngIf="scopesList">
|
||||
<mat-chip class="chip" *ngFor="let scope of scopesList.value" selectable="false" removable
|
||||
(removed)="removeScope(scope)">
|
||||
{{scope}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input [matChipInputFor]="chipScopesList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="true" (matChipInputTokenEnd)="addScope($event)">
|
||||
<input cnslInput [matChipInputFor]="chipScopesList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addScope($event)">
|
||||
</mat-chip-list>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="content">
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'IDP.IDPDISPLAYNAMMAPPING' | translate }}</mat-label>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'IDP.IDPDISPLAYNAMMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="idpDisplayNameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINTFIELD.'+field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'IDP.USERNAMEMAPPING' | translate }}</mat-label>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'IDP.USERNAMEMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="usernameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINTFIELD.'+field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
|
||||
@@ -3,13 +3,12 @@ import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
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 { MatInputModule } from '@angular/material/input';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { IdpCreateRoutingModule } from './idp-create-routing.module';
|
||||
import { IdpCreateComponent } from './idp-create.component';
|
||||
@@ -21,8 +20,7 @@ import { IdpCreateComponent } from './idp-create.component';
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
MatSelectModule,
|
||||
MatIconModule,
|
||||
|
||||
@@ -4,22 +4,22 @@
|
||||
<form (ngSubmit)="updateIdp()">
|
||||
<ng-container [formGroup]="idpForm">
|
||||
<div class="content">
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'IDP.ID' | translate }}</mat-label>
|
||||
<input matInput formControlName="id" />
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'IDP.NAME' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'IDP.STYLE' | translate }}</mat-label>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="id" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'IDP.STYLE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="stylingType">
|
||||
<mat-option *ngFor="let field of styleFields" [value]="field">
|
||||
{{ 'IDP.STYLEFIELD.'+field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
@@ -38,51 +38,51 @@
|
||||
<form (ngSubmit)="updateOidcConfig()">
|
||||
<ng-container [formGroup]="oidcConfigForm">
|
||||
<div class="content">
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'IDP.ISSUER' | translate }}</mat-label>
|
||||
<input matInput formControlName="issuer" />
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'IDP.CLIENTID' | translate }}</mat-label>
|
||||
<input matInput formControlName="clientId" />
|
||||
</mat-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="issuer" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
<mat-checkbox class="desc" [(ngModel)]="showIdSecretSection"
|
||||
[ngModelOptions]="{standalone: true}">
|
||||
Update Client Secret
|
||||
</mat-checkbox>
|
||||
<mat-form-field appearance="outline" class="formfield" *ngIf="showIdSecretSection">
|
||||
<mat-label>{{ 'IDP.CLIENTSECRET' | translate }}</mat-label>
|
||||
<input matInput formControlName="clientSecret" />
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="formfield fullwidth">
|
||||
<mat-label>{{ 'IDP.SCOPESLIST' | translate }}</mat-label>
|
||||
<cnsl-form-field appearance="outline" class="formfield" *ngIf="showIdSecretSection">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield fullwidth">
|
||||
<cnsl-label>{{ 'IDP.SCOPESLIST' | translate }}</cnsl-label>
|
||||
<mat-chip-list #chipScopesList aria-label="scope selection">
|
||||
<mat-chip class="chip" *ngFor="let scope of scopesList?.value" selectable="false"
|
||||
removable (removed)="removeScope(scope)">
|
||||
{{scope}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input [matChipInputFor]="chipScopesList"
|
||||
<input cnslInput [matChipInputFor]="chipScopesList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addScope($event)">
|
||||
</mat-chip-list>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'IDP.IDPDISPLAYNAMMAPPING' | translate }}</mat-label>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'IDP.IDPDISPLAYNAMMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="idpDisplayNameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINGFIELD.'+field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'IDP.USERNAMEMAPPING' | translate }}</mat-label>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'IDP.USERNAMEMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="usernameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINGFIELD.'+field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
|
||||
@@ -4,16 +4,15 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { IdpRoutingModule } from './idp-routing.module';
|
||||
import { IdpComponent } from './idp.component';
|
||||
import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
|
||||
@NgModule({
|
||||
declarations: [IdpComponent],
|
||||
@@ -22,8 +21,7 @@ import { MatSelectModule } from '@angular/material/select';
|
||||
IdpRoutingModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatTooltipModule,
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { FormControl, FormGroupDirective, NgForm } from '@angular/forms';
|
||||
|
||||
|
||||
/** Provider that defines how form controls behave with regards to displaying error messages. */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ErrorStateMatcher {
|
||||
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||
return !!(control && control.invalid && (control.touched || (form && form.submitted)));
|
||||
}
|
||||
}
|
||||
|
||||
/** Error state matcher that matches when a control is invalid and dirty. */
|
||||
@Injectable()
|
||||
export class ShowOnDirtyErrorStateMatcher implements ErrorStateMatcher {
|
||||
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||
return !!(control && control.invalid && (control.dirty || (form && form.submitted)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { InputDirective } from './input.directive';
|
||||
|
||||
describe('InputDirective', () => {
|
||||
it('should create an instance', () => {
|
||||
const directive = new InputDirective();
|
||||
expect(directive).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,459 @@
|
||||
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||
import { getSupportedInputTypes, Platform } from '@angular/cdk/platform';
|
||||
import { AutofillMonitor } from '@angular/cdk/text-field';
|
||||
import {
|
||||
AfterViewInit,
|
||||
Directive,
|
||||
DoCheck,
|
||||
ElementRef,
|
||||
HostListener,
|
||||
Inject,
|
||||
Input,
|
||||
NgZone,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
Optional,
|
||||
Self,
|
||||
} from '@angular/core';
|
||||
import { FormGroupDirective, NgControl, NgForm } from '@angular/forms';
|
||||
import { CanUpdateErrorState, CanUpdateErrorStateCtor, ErrorStateMatcher, mixinErrorState } from '@angular/material/core';
|
||||
import { MAT_FORM_FIELD, MatFormField, MatFormFieldControl } from '@angular/material/form-field';
|
||||
import { getMatInputUnsupportedTypeError, MAT_INPUT_VALUE_ACCESSOR } from '@angular/material/input';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
|
||||
// Invalid input type. Using one of these will throw an MatInputUnsupportedTypeError.
|
||||
const MAT_INPUT_INVALID_TYPES = [
|
||||
'button',
|
||||
'checkbox',
|
||||
'file',
|
||||
'hidden',
|
||||
'image',
|
||||
'radio',
|
||||
'range',
|
||||
'reset',
|
||||
'submit',
|
||||
];
|
||||
|
||||
let nextUniqueId = 0;
|
||||
|
||||
// Boilerplate for applying mixins to MatInput.
|
||||
/** @docs-private */
|
||||
class MatInputBase {
|
||||
constructor(public _defaultErrorStateMatcher: ErrorStateMatcher,
|
||||
public _parentForm: NgForm,
|
||||
public _parentFormGroup: FormGroupDirective,
|
||||
/** @docs-private */
|
||||
public ngControl: NgControl) { }
|
||||
}
|
||||
const _MatInputMixinBase: CanUpdateErrorStateCtor & typeof MatInputBase =
|
||||
mixinErrorState(MatInputBase);
|
||||
|
||||
/** Directive that allows a native input to work inside a `MatFormField`. */
|
||||
@Directive({
|
||||
selector: `input[cnslInput], textarea[cnslInput], select[cnslNativeControl]`,
|
||||
exportAs: 'cnslInput',
|
||||
host: {
|
||||
/**
|
||||
* @breaking-change 8.0.0 remove .mat-form-field-autofill-control in favor of AutofillMonitor.
|
||||
*/
|
||||
// 'class': 'cnsl-input-element cnsl-form-field-autofill-control',
|
||||
// '[class.mat-input-server]': '_isServer',
|
||||
// Native input properties that are overwritten by Angular inputs need to be synced with
|
||||
// the native input element. Otherwise property bindings for those don't work.
|
||||
'[attr.id]': 'id',
|
||||
// At the time of writing, we have a lot of customer tests that look up the input based on its
|
||||
// placeholder. Since we sometimes omit the placeholder attribute from the DOM to prevent screen
|
||||
// readers from reading it twice, we have to keep it somewhere in the DOM for the lookup.
|
||||
'[attr.data-placeholder]': 'placeholder',
|
||||
'[disabled]': 'disabled',
|
||||
'[required]': 'required',
|
||||
'[attr.readonly]': 'readonly && !_isNativeSelect || null',
|
||||
'[attr.aria-invalid]': 'errorState',
|
||||
'[attr.aria-required]': 'required.toString()',
|
||||
},
|
||||
providers: [{ provide: MatFormFieldControl, useExisting: InputDirective }],
|
||||
})
|
||||
export class InputDirective extends _MatInputMixinBase implements MatFormFieldControl<any>, OnChanges,
|
||||
OnDestroy, AfterViewInit, DoCheck, CanUpdateErrorState {
|
||||
protected _uid: string = `cnsl-input-${nextUniqueId++}`;
|
||||
protected _previousNativeValue: any;
|
||||
private _inputValueAccessor: { value: any; };
|
||||
private _previousPlaceholder!: string | null;
|
||||
|
||||
/** Whether the component is being rendered on the server. */
|
||||
readonly _isServer: boolean;
|
||||
|
||||
/** Whether the component is a native html select. */
|
||||
readonly _isNativeSelect: boolean;
|
||||
|
||||
/** Whether the component is a textarea. */
|
||||
readonly _isTextarea: boolean;
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
focused: boolean = false;
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
readonly stateChanges: Subject<void> = new Subject<void>();
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
controlType: string = 'mat-input';
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
autofilled: boolean = false;
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
@Input()
|
||||
get disabled(): boolean {
|
||||
if (this.ngControl && this.ngControl.disabled !== null) {
|
||||
return this.ngControl.disabled;
|
||||
}
|
||||
return this._disabled;
|
||||
}
|
||||
set disabled(value: boolean) {
|
||||
this._disabled = coerceBooleanProperty(value);
|
||||
|
||||
// Browsers may not fire the blur event if the input is disabled too quickly.
|
||||
// Reset from here to ensure that the element doesn't become stuck.
|
||||
if (this.focused) {
|
||||
this.focused = false;
|
||||
this.stateChanges.next();
|
||||
}
|
||||
}
|
||||
protected _disabled: boolean = false;
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
@Input()
|
||||
get id(): string { return this._id; }
|
||||
set id(value: string) { this._id = value || this._uid; }
|
||||
protected _id!: string;
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
@Input() placeholder!: string;
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
@Input()
|
||||
get required(): boolean { return this._required; }
|
||||
set required(value: boolean) { this._required = coerceBooleanProperty(value); }
|
||||
protected _required: boolean = false;
|
||||
|
||||
/** Input type of the element. */
|
||||
@Input()
|
||||
get type(): string { return this._type; }
|
||||
set type(value: string) {
|
||||
this._type = value || 'text';
|
||||
this._validateType();
|
||||
|
||||
// When using Angular inputs, developers are no longer able to set the properties on the native
|
||||
// input element. To ensure that bindings for `type` work, we need to sync the setter
|
||||
// with the native property. Textarea elements don't support the type property or attribute.
|
||||
if (!this._isTextarea && getSupportedInputTypes().has(this._type)) {
|
||||
(this._elementRef.nativeElement as HTMLInputElement).type = this._type;
|
||||
}
|
||||
}
|
||||
protected _type: string = 'text';
|
||||
|
||||
/** An object used to control when error messages are shown. */
|
||||
@Input() errorStateMatcher!: ErrorStateMatcher;
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
// tslint:disable-next-line:no-input-rename
|
||||
@Input('aria-describedby') userAriaDescribedBy!: string;
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
@Input()
|
||||
get value(): string { return this._inputValueAccessor.value; }
|
||||
set value(value: string) {
|
||||
if (value !== this.value) {
|
||||
this._inputValueAccessor.value = value;
|
||||
this.stateChanges.next();
|
||||
}
|
||||
}
|
||||
|
||||
/** Whether the element is readonly. */
|
||||
@Input()
|
||||
get readonly(): boolean { return this._readonly; }
|
||||
set readonly(value: boolean) { this._readonly = coerceBooleanProperty(value); }
|
||||
private _readonly: boolean = false;
|
||||
|
||||
protected _neverEmptyInputTypes: string[] = [
|
||||
'date',
|
||||
'datetime',
|
||||
'datetime-local',
|
||||
'month',
|
||||
'time',
|
||||
'week',
|
||||
].filter(t => getSupportedInputTypes().has(t));
|
||||
|
||||
constructor(
|
||||
protected _elementRef: ElementRef<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>,
|
||||
protected _platform: Platform,
|
||||
/** @docs-private */
|
||||
@Optional() @Self() public ngControl: NgControl,
|
||||
@Optional() _parentForm: NgForm,
|
||||
@Optional() _parentFormGroup: FormGroupDirective,
|
||||
_defaultErrorStateMatcher: ErrorStateMatcher,
|
||||
@Optional() @Self() @Inject(MAT_INPUT_VALUE_ACCESSOR) inputValueAccessor: any,
|
||||
private _autofillMonitor: AutofillMonitor,
|
||||
ngZone: NgZone,
|
||||
// TODO: Remove this once the legacy appearance has been removed. We only need
|
||||
// to inject the form-field for determining whether the placeholder has been promoted.
|
||||
@Optional() @Inject(MAT_FORM_FIELD) private _formField?: MatFormField) {
|
||||
|
||||
super(_defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl);
|
||||
|
||||
const element = this._elementRef.nativeElement;
|
||||
const nodeName = element.nodeName.toLowerCase();
|
||||
|
||||
// If no input value accessor was explicitly specified, use the element as the input value
|
||||
// accessor.
|
||||
this._inputValueAccessor = inputValueAccessor || element;
|
||||
|
||||
this._previousNativeValue = this.value;
|
||||
|
||||
// Force setter to be called in case id was not specified.
|
||||
this.id = this.id;
|
||||
|
||||
// On some versions of iOS the caret gets stuck in the wrong place when holding down the delete
|
||||
// key. In order to get around this we need to "jiggle" the caret loose. Since this bug only
|
||||
// exists on iOS, we only bother to install the listener on iOS.
|
||||
if (_platform.IOS) {
|
||||
ngZone.runOutsideAngular(() => {
|
||||
_elementRef.nativeElement.addEventListener('keyup', (event: Event) => {
|
||||
const el: HTMLInputElement = event.target as HTMLInputElement;
|
||||
if (!el.value && !el.selectionStart && !el.selectionEnd) {
|
||||
// Note: Just setting `0, 0` doesn't fix the issue. Setting
|
||||
// `1, 1` fixes it for the first time that you type text and
|
||||
// then hold delete. Toggling to `1, 1` and then back to
|
||||
// `0, 0` seems to completely fix it.
|
||||
el.setSelectionRange(1, 1);
|
||||
el.setSelectionRange(0, 0);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this._isServer = !this._platform.isBrowser;
|
||||
this._isNativeSelect = nodeName === 'select';
|
||||
this._isTextarea = nodeName === 'textarea';
|
||||
|
||||
if (this._isNativeSelect) {
|
||||
this.controlType = (element as HTMLSelectElement).multiple ? 'mat-native-select-multiple' :
|
||||
'mat-native-select';
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (this._platform.isBrowser) {
|
||||
this._autofillMonitor.monitor(this._elementRef.nativeElement).subscribe(event => {
|
||||
this.autofilled = event.isAutofilled;
|
||||
this.stateChanges.next();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngOnChanges(): void {
|
||||
this.stateChanges.next();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.stateChanges.complete();
|
||||
|
||||
if (this._platform.isBrowser) {
|
||||
this._autofillMonitor.stopMonitoring(this._elementRef.nativeElement);
|
||||
}
|
||||
}
|
||||
|
||||
ngDoCheck(): void {
|
||||
if (this.ngControl) {
|
||||
// We need to re-evaluate this on every change detection cycle, because there are some
|
||||
// error triggers that we can't subscribe to (e.g. parent form submissions). This means
|
||||
// that whatever logic is in here has to be super lean or we risk destroying the performance.
|
||||
this.updateErrorState();
|
||||
}
|
||||
|
||||
// We need to dirty-check the native element's value, because there are some cases where
|
||||
// we won't be notified when it changes (e.g. the consumer isn't using forms or they're
|
||||
// updating the value using `emitEvent: false`).
|
||||
this._dirtyCheckNativeValue();
|
||||
|
||||
// We need to dirty-check and set the placeholder attribute ourselves, because whether it's
|
||||
// present or not depends on a query which is prone to "changed after checked" errors.
|
||||
this._dirtyCheckPlaceholder();
|
||||
}
|
||||
|
||||
/** Focuses the input. */
|
||||
focus(options?: FocusOptions): void {
|
||||
this._elementRef.nativeElement.focus(options);
|
||||
}
|
||||
|
||||
// We have to use a `HostListener` here in order to support both Ivy and ViewEngine.
|
||||
// In Ivy the `host` bindings will be merged when this class is extended, whereas in
|
||||
// ViewEngine they're overwritten.
|
||||
// TODO(crisbeto): we move this back into `host` once Ivy is turned on by default.
|
||||
/** Callback for the cases where the focused state of the input changes. */
|
||||
// tslint:disable:no-host-decorator-in-concrete
|
||||
@HostListener('focus', ['true'])
|
||||
@HostListener('blur', ['false'])
|
||||
// tslint:enable:no-host-decorator-in-concrete
|
||||
_focusChanged(isFocused: boolean): void {
|
||||
if (isFocused !== this.focused && (!this.readonly || !isFocused)) {
|
||||
this.focused = isFocused;
|
||||
this.stateChanges.next();
|
||||
}
|
||||
}
|
||||
|
||||
// We have to use a `HostListener` here in order to support both Ivy and ViewEngine.
|
||||
// In Ivy the `host` bindings will be merged when this class is extended, whereas in
|
||||
// ViewEngine they're overwritten.
|
||||
// TODO(crisbeto): we move this back into `host` once Ivy is turned on by default.
|
||||
// tslint:disable-next-line:no-host-decorator-in-concrete
|
||||
@HostListener('input')
|
||||
_onInput(): void {
|
||||
// This is a noop function and is used to let Angular know whenever the value changes.
|
||||
// Angular will run a new change detection each time the `input` event has been dispatched.
|
||||
// It's necessary that Angular recognizes the value change, because when floatingLabel
|
||||
// is set to false and Angular forms aren't used, the placeholder won't recognize the
|
||||
// value changes and will not disappear.
|
||||
// Listening to the input event wouldn't be necessary when the input is using the
|
||||
// FormsModule or ReactiveFormsModule, because Angular forms also listens to input events.
|
||||
}
|
||||
|
||||
/** Does some manual dirty checking on the native input `placeholder` attribute. */
|
||||
private _dirtyCheckPlaceholder(): void {
|
||||
// If we're hiding the native placeholder, it should also be cleared from the DOM, otherwise
|
||||
// screen readers will read it out twice: once from the label and once from the attribute.
|
||||
// TODO: can be removed once we get rid of the `legacy` style for the form field, because it's
|
||||
// the only one that supports promoting the placeholder to a label.
|
||||
const placeholder = this._formField?._hideControlPlaceholder?.() ? null : this.placeholder;
|
||||
if (placeholder !== this._previousPlaceholder) {
|
||||
const element = this._elementRef.nativeElement;
|
||||
this._previousPlaceholder = placeholder;
|
||||
placeholder ?
|
||||
element.setAttribute('placeholder', placeholder) : element.removeAttribute('placeholder');
|
||||
}
|
||||
}
|
||||
|
||||
/** Does some manual dirty checking on the native input `value` property. */
|
||||
protected _dirtyCheckNativeValue(): void {
|
||||
const newValue = this._elementRef.nativeElement.value;
|
||||
|
||||
if (this._previousNativeValue !== newValue) {
|
||||
this._previousNativeValue = newValue;
|
||||
this.stateChanges.next();
|
||||
}
|
||||
}
|
||||
|
||||
/** Make sure the input is a supported type. */
|
||||
protected _validateType(): void {
|
||||
if (MAT_INPUT_INVALID_TYPES.indexOf(this._type) > -1) {
|
||||
throw getMatInputUnsupportedTypeError(this._type);
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks whether the input type is one of the types that are never empty. */
|
||||
protected _isNeverEmpty(): boolean {
|
||||
return this._neverEmptyInputTypes.indexOf(this._type) > -1;
|
||||
}
|
||||
|
||||
/** Checks whether the input is invalid based on the native validation. */
|
||||
protected _isBadInput(): boolean {
|
||||
// The `validity` property won't be present on platform-server.
|
||||
const validity = (this._elementRef.nativeElement as HTMLInputElement).validity;
|
||||
return validity && validity.badInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
get empty(): boolean {
|
||||
return !this._isNeverEmpty() && !this._elementRef.nativeElement.value && !this._isBadInput() &&
|
||||
!this.autofilled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
get shouldLabelFloat(): boolean {
|
||||
if (this._isNativeSelect) {
|
||||
// For a single-selection `<select>`, the label should float when the selected option has
|
||||
// a non-empty display value. For a `<select multiple>`, the label *always* floats to avoid
|
||||
// overlapping the label with the options.
|
||||
const selectElement = this._elementRef.nativeElement as HTMLSelectElement;
|
||||
const firstOption: HTMLOptionElement | undefined = selectElement.options[0];
|
||||
|
||||
// On most browsers the `selectedIndex` will always be 0, however on IE and Edge it'll be
|
||||
// -1 if the `value` is set to something, that isn't in the list of options, at a later point.
|
||||
return this.focused || selectElement.multiple || !this.empty ||
|
||||
!!(selectElement.selectedIndex > -1 && firstOption && firstOption.label);
|
||||
} else {
|
||||
return this.focused || !this.empty;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
setDescribedByIds(ids: string[]): void {
|
||||
if (ids.length) {
|
||||
this._elementRef.nativeElement.setAttribute('aria-describedby', ids.join(' '));
|
||||
} else {
|
||||
this._elementRef.nativeElement.removeAttribute('aria-describedby');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
* @docs-private
|
||||
*/
|
||||
onContainerClick(): void {
|
||||
// Do not re-focus the input element if the element is already focused. Otherwise it can happen
|
||||
// that someone clicks on a time input and the cursor resets to the "hours" field while the
|
||||
// "minutes" field was actually clicked. See: https://github.com/angular/components/issues/12849
|
||||
if (!this.focused) {
|
||||
this.focus();
|
||||
}
|
||||
}
|
||||
// tslint:disable
|
||||
static ngAcceptInputType_disabled: BooleanInput;
|
||||
static ngAcceptInputType_readonly: BooleanInput;
|
||||
static ngAcceptInputType_required: BooleanInput;
|
||||
|
||||
// Accept `any` to avoid conflicts with other directives on `<input>` that may
|
||||
// accept different types.
|
||||
static ngAcceptInputType_value: any;
|
||||
// tslint:enable
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MatRippleModule } from '@angular/material/core';
|
||||
|
||||
import { FormFieldModule } from '../form-field/form-field.module';
|
||||
import { LabelModule } from '../label/label.module';
|
||||
import { ErrorStateMatcher } from './error-options';
|
||||
import { InputDirective } from './input.directive';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [InputDirective],
|
||||
imports: [
|
||||
LabelModule,
|
||||
CommonModule,
|
||||
FormFieldModule,
|
||||
MatRippleModule,
|
||||
],
|
||||
exports: [InputDirective, FormFieldModule],
|
||||
providers: [ErrorStateMatcher],
|
||||
})
|
||||
export class InputModule { }
|
||||
@@ -0,0 +1,3 @@
|
||||
<span class="cnsl-label">
|
||||
<ng-content></ng-content>
|
||||
</span>
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
@mixin cnsl-label-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
$primary-color: mat-color($primary, 500);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
|
||||
.cnsl-label {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: if($is-dark-theme, var(--grey), var(--grey));
|
||||
margin-bottom: 4px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AvatarComponent } from './avatar.component';
|
||||
|
||||
describe('AvatarComponent', () => {
|
||||
let component: AvatarComponent;
|
||||
let fixture: ComponentFixture<AvatarComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AvatarComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AvatarComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-label',
|
||||
templateUrl: './label.component.html',
|
||||
styleUrls: ['./label.component.scss'],
|
||||
})
|
||||
export class LabelComponent {
|
||||
constructor() { }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MatRippleModule } from '@angular/material/core';
|
||||
|
||||
import { LabelComponent } from './label.component';
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [LabelComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatRippleModule,
|
||||
],
|
||||
exports: [
|
||||
LabelComponent,
|
||||
],
|
||||
})
|
||||
export class LabelModule { }
|
||||
|
||||
@@ -73,17 +73,16 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="roles">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'ROLESLABEL' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let member">
|
||||
<mat-form-field class="form-field" appearance="outline">
|
||||
<mat-label>{{ 'ROLESLABEL' | translate }}</mat-label>
|
||||
<th mat-header-cell *matHeaderCellDef class="role-row"> {{ 'ROLESLABEL' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let member" class="role-row">
|
||||
<cnsl-form-field class="form-field" appearance="outline">
|
||||
<mat-select [(ngModel)]="member.rolesList" multiple [disabled]="!canWrite"
|
||||
(selectionChange)="updateRoles.emit({member: member, change: $event})">
|
||||
<mat-option *ngFor="let role of memberRoleOptions" [value]="role">
|
||||
{{ role }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
@@ -26,11 +26,6 @@
|
||||
.action {
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.selection {
|
||||
width: 50px;
|
||||
max-width: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
tr {
|
||||
@@ -60,3 +55,7 @@
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.role-row {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
@@ -12,6 +11,7 @@ import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { AvatarModule } from '../avatar/avatar.module';
|
||||
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
||||
@@ -23,7 +23,7 @@ import { MembersTableComponent } from './members-table.component';
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatSelectModule,
|
||||
MatCheckboxModule,
|
||||
MatIconModule,
|
||||
|
||||
@@ -15,7 +15,7 @@ export class MetaLayoutComponent {
|
||||
}
|
||||
public hidden: boolean = false;
|
||||
public isSmallScreen$: Observable<boolean> = this.breakpointObserver
|
||||
.observe('(max-width: 899px)')
|
||||
.observe('(max-width: 1000px)')
|
||||
.pipe(map(result => {
|
||||
return result.matches;
|
||||
}));
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
@mixin meta-theme($theme) {
|
||||
/* stylelint-disable */
|
||||
$primary: map-get($theme, primary);
|
||||
$primary-color: mat-color($primary, 500);
|
||||
$primary-dark: mat-color($primary, A800);
|
||||
/* stylelint-enable */
|
||||
|
||||
.meta-wrapper {
|
||||
.meta {
|
||||
position: relative;
|
||||
flex: 1 0 300px;
|
||||
|
||||
&::after {
|
||||
border-left: 2px solid $primary-color;
|
||||
-webkit-border-image:
|
||||
-webkit-gradient(
|
||||
linear,
|
||||
left top,
|
||||
left bottom,
|
||||
from($primary-color),
|
||||
to(rgb(0, 0, 0, .5)),
|
||||
color-stop(
|
||||
01,
|
||||
$primary-dark
|
||||
)
|
||||
) 50 21;
|
||||
border-image:
|
||||
-webkit-gradient(
|
||||
linear,
|
||||
left top,
|
||||
left bottom,
|
||||
from($primary-color),
|
||||
to(rgb(0, 0, 0, .5)),
|
||||
color-stop(
|
||||
01,
|
||||
$primary-dark
|
||||
)
|
||||
) 50 21;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,15 @@
|
||||
[description]="'POLICY.LABEL.DESCRIPTION' | translate">
|
||||
|
||||
<div class="content" *ngIf="labelData">
|
||||
<mat-form-field class="form-field" appearance="outline">
|
||||
<mat-label>{{'POLICY.LABEL.PRIMARYCOLOR' | translate}}</mat-label>
|
||||
<input [(ngModel)]="labelData.primaryColor" matInput />
|
||||
</mat-form-field>
|
||||
<cnsl-form-field class="form-field" appearance="outline">
|
||||
<cnsl-label>{{'POLICY.LABEL.PRIMARYCOLOR' | translate}}</cnsl-label>
|
||||
<input cnslInput [(ngModel)]="labelData.primaryColor" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-form-field class="form-field" appearance="outline">
|
||||
<mat-label>{{'POLICY.LABEL.SECONDARYCOLOR' | translate}}</mat-label>
|
||||
<input [(ngModel)]="labelData.secondaryColor" matInput />
|
||||
</mat-form-field>
|
||||
<cnsl-form-field class="form-field" appearance="outline">
|
||||
<cnsl-label>{{'POLICY.LABEL.SECONDARYCOLOR' | translate}}</cnsl-label>
|
||||
<input cnslInput [(ngModel)]="labelData.secondaryColor" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<div class="btn-container">
|
||||
|
||||
@@ -2,14 +2,13 @@ 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 { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { LabelPolicyRoutingModule } from './label-policy-routing.module';
|
||||
import { LabelPolicyComponent } from './label-policy.component';
|
||||
@@ -20,8 +19,7 @@ import { LabelPolicyComponent } from './label-policy.component';
|
||||
LabelPolicyRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
|
||||
+6
-6
@@ -4,25 +4,25 @@
|
||||
<p class="desc"> {{'LOGINPOLICY.ADDIDP.DESCRIPTION' | translate}}</p>
|
||||
|
||||
<div mat-dialog-content>
|
||||
<mat-form-field *ngIf="serviceType == PolicyComponentServiceType.MGMT" class="full-width" appearance="outline">
|
||||
<mat-label>{{ 'IDP.TYPE' | translate }}</mat-label>
|
||||
<cnsl-form-field *ngIf="serviceType == PolicyComponentServiceType.MGMT" class="full-width" appearance="outline">
|
||||
<cnsl-label>{{ 'IDP.TYPE' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="idpType" (selectionChange)="loadIdps()">
|
||||
<mat-option *ngFor="let type of idpTypes" [value]="type">
|
||||
{{ 'IDP.TYPES.'+type | translate}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
<p>{{'LOGINPOLICY.ADDIDP.SELECTIDPS' | translate}}</p>
|
||||
|
||||
<mat-form-field class="full-width" appearance="outline">
|
||||
<mat-label>{{ 'LOGINPOLICY.ADDIDP.SELECTIDPS' | translate }}</mat-label>
|
||||
<cnsl-form-field class="full-width" appearance="outline">
|
||||
<cnsl-label>{{ 'LOGINPOLICY.ADDIDP.SELECTIDPS' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="idp">
|
||||
<mat-option *ngFor="let idp of availableIdps" [value]="idp">
|
||||
{{ idp.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button mat-button (click)="closeDialog()">
|
||||
|
||||
+1
-2
@@ -61,8 +61,7 @@ export class AddIdpDialogComponent {
|
||||
query.setKey(IdpSearchKey.IDPSEARCHKEY_PROVIDER_TYPE);
|
||||
query.setMethod(SearchMethod.SEARCHMETHOD_EQUALS);
|
||||
query.setValue(this.idpType.toString());
|
||||
console.log(this.idpType);
|
||||
console.log(query.toObject());
|
||||
|
||||
this.mgmtService.SearchIdps(undefined, undefined, [query]).then(idps => {
|
||||
this.availableIdps = idps.toObject().resultList;
|
||||
});
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@ import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { AddIdpDialogComponent } from './add-idp-dialog.component';
|
||||
|
||||
@@ -16,7 +16,7 @@ import { AddIdpDialogComponent } from './add-idp-dialog.component';
|
||||
MatDialogModule,
|
||||
MatButtonModule,
|
||||
TranslateModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatSelectModule,
|
||||
FormsModule,
|
||||
],
|
||||
|
||||
@@ -2,9 +2,7 @@ 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 { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
@@ -13,6 +11,7 @@ import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { CardModule } from 'src/app/modules/card/card.module';
|
||||
import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module';
|
||||
import { IdpTableModule } from 'src/app/modules/idp-table/idp-table.module';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { AddIdpDialogModule } from './add-idp-dialog/add-idp-dialog.module';
|
||||
@@ -26,8 +25,7 @@ import { LoginPolicyComponent } from './login-policy.component';
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
CardModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
|
||||
@@ -2,14 +2,13 @@ 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 { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { OrgIamPolicyRoutingModule } from './org-iam-policy-routing.module';
|
||||
import { OrgIamPolicyComponent } from './org-iam-policy.component';
|
||||
@@ -20,8 +19,7 @@ import { OrgIamPolicyComponent } from './org-iam-policy.component';
|
||||
OrgIamPolicyRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
|
||||
@@ -2,14 +2,13 @@ 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 { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { PasswordAgePolicyRoutingModule } from './password-age-policy-routing.module';
|
||||
import { PasswordAgePolicyComponent } from './password-age-policy.component';
|
||||
@@ -20,8 +19,7 @@ import { PasswordAgePolicyComponent } from './password-age-policy.component';
|
||||
PasswordAgePolicyRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
|
||||
+2
-4
@@ -2,15 +2,14 @@ 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 { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
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 { PasswordComplexityPolicyRoutingModule } from './password-complexity-policy-routing.module';
|
||||
import { PasswordComplexityPolicyComponent } from './password-complexity-policy.component';
|
||||
@@ -21,8 +20,7 @@ import { PasswordComplexityPolicyComponent } from './password-complexity-policy.
|
||||
PasswordComplexityPolicyRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
|
||||
+2
-4
@@ -2,14 +2,13 @@ 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 { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { PasswordLockoutPolicyRoutingModule } from './password-lockout-policy-routing.module';
|
||||
import { PasswordLockoutPolicyComponent } from './password-lockout-policy.component';
|
||||
@@ -20,8 +19,7 @@ import { PasswordLockoutPolicyComponent } from './password-lockout-policy.compon
|
||||
PasswordLockoutPolicyRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<h1>{{'POLICY.TITLE' | translate}}</h1>
|
||||
<h2>{{'POLICY.TITLE' | translate}}</h2>
|
||||
|
||||
<p class="top-desc">{{'POLICY.DESCRIPTION' | translate}}</p>
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
h1 {
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
letter-spacing: .05em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.top-desc {
|
||||
@@ -28,7 +30,7 @@ h1 {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(40deg, rgb(129, 85, 185) 30%, #8983f7);
|
||||
background: linear-gradient(40deg, rgb(129, 85, 185) 30%, #5469d4);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
+12
-12
@@ -4,18 +4,18 @@
|
||||
<p class="desc"> {{'PROJECT.ROLE.EDITDESCRIPTION' | translate}}</p>
|
||||
<div mat-dialog-content>
|
||||
<form *ngIf="formGroup" class="full-width" [formGroup]="formGroup" (ngSubmit)="submitForm()">
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'PROJECT.ROLE.KEY' | translate }}</mat-label>
|
||||
<input matInput formControlName="key" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'PROJECT.ROLE.DISPLAY_NAME' | translate }}</mat-label>
|
||||
<input matInput formControlName="displayName" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'PROJECT.ROLE.GROUP' | translate }}</mat-label>
|
||||
<input matInput formControlName="group" />
|
||||
</mat-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'PROJECT.ROLE.KEY' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="key" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'PROJECT.ROLE.DISPLAY_NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="displayName" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'PROJECT.ROLE.GROUP' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="group" />
|
||||
</cnsl-form-field>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -60,6 +60,11 @@
|
||||
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
|
||||
<div *ngIf="(dataSource.loading$ | async) == false && !dataSource?.totalResult" class="no-content-row">
|
||||
<i class="las la-exclamation"></i>
|
||||
<span>{{'PROJECT.ROLE.EMPTY' | translate}}</span>
|
||||
</div>
|
||||
|
||||
<mat-paginator #paginator [length]="dataSource.totalResult" [pageSize]="50"
|
||||
[pageSizeOptions]="[25, 50, 100, 250]">
|
||||
</mat-paginator>
|
||||
|
||||
@@ -26,11 +26,6 @@
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.selection {
|
||||
width: 50px;
|
||||
max-width: 50px;
|
||||
}
|
||||
|
||||
.margin-neg {
|
||||
margin-left: -1rem;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
@@ -15,6 +13,7 @@ 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 { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module';
|
||||
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
|
||||
@@ -33,10 +32,9 @@ import { ProjectRolesComponent } from './project-roles.component';
|
||||
MatTableModule,
|
||||
MatPaginatorModule,
|
||||
MatDialogModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MatInputModule,
|
||||
MatIconModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatCheckboxModule,
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
<div class="table-header-row">
|
||||
<div class="col">
|
||||
<span class="desc"
|
||||
*ngIf="timestamp">{{timestamp | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'}}</span>
|
||||
<ng-container *ngIf="!selection.hasValue()">
|
||||
<span class="desc">{{'ORG_DETAIL.TABLE.TOTAL' | translate}}</span>
|
||||
<span class="count">{{dataSize}}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="selection.hasValue()">
|
||||
<span class="desc">{{'ORG_DETAIL.TABLE.SELECTION' | translate}}</span>
|
||||
<span class="count">{{selection?.selected?.length}}</span>
|
||||
</ng-container>
|
||||
<span *ngIf="!selection.hasValue()" class="count">{{dataSize}}</span>
|
||||
<span *ngIf="selection.hasValue()" class="count">{{selection?.selected?.length}}</span>
|
||||
<div class="desc">
|
||||
<span *ngIf="!selection.hasValue()">{{'ORG_DETAIL.TABLE.TOTAL' | translate}}</span>
|
||||
<span *ngIf="selection.hasValue()">{{'ORG_DETAIL.TABLE.SELECTION' | translate}}</span>
|
||||
<span *ngIf="timestamp">{{timestamp | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="fill-space"></span>
|
||||
<mat-spinner class="spinner" *ngIf="loading" diameter="20"></mat-spinner>
|
||||
|
||||
@@ -6,10 +6,16 @@
|
||||
.col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
.desc {
|
||||
font-size: .8rem;
|
||||
color: var(--grey);
|
||||
margin-right: 1rem;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.count {
|
||||
@@ -31,8 +37,3 @@
|
||||
margin-right: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
// .table-wrapper {
|
||||
// width: 100%;
|
||||
// overflow-x: auto;
|
||||
// }
|
||||
|
||||
@@ -48,7 +48,6 @@ export class RefreshTableComponent implements OnInit {
|
||||
if (this.emitRefreshOnPreviousRoutes.length && this.refreshService.previousUrls
|
||||
.some(url => this.emitRefreshOnPreviousRoutes.includes(url))) {
|
||||
setTimeout(() => {
|
||||
console.log('refresh now');
|
||||
this.emitRefresh();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
<form>
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Project Name</mat-label>
|
||||
<input matInput *ngIf="singleOutput" type="text" placeholder="Search for the project name" #nameInput
|
||||
<cnsl-form-field appearance="outline" class="full-width">
|
||||
<cnsl-label>Project Name</cnsl-label>
|
||||
<input cnslInput *ngIf="singleOutput" type="text" placeholder="Search for the project name" #nameInput
|
||||
[formControl]="myControl" [matAutocomplete]="auto" />
|
||||
|
||||
<mat-chip-list *ngIf="!singleOutput" #chipList aria-label="name selection">
|
||||
@@ -10,7 +10,7 @@
|
||||
{{selectedProject?.name ? selectedProject.name + ' (owned)' : selectedProject?.projectName ? selectedProject.projectName + ' (granted)': ''}}
|
||||
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input placeholder="{{'PROJECT.NAME' | translate}}" #nameInput [formControl]="myControl"
|
||||
<input cnslInput placeholder="{{'PROJECT.NAME' | translate}}" #nameInput [formControl]="myControl"
|
||||
[matAutocomplete]="auto" [matChipInputFor]="chipList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
|
||||
(matChipInputTokenEnd)="add($event)" />
|
||||
@@ -24,5 +24,5 @@
|
||||
{{project?.name ? project.name + ' (owned)' : project?.projectName ? project.projectName + ' (granted)': ''}}
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
</form>
|
||||
+2
-4
@@ -4,12 +4,11 @@ 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 { MatInputModule } from '@angular/material/input';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { SearchProjectAutocompleteComponent } from './search-project-autocomplete.component';
|
||||
|
||||
@@ -22,9 +21,8 @@ import { SearchProjectAutocompleteComponent } from './search-project-autocomplet
|
||||
MatAutocompleteModule,
|
||||
MatChipsModule,
|
||||
MatButtonModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
ReactiveFormsModule,
|
||||
MatProgressSpinnerModule,
|
||||
FormsModule,
|
||||
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
<form>
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Role Name</mat-label>
|
||||
<input matInput *ngIf="singleOutput" type="text" placeholder="Search for the role name" #nameInput
|
||||
<cnsl-form-field appearance="outline" class="full-width">
|
||||
<cnsl-label>Role Name</cnsl-label>
|
||||
<input cnslInput *ngIf="singleOutput" type="text" placeholder="Search for the role name" #nameInput
|
||||
[formControl]="myControl" [matAutocomplete]="auto" />
|
||||
|
||||
<mat-chip-list *ngIf="!singleOutput" #chipList aria-label="name selection">
|
||||
@@ -10,7 +10,7 @@
|
||||
{{selectedRole.displayName}}
|
||||
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input placeholder="Role Name" #nameInput [formControl]="myControl" [matAutocomplete]="auto"
|
||||
<input cnslInput placeholder="Role Name" #nameInput [formControl]="myControl" [matAutocomplete]="auto"
|
||||
[matChipInputFor]="chipList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="addOnBlur" (matChipInputTokenEnd)="add($event)" />
|
||||
</mat-chip-list>
|
||||
@@ -23,5 +23,5 @@
|
||||
{{role.displayName}}
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
</form>
|
||||
+2
-4
@@ -4,11 +4,10 @@ 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 { MatInputModule } from '@angular/material/input';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { SearchRolesAutocompleteComponent } from './search-roles-autocomplete.component';
|
||||
|
||||
@@ -20,9 +19,8 @@ import { SearchRolesAutocompleteComponent } from './search-roles-autocomplete.co
|
||||
MatAutocompleteModule,
|
||||
MatChipsModule,
|
||||
MatButtonModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
ReactiveFormsModule,
|
||||
MatProgressSpinnerModule,
|
||||
FormsModule,
|
||||
|
||||
+14
-14
@@ -1,8 +1,8 @@
|
||||
<form>
|
||||
<mat-form-field *ngIf="target && target == UserTarget.SELF" appearance="outline" class="full-width">
|
||||
<mat-label>Organizations User Loginname</mat-label>
|
||||
<cnsl-form-field *ngIf="target && target == UserTarget.SELF" appearance="outline" class="full-width more-space">
|
||||
<cnsl-label>Organizations User Loginname</cnsl-label>
|
||||
|
||||
<input matInput *ngIf="singleOutput" type="text" placeholder="Search for the user loginname" #usernameInput
|
||||
<input cnslInput *ngIf="singleOutput" type="text" placeholder="Search for the user loginname" #usernameInput
|
||||
[formControl]="myControl" [matAutocomplete]="auto" />
|
||||
|
||||
<mat-chip-list *ngIf="!singleOutput" #chipList aria-label="loginname selection">
|
||||
@@ -13,8 +13,8 @@
|
||||
{{selecteduser.preferredLoginName}}</small>
|
||||
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input placeholder="{{'ORG_DETAIL.MEMBER.LOGINNAME' | translate}}" #usernameInput [formControl]="myControl"
|
||||
[matAutocomplete]="auto" [matChipInputFor]="chipList"
|
||||
<input cnslInput placeholder="{{'ORG_DETAIL.MEMBER.LOGINNAME' | translate}}" #usernameInput
|
||||
[formControl]="myControl" [matAutocomplete]="auto" [matChipInputFor]="chipList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
|
||||
(matChipInputTokenEnd)="add($event)" />
|
||||
</mat-chip-list>
|
||||
@@ -29,21 +29,21 @@
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
|
||||
<mat-hint class="target-desc">
|
||||
<span class="target-desc">
|
||||
{{'USER.TARGET.SELF'| translate}}
|
||||
<a (click)="changeTarget()">{{'USER.TARGET.CLICKHERE' | translate}}</a>
|
||||
</mat-hint>
|
||||
</mat-form-field>
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
|
||||
<div *ngIf="target && target == UserTarget.EXTERNAL" class="line">
|
||||
<mat-form-field class="form-field" appearance="outline">
|
||||
<mat-label>Global User Loginname</mat-label>
|
||||
<input matInput type="text" [formControl]="globalLoginNameControl" />
|
||||
<mat-hint class="target-desc">
|
||||
<cnsl-form-field class="form-field" appearance="outline">
|
||||
<cnsl-label>Global User Loginname</cnsl-label>
|
||||
<input cnslInput type="text" [formControl]="globalLoginNameControl" />
|
||||
<span class="target-desc">
|
||||
{{(target == UserTarget.SELF ? 'USER.TARGET.SELF' : 'USER.TARGET.EXTERNAL') | translate}}
|
||||
<a (click)="changeTarget()">{{'USER.TARGET.CLICKHERE' | translate}}</a>
|
||||
</mat-hint>
|
||||
</mat-form-field>
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
|
||||
<button color="primary" mat-icon-button (click)="getGlobalUser()">
|
||||
<i class="las la-search"></i>
|
||||
|
||||
+7
-1
@@ -2,7 +2,13 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.more-space {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.target-desc {
|
||||
font-size: 14px;
|
||||
|
||||
a {
|
||||
color: #4072b4;
|
||||
|
||||
@@ -23,7 +29,7 @@
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 1rem;
|
||||
margin-top: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,13 @@ 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 { MatInputModule } from '@angular/material/input';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { AvatarModule } from '../avatar/avatar.module';
|
||||
import { InputModule } from '../input/input.module';
|
||||
import { SearchUserAutocompleteComponent } from './search-user-autocomplete.component';
|
||||
|
||||
|
||||
@@ -22,8 +21,7 @@ import { SearchUserAutocompleteComponent } from './search-user-autocomplete.comp
|
||||
MatAutocompleteModule,
|
||||
MatChipsModule,
|
||||
MatButtonModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
InputModule,
|
||||
MatIconModule,
|
||||
ReactiveFormsModule,
|
||||
MatProgressSpinnerModule,
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<app-refresh-table [loading]="dataSource?.loading$ | async" (refreshed)="changePage()"
|
||||
[emitRefreshOnPreviousRoutes]="refreshOnPreviousRoutes" [timestamp]="dataSource?.viewTimestamp"
|
||||
[dataSize]="dataSource?.totalResult" [selection]="selection">
|
||||
<mat-form-field @appearfade *ngIf="userGrantSearchKey != undefined" actions class="filtername">
|
||||
<mat-label>{{'USER.PAGES.FILTER' | translate}}</mat-label>
|
||||
<input matInput (keyup)="applyFilter($event)"
|
||||
<cnsl-form-field @appearfade *ngIf="userGrantSearchKey != undefined" actions class="filtername">
|
||||
<input cnslInput (keyup)="applyFilter($event)"
|
||||
[placeholder]="('USER.TABLE.FILTER.' + userGrantSearchKey.toString()) | translate" #input>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
<button color="warn" matTooltip="{{'GRANTS.DELETE' | translate}}" class="icon-button" mat-icon-button actions
|
||||
(click)="deleteGrantSelection()" *ngIf="selection.hasValue() && disableDelete == false">
|
||||
@@ -65,25 +64,27 @@
|
||||
{{grant.projectName}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="creationDate">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.CREATIONDATE' | translate }} </th>
|
||||
<ng-container matColumnDef="dates">
|
||||
<th mat-header-cell *matHeaderCellDef> DATES </th>
|
||||
<td mat-cell *matCellDef="let grant">
|
||||
{{grant.creationDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="changeDate">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.CHANGEDATE' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let grant">
|
||||
{{grant.changeDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }} </td>
|
||||
<div class="date-block">
|
||||
<span class="date-sub">{{ 'PROJECT.GRANT.CREATIONDATE' | translate }}:</span>
|
||||
<span>{{grant.creationDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }}</span>
|
||||
</div>
|
||||
<div class="date-block">
|
||||
<span class="date-sub">{{ 'PROJECT.GRANT.CHANGEDATE' | translate }}</span>
|
||||
<span>{{grant.changeDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }}</span>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="roleNamesList">
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
<th mat-header-cell *matHeaderCellDef class="role-data">
|
||||
{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}
|
||||
<template [ngTemplateOutlet]="templateRef"
|
||||
[ngTemplateOutletContext]="{key: UserGrantSearchKey.USERGRANTSEARCHKEY_ROLE_KEY}"></template>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let grant; let i = index">
|
||||
<td mat-cell *matCellDef="let grant; let i = index" class="role-data">
|
||||
<ng-container
|
||||
*ngIf="(context === UserGrantContext.USER || context === UserGrantContext.NONE) && (grant.grantId && grantToEdit !== grant.id) || (grantToEdit !== grant.id)">
|
||||
<div class="flex-row">
|
||||
@@ -101,41 +102,45 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngIf="(context === UserGrantContext.OWNED_PROJECT || context === UserGrantContext.USER || context === UserGrantContext.NONE) && grantToEdit == grant.id && loadedProjectId && loadedProjectId === grant.projectId">
|
||||
<mat-form-field class="form-field" appearance="outline">
|
||||
<mat-label>{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="grant.roleKeysList" multiple
|
||||
[disabled]="disableWrite || !((['user.grant.write$'] | hasRole | async) || ((context === UserGrantContext.OWNED_PROJECT ? ['user.grant.write:' + grant?.projectId] : context === UserGrantContext.GRANTED_PROJECT ? ['user.grant.write:' + grant?.grantId] : []) | hasRole | async))"
|
||||
(selectionChange)="updateRoles(grant, $event)">
|
||||
<mat-option *ngFor="let role of projectRoleOptions" [value]="role.key">
|
||||
{{role.key}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<button *ngIf="context === UserGrantContext.USER || context === UserGrantContext.NONE"
|
||||
mat-icon-button (click)="grantToEdit=''">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
<div class="row-form">
|
||||
<ng-container
|
||||
*ngIf="(context === UserGrantContext.OWNED_PROJECT || context === UserGrantContext.USER || context === UserGrantContext.NONE) && grantToEdit == grant.id && loadedProjectId && loadedProjectId === grant.projectId">
|
||||
<cnsl-form-field class="form-field" appearance="outline">
|
||||
<!-- <cnsl-label>{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}</cnsl-label> -->
|
||||
<mat-select [(ngModel)]="grant.roleKeysList" multiple
|
||||
[disabled]="disableWrite || !((['user.grant.write$'] | hasRole | async) || ((context === UserGrantContext.OWNED_PROJECT ? ['user.grant.write:' + grant?.projectId] : context === UserGrantContext.GRANTED_PROJECT ? ['user.grant.write:' + grant?.grantId] : []) | hasRole | async))"
|
||||
(selectionChange)="updateRoles(grant, $event)">
|
||||
<mat-option *ngFor="let role of projectRoleOptions" [value]="role.key">
|
||||
{{role.key}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
<button matTooltip="{{'ACTIONS.CLOSE' | translate}}"
|
||||
*ngIf="context === UserGrantContext.USER || context === UserGrantContext.NONE"
|
||||
mat-icon-button (click)="grantToEdit=''">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngIf="(context === UserGrantContext.GRANTED_PROJECT || context === UserGrantContext.USER || context === UserGrantContext.NONE) && loadedGrantId && loadedGrantId === grant.grantId && grantToEdit == grant.id">
|
||||
<mat-form-field class="form-field" appearance="outline">
|
||||
<mat-label>{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="grant.roleKeysList" multiple
|
||||
[disabled]="disableWrite || !((['user.grant.write$'] | hasRole | async) || ((context === UserGrantContext.OWNED_PROJECT ? ['user.grant.write:' + grant?.projectId] : context === UserGrantContext.GRANTED_PROJECT ? ['user.grant.write:' + grant?.grantId] : []) | hasRole | async))"
|
||||
(selectionChange)="updateRoles(grant, $event)">
|
||||
<mat-option *ngFor="let role of grantRoleOptions" [value]="role">
|
||||
{{role}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<button *ngIf="context === UserGrantContext.USER || context === UserGrantContext.NONE"
|
||||
mat-icon-button (click)="grantToEdit=''">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
<ng-container
|
||||
*ngIf="(context === UserGrantContext.GRANTED_PROJECT || context === UserGrantContext.USER || context === UserGrantContext.NONE) && loadedGrantId && loadedGrantId === grant.grantId && grantToEdit == grant.id">
|
||||
<cnsl-form-field class="form-field" appearance="outline">
|
||||
<!-- <cnsl-label>{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}</cnsl-label> -->
|
||||
<mat-select [(ngModel)]="grant.roleKeysList" multiple
|
||||
[disabled]="disableWrite || !((['user.grant.write$'] | hasRole | async) || ((context === UserGrantContext.OWNED_PROJECT ? ['user.grant.write:' + grant?.projectId] : context === UserGrantContext.GRANTED_PROJECT ? ['user.grant.write:' + grant?.grantId] : []) | hasRole | async))"
|
||||
(selectionChange)="updateRoles(grant, $event)">
|
||||
<mat-option *ngFor="let role of grantRoleOptions" [value]="role">
|
||||
{{role}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
<button matTooltip="{{'ACTIONS.CLOSE' | translate}}"
|
||||
*ngIf="context === UserGrantContext.USER || context === UserGrantContext.NONE"
|
||||
mat-icon-button (click)="grantToEdit=''">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
@@ -144,6 +149,10 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div *ngIf="(dataSource.loading$ | async) == false && !dataSource?.totalResult" class="no-content-row">
|
||||
<i class="las la-exclamation"></i>
|
||||
<span>{{'GRANTS.EMPTY' | translate}}</span>
|
||||
</div>
|
||||
<mat-paginator class="paginator" #paginator [length]="dataSource.totalResult" [pageSize]="INITIAL_PAGE_SIZE"
|
||||
[length]="dataSource.totalResult" [pageSizeOptions]="[2, 3, 25, 50, 100, 250]" (page)="changePage($event)">
|
||||
</mat-paginator>
|
||||
@@ -152,7 +161,7 @@
|
||||
|
||||
<ng-template #templateRef let-key="key">
|
||||
<button class="search-button" mat-icon-button (click)="setFilter(key)">
|
||||
<mat-icon *ngIf="this.userGrantSearchKey != key">search</mat-icon>
|
||||
<mat-icon *ngIf="this.userGrantSearchKey == key">search_off</mat-icon>
|
||||
<mat-icon class="icon" *ngIf="this.userGrantSearchKey != key">search</mat-icon>
|
||||
<mat-icon class="icon" *ngIf="this.userGrantSearchKey == key">search_off</mat-icon>
|
||||
</button>
|
||||
</ng-template>
|
||||
@@ -23,21 +23,21 @@
|
||||
|
||||
th {
|
||||
.search-button {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
width: 30px;
|
||||
|
||||
.icon {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.search-active {
|
||||
.search-button {
|
||||
display: inline-block;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.selection {
|
||||
width: 50px;
|
||||
max-width: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,9 @@
|
||||
|
||||
button {
|
||||
margin: .5rem 0;
|
||||
display: block;
|
||||
max-width: 120px;
|
||||
box-sizing: border-box;
|
||||
|
||||
i {
|
||||
font-size: 1.2rem;
|
||||
@@ -77,10 +79,35 @@
|
||||
}
|
||||
}
|
||||
|
||||
.row-form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.form-field {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.role-data {
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.date-block {
|
||||
margin: .5rem 0;
|
||||
display: block;
|
||||
min-width: 120px;
|
||||
|
||||
.date-sub {
|
||||
font-size: 13px;
|
||||
color: var(--grey);
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.filtername {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
||||
@Input() public displayedColumns: string[] = ['select',
|
||||
'user',
|
||||
'org',
|
||||
'projectId', 'creationDate', 'changeDate', 'roleNamesList'];
|
||||
'projectId', 'dates', 'roleNamesList'];
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.dataSource = new UserGrantsDataSource(this.userService);
|
||||
|
||||
@@ -3,9 +3,7 @@ import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
@@ -18,12 +16,12 @@ import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.mod
|
||||
import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module';
|
||||
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
|
||||
|
||||
import { InputModule } from '../../modules/input/input.module';
|
||||
import { AvatarModule } from '../avatar/avatar.module';
|
||||
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
||||
import { UserGrantsComponent } from './user-grants.component';
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [UserGrantsComponent],
|
||||
imports: [
|
||||
@@ -40,13 +38,12 @@ import { UserGrantsComponent } from './user-grants.component';
|
||||
MatCheckboxModule,
|
||||
MatTooltipModule,
|
||||
MatSelectModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
TranslateModule,
|
||||
HasRolePipeModule,
|
||||
TimestampToDatePipeModule,
|
||||
RefreshTableModule,
|
||||
LocalizedDatePipeModule,
|
||||
InputModule,
|
||||
],
|
||||
exports: [
|
||||
UserGrantsComponent,
|
||||
|
||||
Reference in New Issue
Block a user