mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-12 02:54:20 +00:00
Merge remote-tracking branch 'origin/master' into new-eventstore
This commit is contained in:
commit
3bd4d3a8e3
@ -12,7 +12,7 @@
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"prefix": "cnsl",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
|
1793
console/package-lock.json
generated
1793
console/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -30,8 +30,8 @@
|
||||
"angular-oauth2-oidc": "^10.0.3",
|
||||
"angularx-qrcode": "^10.0.11",
|
||||
"cors": "^2.8.5",
|
||||
"file-saver": "^2.0.2",
|
||||
"google-proto-files": "^2.2.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"google-proto-files": "^2.3.0",
|
||||
"google-protobuf": "^3.13.0",
|
||||
"grpc": "^1.24.3",
|
||||
"grpc-web": "^1.2.1",
|
||||
@ -44,24 +44,24 @@
|
||||
"zone.js": "~0.11.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.1100.1",
|
||||
"@angular/cli": "~11.0.1",
|
||||
"@angular-devkit/build-angular": "~0.1100.2",
|
||||
"@angular/cli": "~11.0.2",
|
||||
"@angular/compiler-cli": "~11.0.0",
|
||||
"@angular/language-service": "~11.0.0",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@types/jasmine": "~3.6.2",
|
||||
"@angular/language-service": "~11.0.2",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "^14.14.6",
|
||||
"@types/node": "^14.14.9",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jasmine-core": "~3.6.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"jasmine-spec-reporter": "~6.0.0",
|
||||
"karma": "~5.2.3",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"prettier": "^2.1.2",
|
||||
"prettier": "^2.2.0",
|
||||
"protractor": "~7.0.0",
|
||||
"stylelint": "^13.7.2",
|
||||
"stylelint": "^13.8.0",
|
||||
"stylelint-config-standard": "^20.0.0",
|
||||
"stylelint-scss": "^3.18.0",
|
||||
"ts-node": "~9.0.0",
|
||||
|
@ -27,6 +27,23 @@ export const toolbarAnimation: AnimationTriggerMetadata =
|
||||
]),
|
||||
]);
|
||||
|
||||
export const adminLineAnimation: AnimationTriggerMetadata =
|
||||
trigger('adminline', [
|
||||
transition(':enter', [
|
||||
style({
|
||||
transform: 'translateY(100%)',
|
||||
opacity: 0.5,
|
||||
}),
|
||||
animate(
|
||||
'.2s ease-out',
|
||||
style({
|
||||
transform: 'translateY(0%)',
|
||||
opacity: 1,
|
||||
}),
|
||||
),
|
||||
]),
|
||||
]);
|
||||
|
||||
export const accountCard: AnimationTriggerMetadata = trigger('accounts', [
|
||||
transition(':enter', [
|
||||
style({
|
||||
|
@ -24,10 +24,11 @@
|
||||
</mat-spinner>
|
||||
</div>
|
||||
|
||||
<mat-form-field class="filter-form" appearance="fill">
|
||||
<input matInput [formControl]="filterControl" autocomplete="off" (click)="$event.stopPropagation()"
|
||||
placeholder="{{'ORG.PAGES.FILTERPLACEHOLDER' | translate}}" #input>
|
||||
</mat-form-field>
|
||||
<div class="filter-wrapper">
|
||||
<input cnslInput class="filter-input" [formControl]="filterControl" autocomplete="off"
|
||||
(click)="$event.stopPropagation()" placeholder="{{'ORG.PAGES.FILTERPLACEHOLDER' | translate}}"
|
||||
#input>
|
||||
</div>
|
||||
|
||||
<div class="org-wrapper">
|
||||
<button [ngClass]="{'active': temporg.id === org?.id}" [disabled]="!temporg.id"
|
||||
@ -64,8 +65,9 @@
|
||||
<div class="side-column">
|
||||
<div class="list">
|
||||
<ng-container *ngIf="authenticationService.authenticationChanged | async">
|
||||
<a @navitem class="nav-item" [routerLinkActive]="['active']"
|
||||
[routerLinkActiveOptions]="{ exact: true }" [routerLink]="['/users/me']">
|
||||
<a @navitem matTooltip="{{'MENU.TOOLTIP.PERSONAL' | translate}}" class="nav-item"
|
||||
[routerLinkActive]="['active']" [routerLinkActiveOptions]="{ exact: true }"
|
||||
[routerLink]="['/users/me']">
|
||||
<i class="icon las la-user-circle"></i>
|
||||
<span class="label">{{ 'MENU.PERSONAL_INFO' | translate }}</span>
|
||||
</a>
|
||||
@ -77,7 +79,8 @@
|
||||
<span>{{'MENU.ADMINSECTION' | translate}}</span>
|
||||
<div class="hiddenline"></div>
|
||||
</div>
|
||||
<a @navitem class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/iam']">
|
||||
<a @navitem matTooltip="{{'MENU.TOOLTIP.IAM' | translate}}" class="nav-item"
|
||||
[routerLinkActive]="['active']" [routerLink]="[ '/iam']">
|
||||
<i class="icon las la-gem"></i>
|
||||
<span class="label">{{'MENU.IAM' | translate}}</span>
|
||||
</a>
|
||||
@ -85,7 +88,14 @@
|
||||
|
||||
<div *ngIf="org" [@navAnimation]="org">
|
||||
<ng-template appHasRole [appHasRole]="['org.read']">
|
||||
<a @navitem class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/org']">
|
||||
<div @navitem class="divider">
|
||||
<div class="line"></div>
|
||||
<span>{{'MENU.ORGSECTION' | translate}}</span>
|
||||
<div class="hiddenline"></div>
|
||||
</div>
|
||||
|
||||
<a @navitem matTooltip="{{'MENU.TOOLTIP.ORG' | translate}}" class="nav-item"
|
||||
[routerLinkActive]="['active']" [routerLink]="[ '/org']">
|
||||
<i class="icon las la-archway"></i>
|
||||
<span
|
||||
class="label">{{org?.name ? org.name : 'MENU.ORGANIZATION' | translate}}</span>
|
||||
@ -93,13 +103,8 @@
|
||||
</ng-template>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['project.read(:[0-9]*)?']">
|
||||
<div @navitem class="divider">
|
||||
<div class="line"></div>
|
||||
<span>{{'MENU.PROJECTSSECTION' | translate}}</span>
|
||||
<div class="hiddenline"></div>
|
||||
</div>
|
||||
|
||||
<a @navitem class="nav-item" [routerLinkActive]="['active']"
|
||||
<a @navitem matTooltip="{{'MENU.TOOLTIP.SELFPROJECTS' | translate}}"
|
||||
class="nav-item indented" [routerLinkActive]="['active']"
|
||||
[routerLink]="[ '/projects']">
|
||||
<i class="icon las la-layer-group"></i>
|
||||
|
||||
@ -111,9 +116,9 @@
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a @navitem
|
||||
<a @navitem matTooltip="{{'MENU.TOOLTIP.GRANTEDPROJECTS' | translate}}"
|
||||
*ngIf="mgmtService?.grantedProjectsCount && (mgmtService?.grantedProjectsCount | async)"
|
||||
class="nav-item" [routerLinkActive]="['active']"
|
||||
class="nav-item indented" [routerLinkActive]="['active']"
|
||||
[routerLink]="[ '/granted-projects']">
|
||||
<i class="icon las la-layer-group"></i>
|
||||
<div class="c_label">
|
||||
@ -124,20 +129,15 @@
|
||||
</ng-template>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['user.read(:[0-9]*)?']">
|
||||
<div @navitem class="divider">
|
||||
<div class="line"></div>
|
||||
<span class="label">
|
||||
{{ 'MENU.USERSECTION' | translate }}</span>
|
||||
<div class="hiddenline"></div>
|
||||
</div>
|
||||
|
||||
<a @navitem class="nav-item" [routerLinkActive]="['active']"
|
||||
<a @navitem matTooltip="{{'MENU.TOOLTIP.HUMANUSERS' | translate}}"
|
||||
class="nav-item indented" [routerLinkActive]="['active']"
|
||||
[routerLink]="[ '/users/list/humans']" [routerLinkActiveOptions]="{ exact: true }">
|
||||
<i class="icon las la-user-friends"></i>
|
||||
<span class="label">{{ 'MENU.HUMANUSERS' | translate }}</span>
|
||||
</a>
|
||||
|
||||
<a @navitem class="nav-item" [routerLinkActive]="['active']"
|
||||
<a @navitem matTooltip="{{'MENU.TOOLTIP.MACHINEUSERS' | translate}}"
|
||||
class="nav-item indented" [routerLinkActive]="['active']"
|
||||
[routerLink]="[ '/users/list/machines']"
|
||||
[routerLinkActiveOptions]="{ exact: true }">
|
||||
<i class="icon las la-users-cog"></i>
|
||||
@ -146,15 +146,15 @@
|
||||
</ng-template>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['user.grant.read(:[0-9]*)?']">
|
||||
<div @navitem class="divider">
|
||||
<!-- <div @navitem class="divider">
|
||||
<div class="line"></div>
|
||||
<span class="label">
|
||||
{{ 'MENU.GRANTSECTION' | translate }}</span>
|
||||
<div class="hiddenline"></div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<a @navitem class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/grants']"
|
||||
[routerLinkActiveOptions]="{ exact: true }">
|
||||
<a @navitem class="nav-item indented" [routerLinkActive]="['active']"
|
||||
[routerLink]="[ '/grants']" [routerLinkActiveOptions]="{ exact: true }">
|
||||
<i class="icon las la-shield-alt"></i>
|
||||
<span class="label">{{ 'MENU.GRANTS' | translate }}</span>
|
||||
</a>
|
||||
@ -172,7 +172,7 @@
|
||||
</div>
|
||||
</mat-drawer-content>
|
||||
</mat-drawer-container>
|
||||
<div @toolbar *ngIf="iamuser$ | async" class="admin-line" [ngClass]="{'expanded': !hideAdminWarn}"
|
||||
<div @adminline *ngIf="iamuser$ | async" class="admin-line" [ngClass]="{'expanded': !hideAdminWarn}"
|
||||
matTooltip="IAM Administrator">
|
||||
<button [matTooltip]="!hideAdminWarn ? 'Unpin': 'Pin'" (click)="toggleAdminHide()" mat-icon-button>
|
||||
<mat-icon *ngIf="!hideAdminWarn" svgIcon="mdi_pin"></mat-icon>
|
||||
|
@ -103,17 +103,21 @@
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
padding: .2rem 1rem;
|
||||
padding: 0 1rem;
|
||||
margin-right: .5rem;
|
||||
|
||||
&.indented {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin: .5rem 1rem;
|
||||
}
|
||||
|
||||
.label {
|
||||
margin-bottom: 0;
|
||||
font-weight: 500;
|
||||
font-size: .9rem;
|
||||
font-size: 14px;
|
||||
letter-spacing: .05em;
|
||||
}
|
||||
|
||||
.c_label {
|
||||
@ -121,7 +125,8 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: .9rem;
|
||||
font-size: 14px;
|
||||
letter-spacing: .03em;
|
||||
|
||||
.count {
|
||||
font-size: 12px;
|
||||
@ -198,7 +203,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin: .5rem 0;
|
||||
margin: 5px 0;
|
||||
|
||||
span {
|
||||
border: 1px solid #81868a40;
|
||||
@ -219,7 +224,6 @@
|
||||
.hiddenline {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
// flex: 1;
|
||||
width: 4rem;
|
||||
}
|
||||
}
|
||||
@ -228,7 +232,6 @@
|
||||
.filter-form {
|
||||
margin: 0 .5rem;
|
||||
/* stylelint-disable */
|
||||
|
||||
$foreground: map-get($theme, foreground);
|
||||
color: mat-color($foreground, text) !important;
|
||||
}
|
||||
@ -245,6 +248,10 @@
|
||||
.menu {
|
||||
position: relative;
|
||||
|
||||
.filter-wrapper {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.spinner-w {
|
||||
top: 1rem;
|
||||
left: 0;
|
||||
|
@ -11,7 +11,7 @@ import { LangChangeEvent, TranslateService } from '@ngx-translate/core';
|
||||
import { BehaviorSubject, from, Observable, of, Subscription } from 'rxjs';
|
||||
import { catchError, debounceTime, finalize, map, take } from 'rxjs/operators';
|
||||
|
||||
import { accountCard, navAnimations, routeAnimations, toolbarAnimation } from './animations';
|
||||
import { accountCard, adminLineAnimation, navAnimations, routeAnimations, toolbarAnimation } from './animations';
|
||||
import {
|
||||
MyProjectOrgSearchKey,
|
||||
MyProjectOrgSearchQuery,
|
||||
@ -34,6 +34,7 @@ import { UpdateService } from './services/update.service';
|
||||
...navAnimations,
|
||||
accountCard,
|
||||
routeAnimations,
|
||||
adminLineAnimation,
|
||||
],
|
||||
})
|
||||
export class AppComponent implements OnDestroy {
|
||||
|
@ -8,9 +8,7 @@ import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatNativeDateModule } from '@angular/material/core';
|
||||
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 { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
@ -34,6 +32,7 @@ import { HasRoleModule } from './directives/has-role/has-role.module';
|
||||
import { OutsideClickModule } from './directives/outside-click/outside-click.module';
|
||||
import { AccountsCardModule } from './modules/accounts-card/accounts-card.module';
|
||||
import { AvatarModule } from './modules/avatar/avatar.module';
|
||||
import { InputModule } from './modules/input/input.module';
|
||||
import { WarnDialogModule } from './modules/warn-dialog/warn-dialog.module';
|
||||
import { SignedoutComponent } from './pages/signedout/signedout.component';
|
||||
import { HasRolePipeModule } from './pipes/has-role-pipe/has-role-pipe.module';
|
||||
@ -110,8 +109,7 @@ const authConfig: AuthConfig = {
|
||||
MatSidenavModule,
|
||||
MatCardModule,
|
||||
OutsideClickModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
InputModule,
|
||||
HasRolePipeModule,
|
||||
MatProgressBarModule,
|
||||
MatProgressSpinnerModule,
|
||||
|
@ -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;
|
||||
|
18
console/src/app/modules/form-field/animations.ts
Normal file
18
console/src/app/modules/form-field/animations.ts
Normal file
@ -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)'),
|
||||
]),
|
||||
]),
|
||||
};
|
20
console/src/app/modules/form-field/error.directive.ts
Normal file
20
console/src/app/modules/form-field/error.directive.ts
Normal file
@ -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() { }
|
||||
}
|
17
console/src/app/modules/form-field/form-field.component.html
Normal file
17
console/src/app/modules/form-field/form-field.component.html
Normal file
@ -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>
|
45
console/src/app/modules/form-field/form-field.component.scss
Normal file
45
console/src/app/modules/form-field/form-field.component.scss
Normal file
@ -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();
|
||||
});
|
||||
});
|
164
console/src/app/modules/form-field/form-field.component.ts
Normal file
164
console/src/app/modules/form-field/form-field.component.ts
Normal file
@ -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';
|
||||
}
|
||||
}
|
30
console/src/app/modules/form-field/form-field.module.ts
Normal file
30
console/src/app/modules/form-field/form-field.module.ts
Normal file
@ -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 { }
|
||||
|
33
console/src/app/modules/form-field/hint.directive.ts
Normal file
33
console/src/app/modules/form-field/hint.directive.ts
Normal file
@ -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,
|
||||
|
19
console/src/app/modules/input/error-options.ts
Normal file
19
console/src/app/modules/input/error-options.ts
Normal file
@ -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)));
|
||||
}
|
||||
}
|
8
console/src/app/modules/input/input.directive.spec.ts
Normal file
8
console/src/app/modules/input/input.directive.spec.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { InputDirective } from './input.directive';
|
||||
|
||||
describe('InputDirective', () => {
|
||||
it('should create an instance', () => {
|
||||
const directive = new InputDirective();
|
||||
expect(directive).toBeTruthy();
|
||||
});
|
||||
});
|
459
console/src/app/modules/input/input.directive.ts
Normal file
459
console/src/app/modules/input/input.directive.ts
Normal file
@ -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
|
||||
}
|
22
console/src/app/modules/input/input.module.ts
Normal file
22
console/src/app/modules/input/input.module.ts
Normal file
@ -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 { }
|
3
console/src/app/modules/label/label.component.html
Normal file
3
console/src/app/modules/label/label.component.html
Normal file
@ -0,0 +1,3 @@
|
||||
<span class="cnsl-label">
|
||||
<ng-content></ng-content>
|
||||
</span>
|
16
console/src/app/modules/label/label.component.scss
Normal file
16
console/src/app/modules/label/label.component.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
25
console/src/app/modules/label/label.component.spec.ts
Normal file
25
console/src/app/modules/label/label.component.spec.ts
Normal file
@ -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();
|
||||
});
|
||||
});
|
10
console/src/app/modules/label/label.component.ts
Normal file
10
console/src/app/modules/label/label.component.ts
Normal file
@ -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() { }
|
||||
}
|
20
console/src/app/modules/label/label.module.ts
Normal file
20
console/src/app/modules/label/label.module.ts
Normal file
@ -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,
|
||||
|
@ -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()">
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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,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,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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>
|
@ -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,
|
||||
|
@ -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>
|
@ -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,
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -1,9 +1,9 @@
|
||||
<div class="max-width-container">
|
||||
<h2>{{ 'GRANTS.TITLE' | translate }}</h2>
|
||||
<h1>{{ 'GRANTS.TITLE' | translate }}</h1>
|
||||
<p class="desc">{{'GRANTS.DESC' | translate }}</p>
|
||||
<app-user-grants
|
||||
[displayedColumns]="['select', 'user', 'org', 'projectId', 'creationDate', 'changeDate', 'roleNamesList']"
|
||||
<app-user-grants [displayedColumns]="['select', 'user', 'org', 'projectId', 'dates', 'roleNamesList']"
|
||||
[disableWrite]="((['user.grant.write$'] | hasRole) | async) == false"
|
||||
[disableDelete]="((['user.grant.delete$'] | hasRole) | async) == false">
|
||||
[disableDelete]="((['user.grant.delete$'] | hasRole) | async) == false"
|
||||
[refreshOnPreviousRoutes]="['/grant-create']">
|
||||
</app-user-grants>
|
||||
</div>
|
@ -1,3 +1,7 @@
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.desc {
|
||||
color: var(--grey);
|
||||
margin-bottom: 2rem;
|
||||
|
@ -19,11 +19,6 @@
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.selection {
|
||||
width: 50px;
|
||||
max-width: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,6 @@ export class IamMembersComponent {
|
||||
}
|
||||
|
||||
public removeMemberSelection(): void {
|
||||
console.log(this.selection);
|
||||
Promise.all(this.selection.map(member => {
|
||||
return this.adminService.RemoveIamMember(member.userId).then(() => {
|
||||
this.toast.showInfo('IAM.TOAST.MEMBERREMOVED', true);
|
||||
|
@ -19,11 +19,6 @@
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.selection {
|
||||
width: 50px;
|
||||
max-width: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,19 +6,18 @@ import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { CardModule } from 'src/app/modules/card/card.module';
|
||||
import { ChangesModule } from 'src/app/modules/changes/changes.module';
|
||||
import { ContributorsModule } from 'src/app/modules/contributors/contributors.module';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
|
||||
import { PolicyGridModule } from 'src/app/modules/policy-grid/policy-grid.module';
|
||||
import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.module';
|
||||
@ -46,10 +45,9 @@ import { IamComponent } from './iam.component';
|
||||
MatCheckboxModule,
|
||||
MetaLayoutModule,
|
||||
MatIconModule,
|
||||
MatTabsModule,
|
||||
MatTableModule,
|
||||
MatPaginatorModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatSortModule,
|
||||
MatTooltipModule,
|
||||
ReactiveFormsModule,
|
||||
|
@ -12,17 +12,18 @@
|
||||
|
||||
<ng-container *ngIf="!forSelf">
|
||||
<ng-container *ngIf="currentCreateStep == 1">
|
||||
<h1>{{'ORG.PAGES.ORGDETAIL_TITLE' | translate}}</h1>
|
||||
<h1>{{'ORG.PAGES.ORGDETAIL_TITLE' | translate}} </h1>
|
||||
|
||||
<form [formGroup]="orgForm" (ngSubmit)="next()">
|
||||
<div class="content">
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'ORG_DETAIL.DETAIL.NAME' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'ORG_DETAIL.DETAIL.DOMAIN' | translate }}</mat-label>
|
||||
<input matInput formControlName="domain" />
|
||||
</mat-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'ORG_DETAIL.DETAIL.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'ORG_DETAIL.DETAIL.DOMAIN' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="domain" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<div class="btn-container">
|
||||
@ -42,67 +43,67 @@
|
||||
<form [formGroup]="userForm" class="form">
|
||||
<div class="content">
|
||||
<p class="section">{{ 'USER.CREATE.NAMEANDEMAILSECTION' | translate }}</p>
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'USER.PROFILE.USERNAME' | translate }}</mat-label>
|
||||
<input matInput formControlName="userName" required />
|
||||
<mat-error *ngIf="userName?.invalid && userName?.errors?.required">
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'USER.PROFILE.USERNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="userName" required />
|
||||
<span cnsl-error *ngIf="userName?.invalid && userName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'USER.PROFILE.EMAIL' | translate }}</mat-label>
|
||||
<input matInput formControlName="email" required />
|
||||
<mat-error *ngIf="email?.invalid && email?.errors?.required">
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'USER.PROFILE.EMAIL' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="email" required />
|
||||
<span cnsl-error *ngIf="email?.invalid && email?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'USER.PROFILE.FIRSTNAME' | translate }}</mat-label>
|
||||
<input matInput formControlName="firstName" required />
|
||||
<mat-error *ngIf="firstName?.invalid && firstName?.errors?.required">
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'USER.PROFILE.FIRSTNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="firstName" required />
|
||||
<span cnsl-error *ngIf="firstName?.invalid && firstName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'USER.PROFILE.LASTNAME' | translate }}</mat-label>
|
||||
<input matInput formControlName="lastName" required />
|
||||
<mat-error *ngIf="lastName?.invalid && lastName?.errors?.required">
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'USER.PROFILE.LASTNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="lastName" required />
|
||||
<span cnsl-error *ngIf="lastName?.invalid && lastName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'USER.PROFILE.NICKNAME' | translate }}</mat-label>
|
||||
<input matInput formControlName="nickName" />
|
||||
<mat-error *ngIf="nickName?.invalid && nickName?.errors?.required">
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'USER.PROFILE.NICKNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="nickName" />
|
||||
<span cnsl-error *ngIf="nickName?.invalid && nickName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
|
||||
<p class="section">{{ 'USER.CREATE.GENDERLANGSECTION' | translate }}</p>
|
||||
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'USER.PROFILE.GENDER' | translate }}</mat-label>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'USER.PROFILE.GENDER' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="gender">
|
||||
<mat-option *ngFor="let gender of genders" [value]="gender">
|
||||
{{ 'GENDERS.'+gender | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="gender?.invalid && gender?.errors?.required">
|
||||
<span cnsl-error *ngIf="gender?.invalid && gender?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'USER.PROFILE.PREFERRED_LANGUAGE' | translate }}</mat-label>
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'USER.PROFILE.PREFERRED_LANGUAGE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="preferredLanguage">
|
||||
<mat-option *ngFor="let language of languages" [value]="language">
|
||||
{{ 'LANGUAGES.'+language | translate }}
|
||||
</mat-option>
|
||||
<mat-error
|
||||
<span cnsl-error
|
||||
*ngIf="preferredLanguage?.invalid && preferredLanguage?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</mat-error>
|
||||
</span>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox class="checkbox" [(ngModel)]="usePassword"
|
||||
[ngModelOptions]="{standalone: true}" (change)="initPwdValidators()">
|
||||
@ -116,28 +117,28 @@
|
||||
</app-password-complexity-view>
|
||||
|
||||
<form [formGroup]="pwdForm" class="form">
|
||||
<mat-form-field class="formfield" *ngIf="password" appearance="outline">
|
||||
<mat-label>{{ 'USER.PASSWORD.NEW' | translate }}</mat-label>
|
||||
<input autocomplete="off" name="firstpassword" matInput
|
||||
<cnsl-form-field class="formfield" *ngIf="password" appearance="outline">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.NEW' | translate }}</cnsl-label>
|
||||
<input cnslInput autocomplete="off" name="firstpassword"
|
||||
formControlName="password" type="password" />
|
||||
|
||||
<mat-error *ngIf="password?.errors?.required">
|
||||
<span cnsl-error *ngIf="password?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</mat-error>
|
||||
</span>
|
||||
|
||||
</mat-form-field>
|
||||
<mat-form-field class="formfield" *ngIf="confirmPassword" appearance="outline">
|
||||
<mat-label>{{ 'USER.PASSWORD.CONFIRM' | translate }}</mat-label>
|
||||
<input autocomplete="off" name="confirmPassword" matInput
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" *ngIf="confirmPassword" appearance="outline">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.CONFIRM' | translate }}</cnsl-label>
|
||||
<input cnslInput autocomplete="off" name="confirmPassword"
|
||||
formControlName="confirmPassword" type="password" />
|
||||
|
||||
<mat-error *ngIf="confirmPassword?.errors?.required">
|
||||
<span cnsl-error *ngIf="confirmPassword?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="confirmPassword?.errors?.notequal">
|
||||
</span>
|
||||
<span cnsl-error *ngIf="confirmPassword?.errors?.notequal">
|
||||
{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</form>
|
||||
</ng-container>
|
||||
</div>
|
||||
@ -157,13 +158,14 @@
|
||||
<ng-template appHasRole [appHasRole]="['org.create']">
|
||||
<div *ngIf="forSelf">
|
||||
<ng-container *ngIf="currentCreateStep == 1">
|
||||
<h1>{{'ORG.PAGES.ORGDETAIL_TITLE' | translate}}</h1>
|
||||
<h1>{{'ORG.PAGES.ORGDETAIL_TITLE_WITHOUT_DOMAIN' | translate}} </h1>
|
||||
|
||||
<form [formGroup]="orgForm" (ngSubmit)="createOrgForSelf()">
|
||||
<div class="content">
|
||||
<mat-form-field class="formfield" appearance="outline">
|
||||
<mat-label>{{ 'ORG_DETAIL.DETAIL.NAME' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" />
|
||||
</mat-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'ORG_DETAIL.DETAIL.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<div class="btn-container">
|
||||
|
@ -107,8 +107,15 @@ export class OrgCreateComponent {
|
||||
|
||||
this.adminService
|
||||
.SetUpOrg(createOrgRequest, humanRequest)
|
||||
.then((data: OrgSetUpResponse) => {
|
||||
this.router.navigate(['orgs', data.toObject().org?.id]);
|
||||
.then((org: OrgSetUpResponse) => {
|
||||
this.router.navigate(['/org/overview']);
|
||||
// const orgResp = org.getOrg();
|
||||
// if (orgResp) {
|
||||
// this.authService.setActiveOrg(orgResp.toObject());
|
||||
// this.router.navigate(['/org']);
|
||||
// } else {
|
||||
// this.router.navigate(['/org', 'overview']);
|
||||
// }
|
||||
})
|
||||
.catch(error => {
|
||||
this.toast.showError(error);
|
||||
@ -193,7 +200,12 @@ export class OrgCreateComponent {
|
||||
public createOrgForSelf(): void {
|
||||
if (this.name && this.name.value) {
|
||||
this.mgmtService.CreateOrg(this.name.value).then((org) => {
|
||||
this.router.navigate(['orgs', org.toObject().id]);
|
||||
this.router.navigate(['/org/overview']);
|
||||
// const newOrg = org.toObject();
|
||||
// setTimeout(() => {
|
||||
// this.authService.setActiveOrg(newOrg);
|
||||
// this.router.navigate(['/org']);
|
||||
// }, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
|
@ -3,13 +3,12 @@ import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } 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 { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
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 { PasswordComplexityViewModule } from 'src/app/modules/password-complexity-view/password-complexity-view.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
@ -23,8 +22,7 @@ import { OrgCreateComponent } from './org-create.component';
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatSelectModule,
|
||||
|
@ -2,10 +2,10 @@
|
||||
<div mat-dialog-content>
|
||||
<p class="desc"> {{'ORG.DOMAINS.ADD.DESCRIPTION' | translate}}</p>
|
||||
|
||||
<mat-form-field label="Domain" required="true" class="form-field" appearance="outline">
|
||||
<mat-label>Domain</mat-label>
|
||||
<input matInput [(ngModel)]="newdomain" />
|
||||
</mat-form-field>
|
||||
<cnsl-form-field label="Domain" required="true" class="form-field" appearance="outline">
|
||||
<cnsl-label>Domain</cnsl-label>
|
||||
<input cnslInput [(ngModel)]="newdomain" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button mat-button (click)="closeDialog()">
|
||||
|
@ -2,9 +2,8 @@ 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 { MatInputModule } from '@angular/material/input';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { AddDomainDialogComponent } from './add-domain-dialog.component';
|
||||
|
||||
@ -14,8 +13,7 @@ import { AddDomainDialogComponent } from './add-domain-dialog.component';
|
||||
CommonModule,
|
||||
TranslateModule,
|
||||
MatButtonModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
InputModule,
|
||||
FormsModule,
|
||||
],
|
||||
})
|
||||
|
@ -38,7 +38,6 @@
|
||||
color="primary">{{ 'ORG.PAGES.DOWNLOAD_FILE' | translate }}</button>
|
||||
<button color="primary" class="verify-button" type="submit" mat-raised-button (click)="validate()">
|
||||
<span>{{ 'ACTIONS.VERIFY' | translate }}</span>
|
||||
<mat-spinner class="spinner" *ngIf="!validating" diameter="20" mode="indeterminate"></mat-spinner>
|
||||
</button>
|
||||
<mat-spinner class="spinner" *ngIf="validating" diameter="20" mode="indeterminate"></mat-spinner>
|
||||
</div>
|
||||
|
@ -10,7 +10,6 @@
|
||||
.domain {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .5rem 0;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.title {
|
||||
@ -55,6 +54,7 @@
|
||||
&:hover {
|
||||
.rem-button {
|
||||
visibility: visible;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,11 @@
|
||||
<app-refresh-table *ngIf="dataSource" (refreshed)="refresh()" [dataSize]="dataSource.data.length"
|
||||
[loading]="loading$ | async">
|
||||
|
||||
<mat-form-field @appearfade *ngIf="orgSearchKey != undefined" actions class="filter">
|
||||
<mat-label>{{'ORG.PAGES.FILTER' | translate}}</mat-label>
|
||||
<input matInput (keyup)="applyFilter($event)" placeholder="{{'ORG.PAGES.FILTERPLACEHOLDER' | translate}}"
|
||||
<cnsl-form-field @appearfade *ngIf="orgSearchKey != undefined" actions class="filter">
|
||||
<cnsl-label>{{'ORG.PAGES.FILTER' | translate}}</cnsl-label>
|
||||
<input cnslInput (keyup)="applyFilter($event)" placeholder="{{'ORG.PAGES.FILTERPLACEHOLDER' | translate}}"
|
||||
#input>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
<table [dataSource]="dataSource" mat-table class="table" matSort aria-label="Elements">
|
||||
|
||||
|
@ -23,11 +23,6 @@ h1 {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.selection {
|
||||
width: 50px;
|
||||
max-width: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.pointer {
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { AfterViewInit, Component, ViewChild } from '@angular/core';
|
||||
import { MatInput } from '@angular/material/input';
|
||||
import { AfterViewInit, Component, Input, ViewChild } from '@angular/core';
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
@ -23,7 +22,7 @@ export class OrgListComponent implements AfterViewInit {
|
||||
|
||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
||||
@ViewChild(MatSort) sort!: MatSort;
|
||||
@ViewChild('input') public filter!: MatInput;
|
||||
@ViewChild('input') public filter!: Input;
|
||||
|
||||
public dataSource!: MatTableDataSource<Org.AsObject>;
|
||||
public displayedColumns: string[] = ['select', 'id', 'name'];
|
||||
|
@ -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 { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatRadioModule } from '@angular/material/radio';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.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';
|
||||
@ -34,8 +33,7 @@ import { OrgListComponent } from './org-list.component';
|
||||
MatButtonModule,
|
||||
MatTooltipModule,
|
||||
MatRadioModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
InputModule,
|
||||
FormsModule,
|
||||
],
|
||||
})
|
||||
|
@ -1,6 +1,6 @@
|
||||
<form>
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Role Name</mat-label>
|
||||
<cnsl-form-field appearance="outline" class="full-width">
|
||||
<cnsl-label>Role Name</cnsl-label>
|
||||
|
||||
<mat-select [formControl]="myControl" multiple>
|
||||
<mat-option *ngIf="isLoading" class="is-loading">
|
||||
@ -10,5 +10,5 @@
|
||||
{{ role }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
</form>
|
@ -2,12 +2,11 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } 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 { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { OrgMemberRolesAutocompleteComponent } from './org-member-roles-autocomplete.component';
|
||||
|
||||
@ -17,9 +16,8 @@ import { OrgMemberRolesAutocompleteComponent } from './org-member-roles-autocomp
|
||||
CommonModule,
|
||||
MatButtonModule,
|
||||
MatSelectModule,
|
||||
MatFormFieldModule,
|
||||
InputModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
ReactiveFormsModule,
|
||||
MatProgressSpinnerModule,
|
||||
FormsModule,
|
||||
|
@ -4,9 +4,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
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 { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
@ -17,6 +15,7 @@ import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { MemberCreateDialogModule } from 'src/app/modules/add-member-dialog/member-create-dialog.module';
|
||||
import { CardModule } from 'src/app/modules/card/card.module';
|
||||
import { ContributorsModule } from 'src/app/modules/contributors/contributors.module';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
|
||||
import { PolicyGridModule } from 'src/app/modules/policy-grid/policy-grid.module';
|
||||
import { SharedModule } from 'src/app/modules/shared/shared.module';
|
||||
@ -37,8 +36,7 @@ import { OrgsRoutingModule } from './orgs-routing.module';
|
||||
OrgsRoutingModule,
|
||||
FormsModule,
|
||||
HasRoleModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
MatDialogModule,
|
||||
CardModule,
|
||||
|
@ -21,18 +21,18 @@
|
||||
<ng-template matStepLabel>{{'APP.OIDC.NAMEANDTYPESECTION' | translate}}</ng-template>
|
||||
|
||||
<p class="step-title">{{'APP.OIDC.TITLEFIRST' | translate}}</p>
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'APP.NAME' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" />
|
||||
<mat-error *ngIf="name?.errors?.required">{{'PROJECT.APP.NAMEREQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
<span cnsl-error *ngIf="name?.errors?.required">{{'PROJECT.APP.NAMEREQUIRED' | translate}}</span>
|
||||
</cnsl-form-field>
|
||||
|
||||
<p class="step-title">{{'APP.OIDC.TYPETITLE' | translate}}</p>
|
||||
<mat-radio-group color="primary" aria-labelledby="radio-group-label" class="radio-group"
|
||||
formControlName="applicationType">
|
||||
<mat-radio-button class="radio-button" *ngFor="let type of oidcAppTypes | keyvalue"
|
||||
[value]="type.value">
|
||||
<div>{{'APP.OIDC.APPTYPE'+type.key | translate}}</div>
|
||||
<div>{{('APP.OIDC.APPTYPE'+type.key.toString()) | translate}}</div>
|
||||
</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
<div class="actions">
|
||||
@ -89,19 +89,24 @@
|
||||
<p class="step-description" *ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB">
|
||||
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p>
|
||||
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>{{ 'APP.OIDC.REDIRECT' | translate }}</mat-label>
|
||||
<mat-chip-list #chipRedirectList aria-label="uri selection">
|
||||
<mat-chip class="chip" *ngFor="let uri of oidcApp.redirectUrisList" selected removable
|
||||
[matTooltip]="!uri.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
||||
[color]="!uri.startsWith('https://') ? 'warn': 'white'" (removed)="removeUri(uri, 'REDIRECT')">
|
||||
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input [matChipInputFor]="chipRedirectList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="true" [formControl]="redirectControl"
|
||||
(matChipInputTokenEnd)="addUri($event, 'REDIRECT')">
|
||||
</mat-chip-list>
|
||||
</mat-form-field>
|
||||
<form class="chip-form" (ngSubmit)="addUri(redInput, 'REDIRECT')">
|
||||
<cnsl-form-field appearance="outline" class="full-width">
|
||||
<cnsl-label>{{ 'APP.OIDC.REDIRECT' | translate }}</cnsl-label>
|
||||
<input #redInput cnslInput placeholder="{{'APP.OIDC.COMMAORENTERSEPERATION' | translate}}"
|
||||
[formControl]="redirectControl">
|
||||
</cnsl-form-field>
|
||||
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</form>
|
||||
<mat-chip-list #chipRedirectList aria-label="uri selection">
|
||||
<mat-chip #redInput class="chip" *ngFor="let uri of oidcApp.redirectUrisList" selected removable
|
||||
[matTooltip]="!uri?.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
||||
[color]="!uri?.startsWith('https://') ? 'warn': 'white'" (removed)="removeUri(uri, 'REDIRECT')">
|
||||
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
|
||||
<p *ngIf="redirectControl.invalid" class="error">{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>
|
||||
|
||||
<p class="step-title">{{'APP.OIDC.POSTREDIRECTTITLE' | translate}}</p>
|
||||
@ -112,20 +117,25 @@
|
||||
*ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB || oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT">
|
||||
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p>
|
||||
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</mat-label>
|
||||
<mat-chip-list #chipPostRedirectList aria-label="uri selection">
|
||||
<mat-chip class="chip" *ngFor="let uri of oidcApp.postLogoutRedirectUrisList"
|
||||
[matTooltip]="!uri.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
||||
removable (removed)="removeUri(uri, 'POSTREDIRECT')" selected
|
||||
[color]="!uri.startsWith('https://') ? 'warn': 'white'">
|
||||
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input [matChipInputFor]="chipPostRedirectList" [formControl]="postRedirectControl"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addUri($event, 'POSTREDIRECT')">
|
||||
</mat-chip-list>
|
||||
</mat-form-field>
|
||||
<form class="chip-form" (ngSubmit)="addUri(postInput, 'POSTREDIRECT')">
|
||||
<cnsl-form-field appearance="outline" class="full-width">
|
||||
<cnsl-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</cnsl-label>
|
||||
<input #postInput cnslInput placeholder="{{'APP.OIDC.COMMAORENTERSEPERATION' | translate}}"
|
||||
[formControl]="postRedirectControl">
|
||||
</cnsl-form-field>
|
||||
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</form>
|
||||
<mat-chip-list #chipPostRedirectList aria-label="uri selection">
|
||||
<mat-chip class="chip" *ngFor="let uri of oidcApp.postLogoutRedirectUrisList"
|
||||
[matTooltip]="!uri?.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
||||
removable (removed)="removeUri(uri, 'POSTREDIRECT')" selected
|
||||
[color]="!uri?.startsWith('https://') ? 'warn': 'white'">
|
||||
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
|
||||
<p *ngIf="postRedirectControl.invalid" class="error">{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>
|
||||
|
||||
<div class="actions">
|
||||
@ -223,71 +233,72 @@
|
||||
<div *ngIf="devmode" class="dev">
|
||||
<form [formGroup]="form" (ngSubmit)="saveOIDCApp()">
|
||||
<div class="content">
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'APP.NAME' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" />
|
||||
</mat-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'APP.OIDC.APPTYPE' | translate }}</mat-label>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.OIDC.APPTYPE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="applicationType">
|
||||
<mat-option *ngFor="let type of oidcAppTypes" [value]="type">
|
||||
{{ 'APP.OIDC.APPTYPE'+type | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'APP.OIDC.GRANT' | translate }}</mat-label>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.OIDC.GRANT' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="grantTypesList" multiple>
|
||||
<mat-option *ngFor="let grant of oidcGrantTypes" [value]="grant.type">
|
||||
{{ ('APP.OIDC.GRANT' + grant.type) | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'APP.OIDC.RESPONSE' | translate }}</mat-label>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.OIDC.RESPONSE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="responseTypesList" multiple>
|
||||
<mat-option *ngFor="let type of oidcResponseTypes" [value]="type.type">
|
||||
{{ 'APP.OIDC.RESPONSE'+type.type | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'APP.OIDC.AUTHMETHOD' | translate }}</mat-label>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.OIDC.AUTHMETHOD' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="authMethodType">
|
||||
<mat-option *ngFor="let type of oidcAuthMethodType" [value]="type.type">
|
||||
{{ 'APP.OIDC.AUTHMETHOD'+type.type | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="formfield full-width">
|
||||
<mat-label>{{ 'APP.OIDC.REDIRECT' | translate }}</mat-label>
|
||||
<cnsl-form-field appearance="outline" class="formfield full-width">
|
||||
<cnsl-label>{{ 'APP.OIDC.REDIRECT' | translate }}</cnsl-label>
|
||||
<mat-chip-list #chipRedirectList aria-label="uri selection">
|
||||
<mat-chip class="chip" *ngFor="let uri of oidcApp.redirectUrisList" removable
|
||||
(removed)="removeUri(uri, 'REDIRECT')">
|
||||
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input [matChipInputFor]="chipRedirectList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="true" (matChipInputTokenEnd)="addUri($event, 'REDIRECT')">
|
||||
<input cnslInput [matChipInputFor]="chipRedirectList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addUri($event, 'REDIRECT')">
|
||||
</mat-chip-list>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="formfield full-width">
|
||||
<mat-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</mat-label>
|
||||
<cnsl-form-field appearance="outline" class="formfield full-width">
|
||||
<cnsl-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</cnsl-label>
|
||||
<mat-chip-list #chipPostRedirectList aria-label="uri selection">
|
||||
<mat-chip class="chip" *ngFor="let uri of oidcApp.postLogoutRedirectUrisList" removable
|
||||
(removed)="removeUri(uri, 'POSTREDIRECT')">
|
||||
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input [matChipInputFor]="chipPostRedirectList"
|
||||
<input cnslInput [matChipInputFor]="chipPostRedirectList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addUri($event, 'POSTREDIRECT')">
|
||||
</mat-chip-list>
|
||||
</mat-form-field>
|
||||
</cnsl-form-field>
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -56,8 +56,9 @@ p.desc {
|
||||
margin: 0 -1.5rem;
|
||||
|
||||
.step-title {
|
||||
font-size: 1.2rem;
|
||||
color: var(--grey);
|
||||
font-size: 1rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .05em;
|
||||
}
|
||||
|
||||
.step-description {
|
||||
@ -65,12 +66,31 @@ p.desc {
|
||||
color: var(--grey);
|
||||
}
|
||||
|
||||
.chip-form {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.formfield {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
font-size: 13px;
|
||||
color: #f44336;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.chip {
|
||||
border-radius: 4px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.chip[color='white'] {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user