mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:37:23 +00:00
feat(console-v2): save table filters as queryparams, smtp update (#3624)
* show warn for missing smtp * org table, failed events, views table fallback, org table filters * log notification providers, user filter, copy to clip fix * lint Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
parent
a674f99c2d
commit
d0c1ad2c69
94
console/package-lock.json
generated
94
console/package-lock.json
generated
@ -28,6 +28,7 @@
|
|||||||
"@types/google-protobuf": "^3.15.3",
|
"@types/google-protobuf": "^3.15.3",
|
||||||
"@types/uuid": "^8.3.0",
|
"@types/uuid": "^8.3.0",
|
||||||
"angular-oauth2-oidc": "^13.0.1",
|
"angular-oauth2-oidc": "^13.0.1",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
"codemirror": "^5.65.0",
|
"codemirror": "^5.65.0",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
@ -4690,7 +4691,6 @@
|
|||||||
},
|
},
|
||||||
"node_modules/base64-js": {
|
"node_modules/base64-js": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -4754,6 +4754,30 @@
|
|||||||
"readable-stream": "^3.4.0"
|
"readable-stream": "^3.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bl/node_modules/buffer": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.1.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/blob-util": {
|
"node_modules/blob-util": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -4940,8 +4964,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/buffer": {
|
"node_modules/buffer": {
|
||||||
"version": "5.7.1",
|
"version": "6.0.3",
|
||||||
"dev": true,
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -4956,10 +4981,9 @@
|
|||||||
"url": "https://feross.org/support"
|
"url": "https://feross.org/support"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"base64-js": "^1.3.1",
|
"base64-js": "^1.3.1",
|
||||||
"ieee754": "^1.1.13"
|
"ieee754": "^1.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/buffer-crc32": {
|
"node_modules/buffer-crc32": {
|
||||||
@ -6225,6 +6249,30 @@
|
|||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cypress/node_modules/buffer": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.1.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cypress/node_modules/chalk": {
|
"node_modules/cypress/node_modules/chalk": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -8696,7 +8744,6 @@
|
|||||||
},
|
},
|
||||||
"node_modules/ieee754": {
|
"node_modules/ieee754": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -19971,8 +20018,7 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"base64-js": {
|
"base64-js": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1"
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"base64id": {
|
"base64id": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@ -20004,6 +20050,18 @@
|
|||||||
"buffer": "^5.5.0",
|
"buffer": "^5.5.0",
|
||||||
"inherits": "^2.0.4",
|
"inherits": "^2.0.4",
|
||||||
"readable-stream": "^3.4.0"
|
"readable-stream": "^3.4.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"buffer": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.1.13"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"blob-util": {
|
"blob-util": {
|
||||||
@ -20138,11 +20196,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"buffer": {
|
"buffer": {
|
||||||
"version": "5.7.1",
|
"version": "6.0.3",
|
||||||
"dev": true,
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"base64-js": "^1.3.1",
|
"base64-js": "^1.3.1",
|
||||||
"ieee754": "^1.1.13"
|
"ieee754": "^1.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"buffer-crc32": {
|
"buffer-crc32": {
|
||||||
@ -20895,6 +20954,16 @@
|
|||||||
"color-convert": "^2.0.1"
|
"color-convert": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"buffer": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.1.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -22565,8 +22634,7 @@
|
|||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
"ieee754": {
|
"ieee754": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1"
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"ignore": {
|
"ignore": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
"@types/google-protobuf": "^3.15.3",
|
"@types/google-protobuf": "^3.15.3",
|
||||||
"@types/uuid": "^8.3.0",
|
"@types/uuid": "^8.3.0",
|
||||||
"angular-oauth2-oidc": "^13.0.1",
|
"angular-oauth2-oidc": "^13.0.1",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
"codemirror": "^5.65.0",
|
"codemirror": "^5.65.0",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
animate,
|
animate,
|
||||||
animateChild,
|
animateChild,
|
||||||
AnimationTriggerMetadata,
|
AnimationTriggerMetadata,
|
||||||
group,
|
group,
|
||||||
query,
|
query,
|
||||||
stagger,
|
stagger,
|
||||||
style,
|
style,
|
||||||
transition,
|
transition,
|
||||||
trigger,
|
trigger,
|
||||||
} from '@angular/animations';
|
} from '@angular/animations';
|
||||||
|
|
||||||
export const toolbarAnimation: AnimationTriggerMetadata = trigger('toolbar', [
|
export const toolbarAnimation: AnimationTriggerMetadata = trigger('toolbar', [
|
||||||
@ -121,10 +121,10 @@ export const enterAnimations: Array<AnimationTriggerMetadata> = [
|
|||||||
|
|
||||||
export const routeAnimations: AnimationTriggerMetadata = trigger('routeAnimations', [
|
export const routeAnimations: AnimationTriggerMetadata = trigger('routeAnimations', [
|
||||||
transition('HomePage => AddPage', [
|
transition('HomePage => AddPage', [
|
||||||
style({ transform: 'translateX(50%)', opacity: 0.5 }),
|
style({ transform: 'translateX(30vw)', opacity: 0 }),
|
||||||
animate('250ms ease-out', style({ transform: 'translateX(0%)', opacity: 1 })),
|
animate('250ms ease-out', style({ transform: 'translateX(0%)', opacity: 1 })),
|
||||||
]),
|
]),
|
||||||
transition('AddPage => HomePage', [animate('250ms', style({ transform: 'translateX(50%)', opacity: 0.5 }))]),
|
transition('AddPage => HomePage', [animate('250ms', style({ transform: 'translateX(30vw)', opacity: 0 }))]),
|
||||||
transition('HomePage => DetailPage', [
|
transition('HomePage => DetailPage', [
|
||||||
query(':enter, :leave', style({ position: 'absolute', left: 0, right: 0 }), {
|
query(':enter, :leave', style({ position: 'absolute', left: 0, right: 0 }), {
|
||||||
optional: true,
|
optional: true,
|
||||||
@ -135,7 +135,7 @@ export const routeAnimations: AnimationTriggerMetadata = trigger('routeAnimation
|
|||||||
[
|
[
|
||||||
style({
|
style({
|
||||||
transform: 'translateX(20%)',
|
transform: 'translateX(20%)',
|
||||||
opacity: 0.5,
|
opacity: 0,
|
||||||
}),
|
}),
|
||||||
animate(
|
animate(
|
||||||
'.35s ease-in',
|
'.35s ease-in',
|
||||||
|
@ -16,6 +16,7 @@ const routes: Routes = [
|
|||||||
{
|
{
|
||||||
path: 'orgs',
|
path: 'orgs',
|
||||||
loadChildren: () => import('./pages/org-list/org-list.module').then((m) => m.OrgListModule),
|
loadChildren: () => import('./pages/org-list/org-list.module').then((m) => m.OrgListModule),
|
||||||
|
canActivate: [AuthGuard],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'granted-projects',
|
path: 'granted-projects',
|
||||||
|
@ -163,6 +163,11 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.matIconRegistry.addSvgIcon('mdi_symbol', this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/symbol.svg'));
|
this.matIconRegistry.addSvgIcon('mdi_symbol', this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/symbol.svg'));
|
||||||
|
|
||||||
|
this.matIconRegistry.addSvgIcon(
|
||||||
|
'mdi_shield_alert',
|
||||||
|
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/shield-alert.svg'),
|
||||||
|
);
|
||||||
|
|
||||||
this.matIconRegistry.addSvgIcon(
|
this.matIconRegistry.addSvgIcon(
|
||||||
'mdi_numeric',
|
'mdi_numeric',
|
||||||
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/numeric.svg'),
|
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/numeric.svg'),
|
||||||
@ -349,7 +354,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
public changedOrg(org: Org.AsObject): void {
|
public changedOrg(org: Org.AsObject): void {
|
||||||
this.loadPrivateLabelling();
|
this.loadPrivateLabelling();
|
||||||
this.authService.zitadelPermissionsChanged.pipe(take(1)).subscribe(() => {
|
this.authService.zitadelPermissionsChanged.pipe(take(1)).subscribe(() => {
|
||||||
this.router.navigate(['/org'],{fragment: org.id} );
|
this.router.navigate(['/org'], { fragment: org.id });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ export class CopyToClipboardDirective {
|
|||||||
|
|
||||||
@HostListener('click', ['$event']) onMouseEnter($event: any): void {
|
@HostListener('click', ['$event']) onMouseEnter($event: any): void {
|
||||||
$event.preventDefault();
|
$event.preventDefault();
|
||||||
|
$event.stopPropagation();
|
||||||
this.copytoclipboard(this.valueToCopy);
|
this.copytoclipboard(this.valueToCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { FilterUserComponent } from './filter-user.component';
|
import { FilterOrgComponent } from './filter-org.component';
|
||||||
|
|
||||||
describe('FilterUserComponent', () => {
|
describe('FilterOrgComponent', () => {
|
||||||
let component: FilterUserComponent;
|
let component: FilterOrgComponent;
|
||||||
let fixture: ComponentFixture<FilterUserComponent>;
|
let fixture: ComponentFixture<FilterOrgComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ FilterUserComponent ]
|
declarations: [FilterOrgComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(FilterUserComponent);
|
fixture = TestBed.createComponent(FilterOrgComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { MatCheckboxChange } from '@angular/material/checkbox';
|
import { MatCheckboxChange } from '@angular/material/checkbox';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { take } from 'rxjs';
|
||||||
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
|
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
|
||||||
import { OrgNameQuery, OrgQuery, OrgState } from 'src/app/proto/generated/zitadel/org_pb';
|
import { OrgNameQuery, OrgQuery, OrgState } from 'src/app/proto/generated/zitadel/org_pb';
|
||||||
import { UserNameQuery } from 'src/app/proto/generated/zitadel/user_pb';
|
import { UserNameQuery } from 'src/app/proto/generated/zitadel/user_pb';
|
||||||
@ -15,13 +17,44 @@ enum SubQuery {
|
|||||||
templateUrl: './filter-org.component.html',
|
templateUrl: './filter-org.component.html',
|
||||||
styleUrls: ['./filter-org.component.scss'],
|
styleUrls: ['./filter-org.component.scss'],
|
||||||
})
|
})
|
||||||
export class FilterOrgComponent extends FilterComponent {
|
export class FilterOrgComponent extends FilterComponent implements OnInit {
|
||||||
public SubQuery: any = SubQuery;
|
public SubQuery: any = SubQuery;
|
||||||
public searchQueries: OrgQuery[] = [];
|
public searchQueries: OrgQuery[] = [];
|
||||||
|
|
||||||
public states: OrgState[] = [OrgState.ORG_STATE_ACTIVE, OrgState.ORG_STATE_INACTIVE];
|
public states: OrgState[] = [OrgState.ORG_STATE_ACTIVE, OrgState.ORG_STATE_INACTIVE];
|
||||||
constructor() {
|
|
||||||
super();
|
constructor(router: Router, protected route: ActivatedRoute) {
|
||||||
|
super(router, route);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.route.queryParams.pipe(take(1)).subscribe((params) => {
|
||||||
|
const { filter } = params;
|
||||||
|
if (filter) {
|
||||||
|
const stringifiedFilters = filter as string;
|
||||||
|
const filters: OrgQuery.AsObject[] = JSON.parse(stringifiedFilters) as OrgQuery.AsObject[];
|
||||||
|
|
||||||
|
const orgQueries = filters.map((filter) => {
|
||||||
|
if (filter.nameQuery) {
|
||||||
|
const orgQuery = new OrgQuery();
|
||||||
|
|
||||||
|
const orgNameQuery = new OrgNameQuery();
|
||||||
|
orgNameQuery.setName(filter.nameQuery.name);
|
||||||
|
orgNameQuery.setMethod(filter.nameQuery.method);
|
||||||
|
|
||||||
|
orgQuery.setNameQuery(orgNameQuery);
|
||||||
|
return orgQuery;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.searchQueries = orgQueries.filter((q) => q !== undefined) as OrgQuery[];
|
||||||
|
this.filterChanged.emit(this.filterCount ? this.searchQueries : undefined);
|
||||||
|
// this.showFilter = true;
|
||||||
|
// this.filterOpen.emit(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public changeCheckbox(subquery: SubQuery, event: MatCheckboxChange) {
|
public changeCheckbox(subquery: SubQuery, event: MatCheckboxChange) {
|
||||||
|
@ -4,6 +4,7 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
import { FilterModule } from '../filter/filter.module';
|
import { FilterModule } from '../filter/filter.module';
|
||||||
@ -21,6 +22,7 @@ import { FilterOrgComponent } from './filter-org.component';
|
|||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
|
RouterModule,
|
||||||
],
|
],
|
||||||
exports: [FilterOrgComponent],
|
exports: [FilterOrgComponent],
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { MatCheckboxChange } from '@angular/material/checkbox';
|
import { MatCheckboxChange } from '@angular/material/checkbox';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { take } from 'rxjs';
|
||||||
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
|
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
|
||||||
import { ProjectNameQuery, ProjectQuery, ProjectState } from 'src/app/proto/generated/zitadel/project_pb';
|
import { ProjectNameQuery, ProjectQuery, ProjectState } from 'src/app/proto/generated/zitadel/project_pb';
|
||||||
import { UserNameQuery } from 'src/app/proto/generated/zitadel/user_pb';
|
import { UserNameQuery } from 'src/app/proto/generated/zitadel/user_pb';
|
||||||
@ -16,13 +18,43 @@ enum SubQuery {
|
|||||||
templateUrl: './filter-project.component.html',
|
templateUrl: './filter-project.component.html',
|
||||||
styleUrls: ['./filter-project.component.scss'],
|
styleUrls: ['./filter-project.component.scss'],
|
||||||
})
|
})
|
||||||
export class FilterProjectComponent extends FilterComponent {
|
export class FilterProjectComponent extends FilterComponent implements OnInit {
|
||||||
public SubQuery: any = SubQuery;
|
public SubQuery: any = SubQuery;
|
||||||
public searchQueries: ProjectQuery[] = [];
|
public searchQueries: ProjectQuery[] = [];
|
||||||
|
|
||||||
public states: ProjectState[] = [ProjectState.PROJECT_STATE_ACTIVE, ProjectState.PROJECT_STATE_INACTIVE];
|
public states: ProjectState[] = [ProjectState.PROJECT_STATE_ACTIVE, ProjectState.PROJECT_STATE_INACTIVE];
|
||||||
constructor() {
|
constructor(router: Router, route: ActivatedRoute) {
|
||||||
super();
|
super(router, route);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.route.queryParams.pipe(take(1)).subscribe((params) => {
|
||||||
|
const { filter } = params;
|
||||||
|
if (filter) {
|
||||||
|
const stringifiedFilters = filter as string;
|
||||||
|
const filters: ProjectQuery.AsObject[] = JSON.parse(stringifiedFilters) as ProjectQuery.AsObject[];
|
||||||
|
|
||||||
|
const projectQueries = filters.map((filter) => {
|
||||||
|
if (filter.nameQuery) {
|
||||||
|
const nameQuery = new ProjectNameQuery();
|
||||||
|
|
||||||
|
const projectQuery = new ProjectQuery();
|
||||||
|
nameQuery.setName(filter.nameQuery.name);
|
||||||
|
nameQuery.setMethod(filter.nameQuery.method);
|
||||||
|
|
||||||
|
projectQuery.setNameQuery(nameQuery);
|
||||||
|
return projectQuery;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.searchQueries = projectQueries.filter((q) => q !== undefined) as ProjectQuery[];
|
||||||
|
this.filterChanged.emit(this.filterCount ? this.searchQueries : undefined);
|
||||||
|
// this.showFilter = true;
|
||||||
|
// this.filterOpen.emit(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public changeCheckbox(subquery: SubQuery, event: MatCheckboxChange) {
|
public changeCheckbox(subquery: SubQuery, event: MatCheckboxChange) {
|
||||||
|
@ -4,6 +4,7 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
import { FilterModule } from '../filter/filter.module';
|
import { FilterModule } from '../filter/filter.module';
|
||||||
@ -21,6 +22,7 @@ import { FilterProjectComponent } from './filter-project.component';
|
|||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
|
RouterModule,
|
||||||
],
|
],
|
||||||
exports: [FilterProjectComponent],
|
exports: [FilterProjectComponent],
|
||||||
})
|
})
|
||||||
|
@ -1,82 +1,105 @@
|
|||||||
<cnsl-filter (resetted)="resetFilter()" (trigger)="emitFilter()">
|
<cnsl-filter (resetted)="resetFilter()" (trigger)="emitFilter()">
|
||||||
<div class="filter-row" id="filtercomp">
|
<div class="filter-row" id="filtercomp">
|
||||||
<div class="name-query">
|
<div class="name-query">
|
||||||
<mat-checkbox id="displayname" class="cb" [checked]="getSubFilter(SubQuery.DISPLAYNAME)"
|
<mat-checkbox
|
||||||
(change)="changeCheckbox(SubQuery.DISPLAYNAME, $event )">{{'FILTER.DISPLAYNAME' | translate}}
|
id="displayname"
|
||||||
|
class="cb"
|
||||||
|
[checked]="getSubFilter(SubQuery.DISPLAYNAME)"
|
||||||
|
(change)="changeCheckbox(SubQuery.DISPLAYNAME, $event)"
|
||||||
|
>{{ 'FILTER.DISPLAYNAME' | translate }}
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
<div class="subquery" *ngIf="getSubFilter(SubQuery.DISPLAYNAME) as dnq">
|
<div class="subquery" *ngIf="getSubFilter(SubQuery.DISPLAYNAME) as dnq">
|
||||||
<cnsl-form-field class="filter-select-method">
|
<cnsl-form-field class="filter-select-method">
|
||||||
<mat-select [value]="dnq.getMethod()" (selectionChange)="setMethod(dnq, $event)">
|
<mat-select [value]="dnq.getMethod()" (selectionChange)="setMethod(dnq, $event)">
|
||||||
<mat-option *ngFor="let method of methods" [value]="method">
|
<mat-option *ngFor="let method of methods" [value]="method">
|
||||||
{{ 'FILTER.METHODS.'+method | translate }}
|
{{ 'FILTER.METHODS.' + method | translate }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</cnsl-form-field>
|
</cnsl-form-field>
|
||||||
|
|
||||||
<cnsl-form-field class="filter-input-value">
|
<cnsl-form-field class="filter-input-value">
|
||||||
<input cnslInput name="value" [value]="dnq.getDisplayName()"
|
<input
|
||||||
(change)="setValue(SubQuery.DISPLAYNAME, dnq, $event)" />
|
cnslInput
|
||||||
|
name="value"
|
||||||
|
[value]="dnq.getDisplayName()"
|
||||||
|
(change)="setValue(SubQuery.DISPLAYNAME, dnq, $event)"
|
||||||
|
/>
|
||||||
</cnsl-form-field>
|
</cnsl-form-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="usernane-query">
|
<div class="usernane-query">
|
||||||
<mat-checkbox id="username" class="cb" [checked]="getSubFilter(SubQuery.USERNAME)"
|
<mat-checkbox
|
||||||
(change)="changeCheckbox(SubQuery.USERNAME, $event )">{{'FILTER.USERNAME' | translate}}
|
id="username"
|
||||||
|
class="cb"
|
||||||
|
[checked]="getSubFilter(SubQuery.USERNAME)"
|
||||||
|
(change)="changeCheckbox(SubQuery.USERNAME, $event)"
|
||||||
|
>{{ 'FILTER.USERNAME' | translate }}
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
<div class="subquery" *ngIf="getSubFilter(SubQuery.USERNAME) as unq">
|
<div class="subquery" *ngIf="getSubFilter(SubQuery.USERNAME) as unq">
|
||||||
<cnsl-form-field class="filter-select-method">
|
<cnsl-form-field class="filter-select-method">
|
||||||
<mat-select [value]="unq.getMethod()" (selectionChange)="setMethod(unq, $event)">
|
<mat-select [value]="unq.getMethod()" (selectionChange)="setMethod(unq, $event)">
|
||||||
<mat-option *ngFor="let method of methods" [value]="method">
|
<mat-option *ngFor="let method of methods" [value]="method">
|
||||||
{{ 'FILTER.METHODS.'+method | translate}}
|
{{ 'FILTER.METHODS.' + method | translate }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</cnsl-form-field>
|
</cnsl-form-field>
|
||||||
|
|
||||||
<cnsl-form-field class="filter-input-value">
|
<cnsl-form-field class="filter-input-value">
|
||||||
<input cnslInput name="value" [value]="unq.getUserName()"
|
<input cnslInput name="value" [value]="unq.getUserName()" (change)="setValue(SubQuery.USERNAME, unq, $event)" />
|
||||||
(change)="setValue(SubQuery.USERNAME, unq, $event)" />
|
|
||||||
</cnsl-form-field>
|
</cnsl-form-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="email-query">
|
<div class="email-query">
|
||||||
<mat-checkbox id="email" class="cb" [checked]="getSubFilter(SubQuery.ORGNAME)"
|
<mat-checkbox
|
||||||
(change)="changeCheckbox(SubQuery.ORGNAME, $event )">{{'FILTER.ORGNAME' | translate}}
|
id="email"
|
||||||
|
class="cb"
|
||||||
|
[checked]="getSubFilter(SubQuery.ORGNAME)"
|
||||||
|
(change)="changeCheckbox(SubQuery.ORGNAME, $event)"
|
||||||
|
>{{ 'FILTER.ORGNAME' | translate }}
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
<div class="subquery" *ngIf="getSubFilter(SubQuery.ORGNAME) as onq">
|
<div class="subquery" *ngIf="getSubFilter(SubQuery.ORGNAME) as onq">
|
||||||
<cnsl-form-field class="filter-select-method">
|
<cnsl-form-field class="filter-select-method">
|
||||||
<mat-select [value]="onq.getMethod()" (selectionChange)="setMethod(onq, $event)">
|
<mat-select [value]="onq.getMethod()" (selectionChange)="setMethod(onq, $event)">
|
||||||
<mat-option *ngFor="let method of methods" [value]="method">
|
<mat-option *ngFor="let method of methods" [value]="method">
|
||||||
{{ 'FILTER.METHODS.'+method | translate}}
|
{{ 'FILTER.METHODS.' + method | translate }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</cnsl-form-field>
|
</cnsl-form-field>
|
||||||
|
|
||||||
<cnsl-form-field class="filter-input-value">
|
<cnsl-form-field class="filter-input-value">
|
||||||
<input cnslInput name="value" [value]="onq.getOrgName()" (change)="setValue(SubQuery.ORNAME, onq, $event)" />
|
<input cnslInput name="value" [value]="onq.getOrgName()" (change)="setValue(SubQuery.ORGNAME, onq, $event)" />
|
||||||
</cnsl-form-field>
|
</cnsl-form-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="email-query">
|
<div class="email-query">
|
||||||
<mat-checkbox id="projectname" class="cb" [checked]="getSubFilter(SubQuery.PROJECTNAME)"
|
<mat-checkbox
|
||||||
(change)="changeCheckbox(SubQuery.PROJECTNAME, $event )">{{'FILTER.PROJECTNAME' | translate}}
|
id="projectname"
|
||||||
|
class="cb"
|
||||||
|
[checked]="getSubFilter(SubQuery.PROJECTNAME)"
|
||||||
|
(change)="changeCheckbox(SubQuery.PROJECTNAME, $event)"
|
||||||
|
>{{ 'FILTER.PROJECTNAME' | translate }}
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
<div class="subquery" *ngIf="getSubFilter(SubQuery.PROJECTNAME) as pnq">
|
<div class="subquery" *ngIf="getSubFilter(SubQuery.PROJECTNAME) as pnq">
|
||||||
<cnsl-form-field class="filter-select-method">
|
<cnsl-form-field class="filter-select-method">
|
||||||
<mat-select [value]="pnq.getMethod()" (selectionChange)="setMethod(pnq, $event)">
|
<mat-select [value]="pnq.getMethod()" (selectionChange)="setMethod(pnq, $event)">
|
||||||
<mat-option *ngFor="let method of methods" [value]="method">
|
<mat-option *ngFor="let method of methods" [value]="method">
|
||||||
{{ 'FILTER.METHODS.'+method | translate}}
|
{{ 'FILTER.METHODS.' + method | translate }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</cnsl-form-field>
|
</cnsl-form-field>
|
||||||
|
|
||||||
<cnsl-form-field class="filter-input-value">
|
<cnsl-form-field class="filter-input-value">
|
||||||
<input cnslInput name="value" [value]="pnq.getProjectName()"
|
<input
|
||||||
(change)="setValue(SubQuery.PROJECTNAME, pnq, $event)" />
|
cnslInput
|
||||||
|
name="value"
|
||||||
|
[value]="pnq.getProjectName()"
|
||||||
|
(change)="setValue(SubQuery.PROJECTNAME, pnq, $event)"
|
||||||
|
/>
|
||||||
</cnsl-form-field>
|
</cnsl-form-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</cnsl-filter>
|
</cnsl-filter>
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { MatCheckboxChange } from '@angular/material/checkbox';
|
import { MatCheckboxChange } from '@angular/material/checkbox';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { take } from 'rxjs';
|
||||||
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
|
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
|
||||||
import {
|
import {
|
||||||
DisplayNameQuery,
|
DisplayNameQuery,
|
||||||
UserGrantOrgNameQuery,
|
UserGrantOrgNameQuery,
|
||||||
UserGrantProjectNameQuery,
|
UserGrantProjectNameQuery,
|
||||||
UserGrantQuery,
|
UserGrantQuery,
|
||||||
UserNameQuery,
|
UserNameQuery,
|
||||||
} from 'src/app/proto/generated/zitadel/user_pb';
|
} from 'src/app/proto/generated/zitadel/user_pb';
|
||||||
|
|
||||||
import { FilterComponent } from '../filter/filter.component';
|
import { FilterComponent } from '../filter/filter.component';
|
||||||
@ -23,11 +25,68 @@ enum SubQuery {
|
|||||||
templateUrl: './filter-user-grants.component.html',
|
templateUrl: './filter-user-grants.component.html',
|
||||||
styleUrls: ['./filter-user-grants.component.scss'],
|
styleUrls: ['./filter-user-grants.component.scss'],
|
||||||
})
|
})
|
||||||
export class FilterUserGrantsComponent extends FilterComponent {
|
export class FilterUserGrantsComponent extends FilterComponent implements OnInit {
|
||||||
public SubQuery: any = SubQuery;
|
public SubQuery: any = SubQuery;
|
||||||
public searchQueries: UserGrantQuery[] = [];
|
public searchQueries: UserGrantQuery[] = [];
|
||||||
constructor() {
|
|
||||||
super();
|
constructor(router: Router, route: ActivatedRoute) {
|
||||||
|
super(router, route);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.route.queryParams.pipe(take(1)).subscribe((params) => {
|
||||||
|
const { filter } = params;
|
||||||
|
if (filter) {
|
||||||
|
const stringifiedFilters = filter as string;
|
||||||
|
const filters: UserGrantQuery.AsObject[] = JSON.parse(stringifiedFilters) as UserGrantQuery.AsObject[];
|
||||||
|
|
||||||
|
const userQueries = filters.map((filter) => {
|
||||||
|
if (filter.userNameQuery) {
|
||||||
|
const userGrantQuery = new UserGrantQuery();
|
||||||
|
|
||||||
|
const userNameQuery = new UserNameQuery();
|
||||||
|
userNameQuery.setUserName(filter.userNameQuery.userName);
|
||||||
|
userNameQuery.setMethod(filter.userNameQuery.method);
|
||||||
|
|
||||||
|
userGrantQuery.setUserNameQuery(userNameQuery);
|
||||||
|
return userGrantQuery;
|
||||||
|
} else if (filter.displayNameQuery) {
|
||||||
|
const userGrantQuery = new UserGrantQuery();
|
||||||
|
|
||||||
|
const displayNameQuery = new DisplayNameQuery();
|
||||||
|
displayNameQuery.setDisplayName(filter.displayNameQuery.displayName);
|
||||||
|
displayNameQuery.setMethod(filter.displayNameQuery.method);
|
||||||
|
|
||||||
|
userGrantQuery.setDisplayNameQuery(displayNameQuery);
|
||||||
|
return userGrantQuery;
|
||||||
|
} else if (filter.orgNameQuery) {
|
||||||
|
const userGrantQuery = new UserGrantQuery();
|
||||||
|
|
||||||
|
const orgNameQuery = new UserGrantOrgNameQuery();
|
||||||
|
orgNameQuery.setOrgName(filter.orgNameQuery.orgName);
|
||||||
|
orgNameQuery.setMethod(filter.orgNameQuery.method);
|
||||||
|
|
||||||
|
userGrantQuery.setOrgNameQuery(orgNameQuery);
|
||||||
|
return userGrantQuery;
|
||||||
|
} else if (filter.projectNameQuery) {
|
||||||
|
const userGrantQuery = new UserGrantQuery();
|
||||||
|
|
||||||
|
const projectNameQuery = new UserGrantProjectNameQuery();
|
||||||
|
projectNameQuery.setProjectName(filter.projectNameQuery.projectName);
|
||||||
|
|
||||||
|
userGrantQuery.setProjectNameQuery(projectNameQuery);
|
||||||
|
return userGrantQuery;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.searchQueries = userQueries.filter((q) => q !== undefined) as UserGrantQuery[];
|
||||||
|
this.filterChanged.emit(this.filterCount ? this.searchQueries : undefined);
|
||||||
|
// this.showFilter = true;
|
||||||
|
// this.filterOpen.emit(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public changeCheckbox(subquery: SubQuery, event: MatCheckboxChange) {
|
public changeCheckbox(subquery: SubQuery, event: MatCheckboxChange) {
|
||||||
|
@ -4,6 +4,7 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
import { FilterModule } from '../filter/filter.module';
|
import { FilterModule } from '../filter/filter.module';
|
||||||
@ -21,6 +22,7 @@ import { FilterUserGrantsComponent } from './filter-user-grants.component';
|
|||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
|
RouterModule,
|
||||||
],
|
],
|
||||||
exports: [FilterUserGrantsComponent],
|
exports: [FilterUserGrantsComponent],
|
||||||
})
|
})
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { MatCheckboxChange } from '@angular/material/checkbox';
|
import { MatCheckboxChange } from '@angular/material/checkbox';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { take } from 'rxjs';
|
||||||
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
|
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
|
||||||
import {
|
import {
|
||||||
DisplayNameQuery,
|
DisplayNameQuery,
|
||||||
EmailQuery,
|
EmailQuery,
|
||||||
SearchQuery as UserSearchQuery,
|
SearchQuery as UserSearchQuery,
|
||||||
StateQuery,
|
StateQuery,
|
||||||
UserNameQuery,
|
UserNameQuery,
|
||||||
UserState,
|
UserState,
|
||||||
} from 'src/app/proto/generated/zitadel/user_pb';
|
} from 'src/app/proto/generated/zitadel/user_pb';
|
||||||
|
|
||||||
import { FilterComponent } from '../filter/filter.component';
|
import { FilterComponent } from '../filter/filter.component';
|
||||||
@ -24,7 +26,7 @@ enum SubQuery {
|
|||||||
templateUrl: './filter-user.component.html',
|
templateUrl: './filter-user.component.html',
|
||||||
styleUrls: ['./filter-user.component.scss'],
|
styleUrls: ['./filter-user.component.scss'],
|
||||||
})
|
})
|
||||||
export class FilterUserComponent extends FilterComponent {
|
export class FilterUserComponent extends FilterComponent implements OnInit {
|
||||||
public SubQuery: any = SubQuery;
|
public SubQuery: any = SubQuery;
|
||||||
public searchQueries: UserSearchQuery[] = [];
|
public searchQueries: UserSearchQuery[] = [];
|
||||||
|
|
||||||
@ -36,8 +38,64 @@ export class FilterUserComponent extends FilterComponent {
|
|||||||
UserState.USER_STATE_LOCKED,
|
UserState.USER_STATE_LOCKED,
|
||||||
UserState.USER_STATE_SUSPEND,
|
UserState.USER_STATE_SUSPEND,
|
||||||
];
|
];
|
||||||
constructor() {
|
constructor(router: Router, route: ActivatedRoute) {
|
||||||
super();
|
super(router, route);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.route.queryParams.pipe(take(1)).subscribe((params) => {
|
||||||
|
const { filter } = params;
|
||||||
|
if (filter) {
|
||||||
|
const stringifiedFilters = filter as string;
|
||||||
|
const filters: UserSearchQuery.AsObject[] = JSON.parse(stringifiedFilters) as UserSearchQuery.AsObject[];
|
||||||
|
|
||||||
|
const userQueries = filters.map((filter) => {
|
||||||
|
if (filter.userNameQuery) {
|
||||||
|
const userQuery = new UserSearchQuery();
|
||||||
|
|
||||||
|
const userNameQuery = new UserNameQuery();
|
||||||
|
userNameQuery.setUserName(filter.userNameQuery.userName);
|
||||||
|
userNameQuery.setMethod(filter.userNameQuery.method);
|
||||||
|
|
||||||
|
userQuery.setUserNameQuery(userNameQuery);
|
||||||
|
return userQuery;
|
||||||
|
} else if (filter.displayNameQuery) {
|
||||||
|
const userQuery = new UserSearchQuery();
|
||||||
|
|
||||||
|
const displayNameQuery = new DisplayNameQuery();
|
||||||
|
displayNameQuery.setDisplayName(filter.displayNameQuery.displayName);
|
||||||
|
displayNameQuery.setMethod(filter.displayNameQuery.method);
|
||||||
|
|
||||||
|
userQuery.setDisplayNameQuery(displayNameQuery);
|
||||||
|
return userQuery;
|
||||||
|
} else if (filter.emailQuery) {
|
||||||
|
const userQuery = new UserSearchQuery();
|
||||||
|
|
||||||
|
const emailQuery = new EmailQuery();
|
||||||
|
emailQuery.setEmailAddress(filter.emailQuery.emailAddress);
|
||||||
|
emailQuery.setMethod(filter.emailQuery.method);
|
||||||
|
|
||||||
|
userQuery.setEmailQuery(emailQuery);
|
||||||
|
return userQuery;
|
||||||
|
} else if (filter.stateQuery) {
|
||||||
|
const userQuery = new UserSearchQuery();
|
||||||
|
|
||||||
|
const stateQuery = new StateQuery();
|
||||||
|
stateQuery.setState(filter.stateQuery.state);
|
||||||
|
|
||||||
|
userQuery.setStateQuery(stateQuery);
|
||||||
|
return userQuery;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.searchQueries = userQueries.filter((q) => q !== undefined) as UserSearchQuery[];
|
||||||
|
this.filterChanged.emit(this.filterCount ? this.searchQueries : undefined);
|
||||||
|
// this.showFilter = true;
|
||||||
|
// this.filterOpen.emit(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public changeCheckbox(subquery: SubQuery, event: MatCheckboxChange) {
|
public changeCheckbox(subquery: SubQuery, event: MatCheckboxChange) {
|
||||||
|
@ -4,6 +4,7 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
import { FilterModule } from '../filter/filter.module';
|
import { FilterModule } from '../filter/filter.module';
|
||||||
@ -19,6 +20,7 @@ import { FilterUserComponent } from './filter-user.component';
|
|||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
|
RouterModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
],
|
],
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { ConnectedPosition, ConnectionPositionPair } from '@angular/cdk/overlay';
|
import { ConnectedPosition, ConnectionPositionPair } from '@angular/cdk/overlay';
|
||||||
import { Component, EventEmitter, OnDestroy, Output } from '@angular/core';
|
import { Component, EventEmitter, OnDestroy, Output } from '@angular/core';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { BehaviorSubject, Subject, takeUntil } from 'rxjs';
|
||||||
import { SearchQuery as MemberSearchQuery } from 'src/app/proto/generated/zitadel/member_pb';
|
import { SearchQuery as MemberSearchQuery } from 'src/app/proto/generated/zitadel/member_pb';
|
||||||
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
|
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
|
||||||
import { OrgQuery } from 'src/app/proto/generated/zitadel/org_pb';
|
import { OrgQuery } from 'src/app/proto/generated/zitadel/org_pb';
|
||||||
@ -10,6 +11,12 @@ import { SearchQuery as UserSearchQuery, UserGrantQuery } from 'src/app/proto/ge
|
|||||||
import { ActionKeysType } from '../action-keys/action-keys.component';
|
import { ActionKeysType } from '../action-keys/action-keys.component';
|
||||||
|
|
||||||
type FilterSearchQuery = UserSearchQuery | MemberSearchQuery | UserGrantQuery | ProjectQuery | OrgQuery;
|
type FilterSearchQuery = UserSearchQuery | MemberSearchQuery | UserGrantQuery | ProjectQuery | OrgQuery;
|
||||||
|
type FilterSearchQueryAsObject =
|
||||||
|
| UserSearchQuery.AsObject
|
||||||
|
| MemberSearchQuery.AsObject
|
||||||
|
| UserGrantQuery.AsObject
|
||||||
|
| ProjectQuery.AsObject
|
||||||
|
| OrgQuery.AsObject;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cnsl-filter',
|
selector: 'cnsl-filter',
|
||||||
@ -23,6 +30,8 @@ export class FilterComponent implements OnDestroy {
|
|||||||
@Output() public resetted: EventEmitter<void> = new EventEmitter();
|
@Output() public resetted: EventEmitter<void> = new EventEmitter();
|
||||||
@Output() public trigger: EventEmitter<void> = new EventEmitter();
|
@Output() public trigger: EventEmitter<void> = new EventEmitter();
|
||||||
|
|
||||||
|
private destroy$: Subject<void> = new Subject();
|
||||||
|
|
||||||
public filterCount$: BehaviorSubject<number> = new BehaviorSubject(0);
|
public filterCount$: BehaviorSubject<number> = new BehaviorSubject(0);
|
||||||
|
|
||||||
public showFilter: boolean = false;
|
public showFilter: boolean = false;
|
||||||
@ -51,5 +60,33 @@ export class FilterComponent implements OnDestroy {
|
|||||||
|
|
||||||
public ngOnDestroy(): void {
|
public ngOnDestroy(): void {
|
||||||
this.filterCount$.complete();
|
this.filterCount$.complete();
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private router: Router, protected route: ActivatedRoute) {
|
||||||
|
const changes$ = this.filterChanged.asObservable();
|
||||||
|
changes$.pipe(takeUntil(this.destroy$)).subscribe((queries) => {
|
||||||
|
const filters: Array<FilterSearchQueryAsObject | {}> | undefined = queries
|
||||||
|
?.map((q) => q.toObject())
|
||||||
|
.map((query) =>
|
||||||
|
Object.keys(query).reduce((acc, key) => {
|
||||||
|
const _acc = acc;
|
||||||
|
if ((query as any)[key] !== undefined) (_acc as any)[key] = (query as any)[key];
|
||||||
|
return _acc as FilterSearchQueryAsObject;
|
||||||
|
}, {}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (filters && Object.keys(filters)) {
|
||||||
|
this.router.navigate([], {
|
||||||
|
relativeTo: this.route,
|
||||||
|
queryParams: {
|
||||||
|
['filter']: JSON.stringify(filters),
|
||||||
|
},
|
||||||
|
queryParamsHandling: 'merge',
|
||||||
|
skipLocationChange: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
<div class="info-section-row" [ngClass]="{'info': type === 'INFO', 'warn': type === 'WARN'}">
|
<div
|
||||||
<i *ngIf="type === 'INFO'" class="icon las la-info"></i>
|
class="info-section-row"
|
||||||
<i *ngIf="type === 'WARN'" class="icon las la-exclamation"></i>
|
[ngClass]="{ info: type === 'INFO', warn: type === 'WARN', alert: type === 'ALERT', fit: fitWidth }"
|
||||||
|
>
|
||||||
|
<i *ngIf="type === 'INFO'" class="icon las la-info"></i>
|
||||||
|
<i *ngIf="type === 'WARN'" class="icon las la-exclamation"></i>
|
||||||
|
<i *ngIf="type === 'ALERT'" class="icon las la-exclamation"></i>
|
||||||
|
|
||||||
<div class="info-section-content">
|
<div class="info-section-content">
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,23 +10,27 @@
|
|||||||
.info-section-row {
|
.info-section-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: .5rem 0;
|
padding: 0.5rem 0;
|
||||||
padding-right: 1rem;
|
padding-right: 1rem;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin: .5rem 0;
|
margin: 0.5rem 0;
|
||||||
|
|
||||||
|
&.fit {
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
height: 1.2rem;
|
height: 1.2rem;
|
||||||
line-height: 1.2rem;
|
line-height: 1.2rem;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
margin-left: .5rem;
|
margin-left: 0.5rem;
|
||||||
padding: .25rem 0;
|
padding: 0.25rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-section-content {
|
.info-section-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: .25rem 0;
|
padding: 0.25rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.info {
|
&.info {
|
||||||
@ -55,5 +59,14 @@
|
|||||||
color: map-get($foreground, warninfosection);
|
color: map-get($foreground, warninfosection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.alert {
|
||||||
|
background-color: map-get($background, alertinfosection);
|
||||||
|
color: map-get($foreground, alertinfosection);
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: map-get($foreground, alertinfosection);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ export enum InfoSectionType {
|
|||||||
INFO = 'INFO',
|
INFO = 'INFO',
|
||||||
SUCCESS = 'SUCCESS',
|
SUCCESS = 'SUCCESS',
|
||||||
WARN = 'WARN',
|
WARN = 'WARN',
|
||||||
|
ALERT = 'ALERT',
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -12,6 +13,6 @@ export enum InfoSectionType {
|
|||||||
styleUrls: ['./info-section.component.scss'],
|
styleUrls: ['./info-section.component.scss'],
|
||||||
})
|
})
|
||||||
export class InfoSectionComponent {
|
export class InfoSectionComponent {
|
||||||
|
|
||||||
@Input() type: InfoSectionType = InfoSectionType.INFO;
|
@Input() type: InfoSectionType = InfoSectionType.INFO;
|
||||||
|
@Input() fitWidth: boolean = false;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<cnsl-refresh-table
|
<cnsl-refresh-table
|
||||||
*ngIf="dataSource"
|
|
||||||
[hideRefresh]="true"
|
[hideRefresh]="true"
|
||||||
(refreshed)="refresh()"
|
(refreshed)="refresh()"
|
||||||
[dataSize]="dataSource.data.length"
|
[dataSize]="dataSource.data.length"
|
||||||
@ -33,7 +32,7 @@
|
|||||||
|
|
||||||
<ng-container matColumnDef="primaryDomain">
|
<ng-container matColumnDef="primaryDomain">
|
||||||
<th mat-header-cell *matHeaderCellDef>{{ 'ORG.PAGES.PRIMARYDOMAIN' | translate }}</th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'ORG.PAGES.PRIMARYDOMAIN' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let org">
|
<td mat-cell *matCellDef="let org" (click)="setAndNavigateToOrg(org)">
|
||||||
<span>{{ org.primaryDomain }}</span>
|
<span>{{ org.primaryDomain }}</span>
|
||||||
<button
|
<button
|
||||||
color="primary"
|
color="primary"
|
||||||
@ -101,6 +100,6 @@
|
|||||||
[length]="totalResult || 0"
|
[length]="totalResult || 0"
|
||||||
[pageSize]="initialLimit"
|
[pageSize]="initialLimit"
|
||||||
[pageSizeOptions]="[10, 20, 50, 100]"
|
[pageSizeOptions]="[10, 20, 50, 100]"
|
||||||
(page)="changePage($event)"
|
(page)="changePage()"
|
||||||
></cnsl-paginator>
|
></cnsl-paginator>
|
||||||
</cnsl-refresh-table>
|
</cnsl-refresh-table>
|
||||||
|
@ -2,16 +2,19 @@ import { Component, Input, ViewChild } from '@angular/core';
|
|||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
||||||
import { BehaviorSubject, catchError, finalize, from, map, Observable, of } from 'rxjs';
|
import { BehaviorSubject, catchError, finalize, from, map, Observable, of, Subject, switchMap, takeUntil } from 'rxjs';
|
||||||
import { Org, OrgQuery, OrgState } from 'src/app/proto/generated/zitadel/org_pb';
|
import { Org, OrgQuery, OrgState } from 'src/app/proto/generated/zitadel/org_pb';
|
||||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||||
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
import { PageEvent, PaginatorComponent } from '../paginator/paginator.component';
|
import { PaginatorComponent } from '../paginator/paginator.component';
|
||||||
|
|
||||||
enum OrgListSearchKey {
|
enum OrgListSearchKey {
|
||||||
NAME = 'NAME',
|
NAME = 'NAME',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Request = { limit: number; offset: number; queries: OrgQuery[] };
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cnsl-org-table',
|
selector: 'cnsl-org-table',
|
||||||
templateUrl: './org-table.component.html',
|
templateUrl: './org-table.component.html',
|
||||||
@ -23,7 +26,7 @@ export class OrgTableComponent {
|
|||||||
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||||
@ViewChild('input') public filter!: Input;
|
@ViewChild('input') public filter!: Input;
|
||||||
|
|
||||||
public dataSource!: MatTableDataSource<Org.AsObject>;
|
public dataSource: MatTableDataSource<Org.AsObject> = new MatTableDataSource<Org.AsObject>([]);
|
||||||
public displayedColumns: string[] = ['name', 'state', 'primaryDomain', 'creationDate', 'changeDate'];
|
public displayedColumns: string[] = ['name', 'state', 'primaryDomain', 'creationDate', 'changeDate'];
|
||||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||||
@ -35,27 +38,40 @@ export class OrgTableComponent {
|
|||||||
public filterOpen: boolean = false;
|
public filterOpen: boolean = false;
|
||||||
public OrgState: any = OrgState;
|
public OrgState: any = OrgState;
|
||||||
public copied: string = '';
|
public copied: string = '';
|
||||||
constructor(private authService: GrpcAuthService, private router: Router) {
|
|
||||||
this.loadOrgs(this.initialLimit, 0);
|
private searchQueries: OrgQuery[] = [];
|
||||||
|
private destroy$: Subject<void> = new Subject();
|
||||||
|
private requestOrgs$: BehaviorSubject<Request> = new BehaviorSubject<Request>({
|
||||||
|
limit: this.initialLimit,
|
||||||
|
offset: 0,
|
||||||
|
queries: [],
|
||||||
|
});
|
||||||
|
private requestOrgsObservable$ = this.requestOrgs$.pipe(takeUntil(this.destroy$));
|
||||||
|
|
||||||
|
constructor(private authService: GrpcAuthService, private router: Router, private toast: ToastService) {
|
||||||
|
this.requestOrgs$.next({ limit: this.initialLimit, offset: 0, queries: this.searchQueries });
|
||||||
this.authService.getActiveOrg().then((org) => (this.activeOrg = org));
|
this.authService.getActiveOrg().then((org) => (this.activeOrg = org));
|
||||||
|
|
||||||
|
this.requestOrgsObservable$.pipe(switchMap((req) => this.loadOrgs(req))).subscribe((orgs) => {
|
||||||
|
this.dataSource = new MatTableDataSource<Org.AsObject>(orgs);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public loadOrgs(limit: number, offset: number, queries?: OrgQuery[]): void {
|
public loadOrgs(request: Request): Observable<Org.AsObject[]> {
|
||||||
this.loadingSubject.next(true);
|
this.loadingSubject.next(true);
|
||||||
|
|
||||||
from(this.authService.listMyProjectOrgs(limit, offset, queries))
|
return from(this.authService.listMyProjectOrgs(request.limit, request.offset, request.queries)).pipe(
|
||||||
.pipe(
|
map((resp) => {
|
||||||
map((resp) => {
|
this.timestamp = resp.details?.viewTimestamp;
|
||||||
this.timestamp = resp.details?.viewTimestamp;
|
this.totalResult = resp.details?.totalResult ?? 0;
|
||||||
this.totalResult = resp.details?.totalResult ?? 0;
|
return resp.resultList;
|
||||||
return resp.resultList;
|
}),
|
||||||
}),
|
catchError((error) => {
|
||||||
catchError(() => of([])),
|
this.toast.showError(error);
|
||||||
finalize(() => this.loadingSubject.next(false)),
|
return of([]);
|
||||||
)
|
}),
|
||||||
.subscribe((views) => {
|
finalize(() => this.loadingSubject.next(false)),
|
||||||
this.dataSource = new MatTableDataSource(views);
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public selectOrg(item: Org.AsObject, event?: any): void {
|
public selectOrg(item: Org.AsObject, event?: any): void {
|
||||||
@ -63,11 +79,20 @@ export class OrgTableComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public refresh(): void {
|
public refresh(): void {
|
||||||
this.loadOrgs(this.paginator.length, this.paginator.pageSize * this.paginator.pageIndex);
|
this.requestOrgs$.next({
|
||||||
|
limit: this.paginator.length,
|
||||||
|
offset: this.paginator.pageSize * this.paginator.pageIndex,
|
||||||
|
queries: this.searchQueries,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public applySearchQuery(searchQueries: OrgQuery[]): void {
|
public applySearchQuery(searchQueries: OrgQuery[]): void {
|
||||||
this.loadOrgs(this.paginator.pageSize, this.paginator.pageSize * this.paginator.pageIndex, searchQueries);
|
this.searchQueries = searchQueries;
|
||||||
|
this.requestOrgs$.next({
|
||||||
|
limit: this.paginator ? this.paginator.pageSize : this.initialLimit,
|
||||||
|
offset: this.paginator ? this.paginator.pageSize * this.paginator.pageIndex : 0,
|
||||||
|
queries: this.searchQueries,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public setFilter(key: OrgListSearchKey): void {
|
public setFilter(key: OrgListSearchKey): void {
|
||||||
@ -90,8 +115,8 @@ export class OrgTableComponent {
|
|||||||
this.router.navigate(['/org']);
|
this.router.navigate(['/org']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public changePage(event: PageEvent): void {
|
public changePage(): void {
|
||||||
this.loadOrgs(event.pageSize, event.pageIndex * event.pageSize);
|
this.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
public gotoRouterLink(rL: any) {
|
public gotoRouterLink(rL: any) {
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
<h1 mat-dialog-title class="title">
|
<h1 mat-dialog-title class="title">
|
||||||
<span>{{ 'SETTING.SMS.ADDPROVIDER' | translate }}</span>
|
<span>{{ provider === SMSProviderType.Twilio ? 'Twilio' : ('SETTING.SMS.ADDPROVIDER' | translate) }}</span>
|
||||||
</h1>
|
</h1>
|
||||||
<div mat-dialog-content>
|
<div mat-dialog-content>
|
||||||
<p class="desc cnsl-secondary-text">{{ 'SETTING.SMS.ADDPROVIDERDESCRIPTION' | translate }}</p>
|
<!-- <p class="desc cnsl-secondary-text">{{ 'SETTING.SMS.ADDPROVIDERDESCRIPTION' | translate }}</p> -->
|
||||||
|
|
||||||
<cnsl-form-field class="form-field" label="Access Code" required="true">
|
<!-- <cnsl-form-field class="form-field" label="Access Code" required="true">
|
||||||
<cnsl-label>{{ 'MFA.TYPE' | translate }}</cnsl-label>
|
<cnsl-label>{{ 'MFA.TYPE' | translate }}</cnsl-label>
|
||||||
<mat-select [(ngModel)]="provider">
|
<mat-select [(ngModel)]="provider">
|
||||||
<mat-option *ngFor="let prov of availableSMSProviders" [value]="prov">
|
<mat-option *ngFor="let prov of availableSMSProviders" [value]="prov">
|
||||||
<span *ngIf="prov === SMSProviderType.Twilio">Twilio</span>
|
<span *ngIf="prov === SMSProviderType.Twilio">Twilio</span>
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</cnsl-form-field>
|
</cnsl-form-field> -->
|
||||||
|
|
||||||
<form *ngIf="provider === SMSProviderType.Twilio" (ngSubmit)="closeDialogWithRequest()" [formGroup]="twilioForm">
|
<form *ngIf="provider === SMSProviderType.Twilio" (ngSubmit)="closeDialogWithRequest()" [formGroup]="twilioForm">
|
||||||
<h2>Twilio</h2>
|
<!-- <h2>Twilio</h2> -->
|
||||||
|
|
||||||
<cnsl-form-field class="sms-form-field" label="sid">
|
<cnsl-form-field class="sms-form-field" label="sid">
|
||||||
<cnsl-label>{{ 'SETTING.SMS.TWILIO.SID' | translate }}</cnsl-label>
|
<cnsl-label>{{ 'SETTING.SMS.TWILIO.SID' | translate }}</cnsl-label>
|
||||||
@ -43,6 +43,6 @@
|
|||||||
color="primary"
|
color="primary"
|
||||||
(click)="closeDialogWithRequest()"
|
(click)="closeDialogWithRequest()"
|
||||||
>
|
>
|
||||||
<span>{{ 'ACTIONS.OK' | translate }}</span>
|
<span>{{ 'ACTIONS.SAVE' | translate }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
|
|
||||||
<h2>{{ 'SETTING.SMTP.TITLE' | translate }}</h2>
|
<h2>{{ 'SETTING.SMTP.TITLE' | translate }}</h2>
|
||||||
|
|
||||||
|
<cnsl-info-section *ngIf="!form.valid" class="info-section-warn" [fitWidth]="true" [type]="InfoSectionType.ALERT">{{
|
||||||
|
'SETTING.SMTP.REQUIREDWARN' | translate
|
||||||
|
}}</cnsl-info-section>
|
||||||
|
|
||||||
<form (ngSubmit)="savePolicy()" [formGroup]="form" autocomplete="off">
|
<form (ngSubmit)="savePolicy()" [formGroup]="form" autocomplete="off">
|
||||||
<cnsl-form-field class="smtp-form-field" label="Sender Address" required="true">
|
<cnsl-form-field class="smtp-form-field" label="Sender Address" required="true">
|
||||||
<cnsl-label>{{ 'SETTING.SMTP.SENDERADDRESS' | translate }}</cnsl-label>
|
<cnsl-label>{{ 'SETTING.SMTP.SENDERADDRESS' | translate }}</cnsl-label>
|
||||||
@ -50,26 +54,28 @@
|
|||||||
|
|
||||||
<br />
|
<br />
|
||||||
<h2>{{ 'SETTING.SMS.TITLE' | translate }}</h2>
|
<h2>{{ 'SETTING.SMS.TITLE' | translate }}</h2>
|
||||||
<h3>{{ 'SETTING.SMS.PROVIDERS' | translate }}</h3>
|
|
||||||
<div class="sms-providers">
|
<div class="sms-providers">
|
||||||
<cnsl-card *ngFor="let provider of smsProviders" class="sms-card">
|
<cnsl-card class="sms-card" [nomargin]="true">
|
||||||
<div *ngIf="provider.twilio" class="sms-provider">
|
<div class="sms-provider">
|
||||||
<h4 class="title">Twilio</h4>
|
<h4 class="title">Twilio</h4>
|
||||||
<span class="cnsl-secondary-text">{{ 'SETTING.SMS.PROVIDER' | translate }}</span>
|
|
||||||
|
|
||||||
<span
|
<span
|
||||||
|
*ngIf="twilio"
|
||||||
class="state"
|
class="state"
|
||||||
[ngClass]="{
|
[ngClass]="{
|
||||||
active: provider.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_ACTIVE,
|
active: twilio?.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_ACTIVE,
|
||||||
inactive: provider.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_INACTIVE
|
inactive: twilio?.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_INACTIVE
|
||||||
}"
|
}"
|
||||||
></span>
|
></span>
|
||||||
|
|
||||||
|
<span class="fill-space"></span>
|
||||||
|
<button mat-icon-button (click)="addSMSProvider()"><i class="las la-pen"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</cnsl-card>
|
</cnsl-card>
|
||||||
<button mat-stroked-button (click)="addSMSProvider()">
|
<!-- <button mat-stroked-button (click)="addSMSProvider()">
|
||||||
<div class="sms-card add">
|
<div class="sms-card add">
|
||||||
<mat-icon>add</mat-icon>
|
<mat-icon>add</mat-icon>
|
||||||
<span>{{ 'ACTIONS.ADD' | translate }}</span>
|
<span>{{ 'ACTIONS.ADD' | translate }}</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button> -->
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,11 +2,16 @@
|
|||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.smtp-form-field {
|
.smtp-form-field,
|
||||||
|
.info-section-warn {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-section-warn {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.smtp-checkbox {
|
.smtp-checkbox {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
display: block;
|
display: block;
|
||||||
@ -40,7 +45,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: -0.5rem;
|
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
@ -3,13 +3,15 @@ import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/fo
|
|||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import {
|
import {
|
||||||
AddSMSProviderTwilioRequest,
|
AddSMSProviderTwilioRequest,
|
||||||
|
UpdateSMTPConfigPasswordRequest,
|
||||||
UpdateSMTPConfigPasswordResponse,
|
UpdateSMTPConfigPasswordResponse,
|
||||||
UpdateSMTPConfigRequest,
|
UpdateSMTPConfigRequest,
|
||||||
} from 'src/app/proto/generated/zitadel/admin_pb';
|
} from 'src/app/proto/generated/zitadel/admin_pb';
|
||||||
import { SMSProvider, SMSProviderConfigState } from 'src/app/proto/generated/zitadel/settings_pb';
|
import { DebugNotificationProvider, SMSProvider, SMSProviderConfigState } from 'src/app/proto/generated/zitadel/settings_pb';
|
||||||
import { AdminService } from 'src/app/services/admin.service';
|
import { AdminService } from 'src/app/services/admin.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
|
import { InfoSectionType } from '../../info-section/info-section.component';
|
||||||
import { PolicyComponentServiceType } from '../policy-component-types.enum';
|
import { PolicyComponentServiceType } from '../policy-component-types.enum';
|
||||||
import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider/dialog-add-sms-provider.component';
|
import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider/dialog-add-sms-provider.component';
|
||||||
|
|
||||||
@ -21,11 +23,16 @@ import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider/dialog-
|
|||||||
export class NotificationSettingsComponent implements OnInit {
|
export class NotificationSettingsComponent implements OnInit {
|
||||||
@Input() public serviceType!: PolicyComponentServiceType;
|
@Input() public serviceType!: PolicyComponentServiceType;
|
||||||
public smsProviders: SMSProvider.AsObject[] = [];
|
public smsProviders: SMSProvider.AsObject[] = [];
|
||||||
|
public logNotificationProvider!: DebugNotificationProvider.AsObject;
|
||||||
|
public fileNotificationProvider!: DebugNotificationProvider.AsObject;
|
||||||
public loading: boolean = false;
|
public loading: boolean = false;
|
||||||
public form!: FormGroup;
|
public form!: FormGroup;
|
||||||
|
|
||||||
public SMSProviderConfigState: any = SMSProviderConfigState;
|
public SMSProviderConfigState: any = SMSProviderConfigState;
|
||||||
|
public InfoSectionType: any = InfoSectionType;
|
||||||
|
|
||||||
|
// show available providers
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private service: AdminService,
|
private service: AdminService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
@ -66,6 +73,30 @@ export class NotificationSettingsComponent implements OnInit {
|
|||||||
console.log(this.smsProviders);
|
console.log(this.smsProviders);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.service
|
||||||
|
.getLogNotificationProvider()
|
||||||
|
.then((logNotificationProvider) => {
|
||||||
|
if (logNotificationProvider.provider) {
|
||||||
|
this.logNotificationProvider = logNotificationProvider.provider;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.toast.showError(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.service
|
||||||
|
.getFileSystemNotificationProvider()
|
||||||
|
.then((fileNotificationProvider) => {
|
||||||
|
if (fileNotificationProvider.provider) {
|
||||||
|
console.log(fileNotificationProvider);
|
||||||
|
this.fileNotificationProvider = fileNotificationProvider.provider;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log('hehe');
|
||||||
|
this.toast.showError(error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateData(): Promise<UpdateSMTPConfigPasswordResponse.AsObject> | any {
|
private updateData(): Promise<UpdateSMTPConfigPasswordResponse.AsObject> | any {
|
||||||
@ -76,18 +107,16 @@ export class NotificationSettingsComponent implements OnInit {
|
|||||||
req.setTls(this.tls?.value ?? false);
|
req.setTls(this.tls?.value ?? false);
|
||||||
req.setUser(this.user?.value ?? '');
|
req.setUser(this.user?.value ?? '');
|
||||||
|
|
||||||
console.log(req.toObject());
|
return this.service.updateSMTPConfig(req).then(() => {
|
||||||
|
let passwordReq: UpdateSMTPConfigPasswordRequest;
|
||||||
// return this.service.updateSMTPConfig(req).then(() => {
|
if (this.password) {
|
||||||
// let passwordReq: UpdateSMTPConfigPasswordRequest;
|
passwordReq = new UpdateSMTPConfigPasswordRequest();
|
||||||
// if (this.password) {
|
passwordReq.setPassword(this.password.value);
|
||||||
// passwordReq = new UpdateSMTPConfigPasswordRequest();
|
return this.service.updateSMTPConfigPassword(passwordReq);
|
||||||
// passwordReq.setPassword(this.password.value);
|
} else {
|
||||||
// return this.service.updateSMTPConfigPassword(passwordReq);
|
return;
|
||||||
// } else {
|
}
|
||||||
// return;
|
});
|
||||||
// }
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public savePolicy(): void {
|
public savePolicy(): void {
|
||||||
@ -126,6 +155,10 @@ export class NotificationSettingsComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get twilio(): SMSProvider.AsObject | undefined {
|
||||||
|
return this.smsProviders.find((p) => p.twilio);
|
||||||
|
}
|
||||||
|
|
||||||
public get senderAddress(): AbstractControl | null {
|
public get senderAddress(): AbstractControl | null {
|
||||||
return this.form.get('senderAddress');
|
return this.form.get('senderAddress');
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
|||||||
|
|
||||||
import { CardModule } from '../../card/card.module';
|
import { CardModule } from '../../card/card.module';
|
||||||
import { FormFieldModule } from '../../form-field/form-field.module';
|
import { FormFieldModule } from '../../form-field/form-field.module';
|
||||||
|
import { InfoSectionModule } from '../../info-section/info-section.module';
|
||||||
import { InputModule } from '../../input/input.module';
|
import { InputModule } from '../../input/input.module';
|
||||||
import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider/dialog-add-sms-provider.component';
|
import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider/dialog-add-sms-provider.component';
|
||||||
import { NotificationSettingsComponent } from './notification-settings.component';
|
import { NotificationSettingsComponent } from './notification-settings.component';
|
||||||
@ -19,6 +20,7 @@ import { NotificationSettingsComponent } from './notification-settings.component
|
|||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
CardModule,
|
CardModule,
|
||||||
|
InfoSectionModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
[ngClass]="{ active: currentSetting === setting.id, show: currentSetting === undefined }"
|
[ngClass]="{ active: currentSetting === setting.id, show: currentSetting === undefined }"
|
||||||
>
|
>
|
||||||
<span>{{ setting.i18nKey | translate }}</span>
|
<span>{{ setting.i18nKey | translate }}</span>
|
||||||
|
<mat-icon *ngIf="setting.showWarn" class="warn-icon" svgIcon="mdi_shield_alert"></mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-template #btn>
|
<ng-template #btn>
|
||||||
|
@ -67,21 +67,35 @@
|
|||||||
background: none;
|
background: none;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 0.75rem 0;
|
padding: 0.75rem 0;
|
||||||
opacity: 0.6;
|
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: map-get($foreground, base);
|
color: map-get($foreground, base);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
span {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
i {
|
i {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
height: 1.2rem;
|
height: 1.2rem;
|
||||||
line-height: 1.2rem;
|
line-height: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.warn-icon {
|
||||||
|
color: map-get($background, alert);
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
height: 1.2rem;
|
||||||
|
width: 1.2rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 1;
|
span {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mob-only {
|
&.mob-only {
|
||||||
@ -108,7 +122,10 @@
|
|||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
opacity: 1;
|
|
||||||
|
span {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ export interface SidenavSetting {
|
|||||||
i18nKey: string;
|
i18nKey: string;
|
||||||
groupI18nKey?: string;
|
groupI18nKey?: string;
|
||||||
requiredRoles?: { [serviceType in PolicyComponentServiceType]: string[] };
|
requiredRoles?: { [serviceType in PolicyComponentServiceType]: string[] };
|
||||||
|
showWarn?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -1,40 +1,38 @@
|
|||||||
<div class="max-width-container">
|
<div class="max-width-container">
|
||||||
<h1 class="failed-events-title">{{ 'IAM.FAILEDEVENTS.TITLE' | translate }}</h1>
|
<h1 class="failed-events-title">{{ 'IAM.FAILEDEVENTS.TITLE' | translate }}</h1>
|
||||||
<p class="failed-events-desc cnsl-secondary-text">{{'IAM.FAILEDEVENTS.DESCRIPTION' | translate }}</p>
|
<p class="failed-events-desc cnsl-secondary-text">{{ 'IAM.FAILEDEVENTS.DESCRIPTION' | translate }}</p>
|
||||||
|
|
||||||
<div class="table-wrapper">
|
<div class="table-wrapper">
|
||||||
<cnsl-refresh-table *ngIf="eventDataSource" (refreshed)="loadEvents()" [dataSize]="eventDataSource.data.length"
|
<cnsl-refresh-table (refreshed)="loadEvents()" [dataSize]="eventDataSource.data.length" [loading]="loading$ | async">
|
||||||
[loading]="loading$ | async">
|
<table [dataSource]="eventDataSource" mat-table class="table" aria-label="Elements">
|
||||||
|
|
||||||
<table [dataSource]="eventDataSource" mat-table class="table " aria-label="Elements">
|
|
||||||
<ng-container matColumnDef="viewName">
|
<ng-container matColumnDef="viewName">
|
||||||
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.FAILEDEVENTS.VIEWNAME' | translate }} </th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.FAILEDEVENTS.VIEWNAME' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let event"> {{event.viewName}} </td>
|
<td mat-cell *matCellDef="let event">{{ event.viewName }}</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="database">
|
<ng-container matColumnDef="database">
|
||||||
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.FAILEDEVENTS.DATABASE' | translate }} </th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.FAILEDEVENTS.DATABASE' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let event"> {{event.database}} </td>
|
<td mat-cell *matCellDef="let event">{{ event.database }}</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="failedSequence">
|
<ng-container matColumnDef="failedSequence">
|
||||||
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.FAILEDEVENTS.FAILEDSEQUENCE' | translate }} </th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.FAILEDEVENTS.FAILEDSEQUENCE' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let event">
|
<td mat-cell *matCellDef="let event">
|
||||||
<span>{{event?.failedSequence}}</span>
|
<span>{{ event?.failedSequence }}</span>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="failureCount">
|
<ng-container matColumnDef="failureCount">
|
||||||
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.FAILEDEVENTS.FAILURECOUNT' | translate }} </th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.FAILEDEVENTS.FAILURECOUNT' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let event">
|
<td mat-cell *matCellDef="let event">
|
||||||
<span>{{event?.failureCount }}</span>
|
<span>{{ event?.failureCount }}</span>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="errorMessage">
|
<ng-container matColumnDef="errorMessage">
|
||||||
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.FAILEDEVENTS.ERRORMESSAGE' | translate }} </th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.FAILEDEVENTS.ERRORMESSAGE' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let event">
|
<td mat-cell *matCellDef="let event">
|
||||||
<span class="failed-event-error-message">{{event?.errorMessage }}</span>
|
<span class="failed-event-error-message">{{ event?.errorMessage }}</span>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
@ -42,8 +40,13 @@
|
|||||||
<th mat-header-cell *matHeaderCellDef></th>
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
<td class="back" mat-cell *matCellDef="let event">
|
<td class="back" mat-cell *matCellDef="let event">
|
||||||
<cnsl-table-actions>
|
<cnsl-table-actions>
|
||||||
<button actions color="warn" mat-icon-button matTooltip="{{'IAM.FAILEDEVENTS.DELETE' | translate}}"
|
<button
|
||||||
(click)="cancelEvent(event.viewName, event.database, event.failedSequence)">
|
actions
|
||||||
|
color="warn"
|
||||||
|
mat-icon-button
|
||||||
|
matTooltip="{{ 'IAM.FAILEDEVENTS.DELETE' | translate }}"
|
||||||
|
(click)="cancelEvent(event.viewName, event.database, event.failedSequence)"
|
||||||
|
>
|
||||||
<i class="las la-minus-circle"></i>
|
<i class="las la-minus-circle"></i>
|
||||||
</button>
|
</button>
|
||||||
</cnsl-table-actions>
|
</cnsl-table-actions>
|
||||||
@ -51,10 +54,10 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="eventDisplayedColumns"></tr>
|
<tr mat-header-row *matHeaderRowDef="eventDisplayedColumns"></tr>
|
||||||
<tr class="highlight" mat-row *matRowDef="let row; columns: eventDisplayedColumns;"></tr>
|
<tr class="highlight" mat-row *matRowDef="let row; columns: eventDisplayedColumns"></tr>
|
||||||
</table>
|
</table>
|
||||||
<cnsl-paginator #paginator class="paginator" [hidePagination]="true" [length]="eventDataSource.data.length || 0">
|
<cnsl-paginator #paginator class="paginator" [hidePagination]="true" [length]="eventDataSource.data.length || 0">
|
||||||
</cnsl-paginator>
|
</cnsl-paginator>
|
||||||
</cnsl-refresh-table>
|
</cnsl-refresh-table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,7 +15,7 @@ import { ToastService } from 'src/app/services/toast.service';
|
|||||||
})
|
})
|
||||||
export class FailedEventsComponent implements AfterViewInit {
|
export class FailedEventsComponent implements AfterViewInit {
|
||||||
@ViewChild(MatPaginator) public eventPaginator!: MatPaginator;
|
@ViewChild(MatPaginator) public eventPaginator!: MatPaginator;
|
||||||
public eventDataSource!: MatTableDataSource<FailedEvent.AsObject>;
|
public eventDataSource: MatTableDataSource<FailedEvent.AsObject> = new MatTableDataSource<FailedEvent.AsObject>([]);
|
||||||
|
|
||||||
public eventDisplayedColumns: string[] = [
|
public eventDisplayedColumns: string[] = [
|
||||||
'viewName',
|
'viewName',
|
||||||
@ -59,8 +59,8 @@ export class FailedEventsComponent implements AfterViewInit {
|
|||||||
catchError(() => of([])),
|
catchError(() => of([])),
|
||||||
finalize(() => this.loadingSubject.next(false)),
|
finalize(() => this.loadingSubject.next(false)),
|
||||||
)
|
)
|
||||||
.subscribe((views) => {
|
.subscribe((events) => {
|
||||||
this.eventDataSource = new MatTableDataSource(views);
|
this.eventDataSource = new MatTableDataSource<FailedEvent.AsObject>(events);
|
||||||
this.eventDataSource.paginator = this.eventPaginator;
|
this.eventDataSource.paginator = this.eventPaginator;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,45 +1,42 @@
|
|||||||
<div class="max-width-container">
|
<div class="max-width-container">
|
||||||
<h1 class="views-title">{{ 'IAM.VIEWS.TITLE' | translate }}</h1>
|
<h1 class="views-title">{{ 'IAM.VIEWS.TITLE' | translate }}</h1>
|
||||||
<p class="views-desc cnsl-secondary-text">{{'IAM.VIEWS.DESCRIPTION' | translate }}</p>
|
<p class="views-desc cnsl-secondary-text">{{ 'IAM.VIEWS.DESCRIPTION' | translate }}</p>
|
||||||
|
|
||||||
<cnsl-refresh-table *ngIf="dataSource" (refreshed)="loadViews()" [dataSize]="dataSource.data.length"
|
<cnsl-refresh-table (refreshed)="loadViews()" [dataSize]="dataSource.data.length" [loading]="loading$ | async">
|
||||||
[loading]="loading$ | async">
|
<table [dataSource]="dataSource" mat-table class="table views-table" aria-label="Views" matSort>
|
||||||
|
<ng-container matColumnDef="viewName">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'IAM.VIEWS.VIEWNAME' | translate }}</th>
|
||||||
|
<td mat-cell *matCellDef="let view">{{ view.viewName }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<table [dataSource]="dataSource" mat-table class="table views-table" aria-label="Views" matSort>
|
<ng-container matColumnDef="database">
|
||||||
<ng-container matColumnDef="viewName">
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'IAM.VIEWS.DATABASE' | translate }}</th>
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'IAM.VIEWS.VIEWNAME' | translate }} </th>
|
<td mat-cell *matCellDef="let view">{{ view.database }}</td>
|
||||||
<td mat-cell *matCellDef="let view"> {{view.viewName}} </td>
|
</ng-container>
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="database">
|
<ng-container matColumnDef="sequence">
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'IAM.VIEWS.DATABASE' | translate }} </th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.VIEWS.SEQUENCE' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let view"> {{view.database}} </td>
|
<td mat-cell *matCellDef="let view">{{ view.processedSequence }}</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="sequence">
|
<ng-container matColumnDef="eventTimestamp">
|
||||||
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.VIEWS.SEQUENCE' | translate }} </th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.VIEWS.EVENTTIMESTAMP' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let view"> {{view.processedSequence}} </td>
|
<td mat-cell *matCellDef="let view">
|
||||||
</ng-container>
|
<span>{{ view?.eventTimestamp | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="eventTimestamp">
|
<ng-container matColumnDef="lastSuccessfulSpoolerRun">
|
||||||
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.VIEWS.EVENTTIMESTAMP' | translate }} </th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.VIEWS.LASTSPOOL' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let view">
|
<td mat-cell *matCellDef="let view">
|
||||||
<span>{{view?.eventTimestamp | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
|
<span>{{ view?.lastSuccessfulSpoolerRun | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="lastSuccessfulSpoolerRun">
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.VIEWS.LASTSPOOL' | translate }} </th>
|
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||||
<td mat-cell *matCellDef="let view">
|
</table>
|
||||||
<span>{{view?.lastSuccessfulSpoolerRun | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'
|
<cnsl-paginator #paginator class="paginator" [hidePagination]="true" [length]="dataSource.data.length || 0">
|
||||||
}}</span>
|
</cnsl-paginator>
|
||||||
</td>
|
</cnsl-refresh-table>
|
||||||
</ng-container>
|
</div>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
|
||||||
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
|
||||||
</table>
|
|
||||||
<cnsl-paginator #paginator class="paginator" [hidePagination]="true" [length]="dataSource.data.length || 0">
|
|
||||||
</cnsl-paginator>
|
|
||||||
</cnsl-refresh-table>
|
|
||||||
</div>
|
|
||||||
|
@ -17,7 +17,7 @@ export class IamViewsComponent implements AfterViewInit {
|
|||||||
@ViewChild(MatSort) sort!: MatSort;
|
@ViewChild(MatSort) sort!: MatSort;
|
||||||
|
|
||||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
||||||
public dataSource!: MatTableDataSource<View.AsObject>;
|
public dataSource: MatTableDataSource<View.AsObject> = new MatTableDataSource<View.AsObject>([]);
|
||||||
|
|
||||||
public displayedColumns: string[] = ['viewName', 'database', 'sequence', 'eventTimestamp', 'lastSuccessfulSpoolerRun'];
|
public displayedColumns: string[] = ['viewName', 'database', 'sequence', 'eventTimestamp', 'lastSuccessfulSpoolerRun'];
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ export class IamViewsComponent implements AfterViewInit {
|
|||||||
finalize(() => this.loadingSubject.next(false)),
|
finalize(() => this.loadingSubject.next(false)),
|
||||||
)
|
)
|
||||||
.subscribe((views) => {
|
.subscribe((views) => {
|
||||||
this.dataSource = new MatTableDataSource(views);
|
this.dataSource = new MatTableDataSource<View.AsObject>(views);
|
||||||
this.dataSource.paginator = this.paginator;
|
this.dataSource.paginator = this.paginator;
|
||||||
this.dataSource.sort = this.sort;
|
this.dataSource.sort = this.sort;
|
||||||
});
|
});
|
||||||
|
@ -31,7 +31,7 @@ export class InstanceSettingsComponent {
|
|||||||
public settingsList: SidenavSetting[] = [
|
public settingsList: SidenavSetting[] = [
|
||||||
GENERAL,
|
GENERAL,
|
||||||
// notifications
|
// notifications
|
||||||
NOTIFICATIONS,
|
{ showWarn: true, ...NOTIFICATIONS },
|
||||||
// login
|
// login
|
||||||
LOGIN,
|
LOGIN,
|
||||||
COMPLEXITY,
|
COMPLEXITY,
|
||||||
|
@ -241,7 +241,12 @@ export class UserTableComponent implements OnInit {
|
|||||||
|
|
||||||
public applySearchQuery(searchQueries: SearchQuery[]): void {
|
public applySearchQuery(searchQueries: SearchQuery[]): void {
|
||||||
this.selection.clear();
|
this.selection.clear();
|
||||||
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize, this.type, searchQueries);
|
this.getData(
|
||||||
|
this.paginator ? this.paginator.pageSize : this.INITIAL_PAGE_SIZE,
|
||||||
|
this.paginator ? this.paginator.pageIndex * this.paginator.pageSize : 0,
|
||||||
|
this.type,
|
||||||
|
searchQueries,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteUser(user: User.AsObject): void {
|
public deleteUser(user: User.AsObject): void {
|
||||||
|
@ -579,9 +579,8 @@ export class AdminService {
|
|||||||
return this.grpcService.admin.getLogNotificationProvider(req, null).then((resp) => resp.toObject());
|
return this.grpcService.admin.getLogNotificationProvider(req, null).then((resp) => resp.toObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFileSystemNotificationProvider(
|
public getFileSystemNotificationProvider(): Promise<GetFileSystemNotificationProviderResponse.AsObject> {
|
||||||
req: GetFileSystemNotificationProviderRequest,
|
const req = new GetFileSystemNotificationProviderRequest();
|
||||||
): Promise<GetFileSystemNotificationProviderResponse.AsObject> {
|
|
||||||
return this.grpcService.admin.getFileSystemNotificationProvider(req, null).then((resp) => resp.toObject());
|
return this.grpcService.admin.getFileSystemNotificationProvider(req, null).then((resp) => resp.toObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -847,7 +847,8 @@
|
|||||||
"USER": "Benutzer",
|
"USER": "Benutzer",
|
||||||
"PASSWORD": "Passwort",
|
"PASSWORD": "Passwort",
|
||||||
"TLS": "Transport Layer Security (TLS)",
|
"TLS": "Transport Layer Security (TLS)",
|
||||||
"SAVED": "Erfolgreich gespeichert."
|
"SAVED": "Erfolgreich gespeichert.",
|
||||||
|
"REQUIREDWARN": "Damit Mails von Ihrer Domain verschickt werden können, müssen Sie Ihre SMTP Einstellungen konfigurieren."
|
||||||
},
|
},
|
||||||
"SMS": {
|
"SMS": {
|
||||||
"TITLE": "SMS Einstellungen",
|
"TITLE": "SMS Einstellungen",
|
||||||
|
@ -847,7 +847,8 @@
|
|||||||
"USER": "User",
|
"USER": "User",
|
||||||
"PASSWORD": "Password",
|
"PASSWORD": "Password",
|
||||||
"TLS": "Transport Layer Security (TLS)",
|
"TLS": "Transport Layer Security (TLS)",
|
||||||
"SAVED": "Saved successfully!"
|
"SAVED": "Saved successfully!",
|
||||||
|
"REQUIREDWARN": "To send notifications from your domain, you have to enter your SMTP data."
|
||||||
},
|
},
|
||||||
"SMS": {
|
"SMS": {
|
||||||
"TITLE": "SMS Settings",
|
"TITLE": "SMS Settings",
|
||||||
|
@ -847,7 +847,8 @@
|
|||||||
"USER": "Utente",
|
"USER": "Utente",
|
||||||
"PASSWORD": "Password",
|
"PASSWORD": "Password",
|
||||||
"TLS": "Transport Layer Security (TLS)",
|
"TLS": "Transport Layer Security (TLS)",
|
||||||
"SAVED": "Salvato con successo!"
|
"SAVED": "Salvato con successo!",
|
||||||
|
"REQUIREDWARN": "Per inviare notifiche dal tuo dominio, devi inserire i tuoi dati SMTP."
|
||||||
},
|
},
|
||||||
"SMS": {
|
"SMS": {
|
||||||
"TITLE": "Impostazioni SMS",
|
"TITLE": "Impostazioni SMS",
|
||||||
|
1
console/src/assets/mdi/shield-alert.svg
Normal file
1
console/src/assets/mdi/shield-alert.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12,1L3,5V11C3,16.55 6.84,21.74 12,23C17.16,21.74 21,16.55 21,11V5M11,7H13V13H11M11,15H13V17H11" /></svg>
|
After Width: | Height: | Size: 390 B |
@ -253,6 +253,7 @@ $caos-dark-theme-background: (
|
|||||||
tooltip: map_get($mat-gray, 700),
|
tooltip: map_get($mat-gray, 700),
|
||||||
infosection: map_get($caos-dark-background, 300),
|
infosection: map_get($caos-dark-background, 300),
|
||||||
warninfosection: #741f2c4a,
|
warninfosection: #741f2c4a,
|
||||||
|
alertinfosection: #92400e50,
|
||||||
successinfosection: map_get($caos-dark-background, 300),
|
successinfosection: map_get($caos-dark-background, 300),
|
||||||
state: map_get($caos-dark-background, 300),
|
state: map_get($caos-dark-background, 300),
|
||||||
state-active: #68cf8340,
|
state-active: #68cf8340,
|
||||||
@ -261,6 +262,7 @@ $caos-dark-theme-background: (
|
|||||||
moz-toolbar: map_get($caos-dark-background, 500),
|
moz-toolbar: map_get($caos-dark-background, 500),
|
||||||
footer: #00000020,
|
footer: #00000020,
|
||||||
metadata-section: #00000020,
|
metadata-section: #00000020,
|
||||||
|
alert: #fbbf24,
|
||||||
);
|
);
|
||||||
|
|
||||||
$caos-light-theme-background: (
|
$caos-light-theme-background: (
|
||||||
@ -287,11 +289,13 @@ $caos-light-theme-background: (
|
|||||||
tooltip: map_get($mat-gray, 700),
|
tooltip: map_get($mat-gray, 700),
|
||||||
infosection: map_get($caos-light-primary, 100),
|
infosection: map_get($caos-light-primary, 100),
|
||||||
warninfosection: #ffc1c1,
|
warninfosection: #ffc1c1,
|
||||||
|
alertinfosection: rgb(251, 191, 36),
|
||||||
successinfosection: #cbf4c9,
|
successinfosection: #cbf4c9,
|
||||||
toolbar: rgba(map_get($caos-light-background, 500), 0.9),
|
toolbar: rgba(map_get($caos-light-background, 500), 0.9),
|
||||||
moz-toolbar: map_get($caos-light-background, 500),
|
moz-toolbar: map_get($caos-light-background, 500),
|
||||||
footer: #00000008,
|
footer: #00000008,
|
||||||
metadata-section: #605f5f08,
|
metadata-section: #605f5f08,
|
||||||
|
alert: rgb(251, 191, 36),
|
||||||
);
|
);
|
||||||
|
|
||||||
$caos-dark-theme-foreground: (
|
$caos-dark-theme-foreground: (
|
||||||
@ -313,6 +317,7 @@ $caos-dark-theme-foreground: (
|
|||||||
slider-off-active: rgba(white, 0.38),
|
slider-off-active: rgba(white, 0.38),
|
||||||
infosection: #f0f0f0,
|
infosection: #f0f0f0,
|
||||||
warninfosection: #ffc1c1,
|
warninfosection: #ffc1c1,
|
||||||
|
alertinfosection: rgb(251, 191, 36),
|
||||||
successinfosection: #cbf4c9,
|
successinfosection: #cbf4c9,
|
||||||
toolbar-items: map-get(map-get($caos-dark-primary, contrast), 500),
|
toolbar-items: map-get(map-get($caos-dark-primary, contrast), 500),
|
||||||
slash: #ffffff6e,
|
slash: #ffffff6e,
|
||||||
@ -337,6 +342,7 @@ $caos-light-theme-foreground: (
|
|||||||
slider-off-active: rgba(black, 0.38),
|
slider-off-active: rgba(black, 0.38),
|
||||||
infosection: #4a4a4a,
|
infosection: #4a4a4a,
|
||||||
warninfosection: #620e0e,
|
warninfosection: #620e0e,
|
||||||
|
alertinfosection: rgb(146, 64, 14),
|
||||||
successinfosection: #0e6245,
|
successinfosection: #0e6245,
|
||||||
toolbar-items: map-get(map-get($caos-light-primary, contrast), 500),
|
toolbar-items: map-get(map-get($caos-light-primary, contrast), 500),
|
||||||
slash: #0000006e,
|
slash: #0000006e,
|
||||||
|
@ -16,10 +16,7 @@
|
|||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"target": "es2015",
|
"target": "es2015",
|
||||||
"module": "es2020",
|
"module": "es2020",
|
||||||
"lib": [
|
"lib": ["es2020", "dom"]
|
||||||
"es2019",
|
|
||||||
"dom"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"strictInjectionParameters": true,
|
"strictInjectionParameters": true,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user