mirror of
https://github.com/zitadel/zitadel.git
synced 2025-06-14 15:38:31 +00:00
fix(console): table pagination, diverse optimizations, lint workspace (#1563)
* show app redirect issues, action layout * refactor pagination * tos, privacy * new paginator everywhere * layout width and table optim * lint pt1 * lint config, ts * stylelint * chore(deps-dev): bump @angular/cli from 11.2.7 to 11.2.8 in /console (#1566) * fix: remove app name check on ChangeAPIApplication (#1561) * fix: remove app name check on ChangeAPIApplication * fix APIConfigInvalid message * chore(workflow): ignore tags for docs and codecov flows (#1564) * chore(deps-dev): bump @angular/cli from 11.2.7 to 11.2.8 in /console Bumps [@angular/cli](https://github.com/angular/angular-cli) from 11.2.7 to 11.2.8. - [Release notes](https://github.com/angular/angular-cli/releases) - [Commits](https://github.com/angular/angular-cli/compare/v11.2.7...v11.2.8) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump jasmine-spec-reporter from 6.0.0 to 7.0.0 in /console (#1573) * fix: remove app name check on ChangeAPIApplication (#1561) * fix: remove app name check on ChangeAPIApplication * fix APIConfigInvalid message * chore(workflow): ignore tags for docs and codecov flows (#1564) * chore(deps-dev): bump jasmine-spec-reporter in /console Bumps [jasmine-spec-reporter](https://github.com/bcaudan/jasmine-spec-reporter) from 6.0.0 to 7.0.0. - [Release notes](https://github.com/bcaudan/jasmine-spec-reporter/releases) - [Changelog](https://github.com/bcaudan/jasmine-spec-reporter/blob/master/CHANGELOG.md) - [Commits](https://github.com/bcaudan/jasmine-spec-reporter/compare/v6.0.0...v7.0.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular-devkit/build-angular from 0.1102.7 to 0.1102.8 in /console (#1574) * fix: remove app name check on ChangeAPIApplication (#1561) * fix: remove app name check on ChangeAPIApplication * fix APIConfigInvalid message * chore(workflow): ignore tags for docs and codecov flows (#1564) * chore(deps-dev): bump @angular-devkit/build-angular in /console Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.1102.7 to 0.1102.8. - [Release notes](https://github.com/angular/angular-cli/releases) - [Commits](https://github.com/angular/angular-cli/commits) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> * chore(deps): bump @types/file-saver from 2.0.1 to 2.0.2 in /console (#1576) * fix: remove app name check on ChangeAPIApplication (#1561) * fix: remove app name check on ChangeAPIApplication * fix APIConfigInvalid message * chore(workflow): ignore tags for docs and codecov flows (#1564) * chore(deps): bump @types/file-saver from 2.0.1 to 2.0.2 in /console Bumps [@types/file-saver](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/file-saver) from 2.0.1 to 2.0.2. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/file-saver) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular/language-service from 11.2.8 to 11.2.9 in /console (#1567) * fix: remove app name check on ChangeAPIApplication (#1561) * fix: remove app name check on ChangeAPIApplication * fix APIConfigInvalid message * chore(workflow): ignore tags for docs and codecov flows (#1564) * chore(deps-dev): bump @angular/language-service in /console Bumps [@angular/language-service](https://github.com/angular/angular/tree/HEAD/packages/language-service) from 11.2.8 to 11.2.9. - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/11.2.9/packages/language-service) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * update protobuf, libphone * chore(deps): bump rxjs from 6.6.3 to 6.6.7 in /console (#1488) Bumps [rxjs](https://github.com/reactivex/rxjs) from 6.6.3 to 6.6.7. - [Release notes](https://github.com/reactivex/rxjs/releases) - [Changelog](https://github.com/ReactiveX/rxjs/blob/6.6.7/CHANGELOG.md) - [Commits](https://github.com/reactivex/rxjs/compare/6.6.3...6.6.7) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @types/jasmine from 3.6.3 to 3.6.9 in /console (#1485) Bumps [@types/jasmine](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jasmine) from 3.6.3 to 3.6.9. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jasmine) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> * chore(deps-dev): bump jasmine-core from 3.6.0 to 3.7.1 in /console (#1445) Bumps [jasmine-core](https://github.com/jasmine/jasmine) from 3.6.0 to 3.7.1. - [Release notes](https://github.com/jasmine/jasmine/releases) - [Changelog](https://github.com/jasmine/jasmine/blob/main/RELEASE.md) - [Commits](https://github.com/jasmine/jasmine/compare/v3.6.0...v3.7.1) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
parent
b0681a0bbe
commit
56b527060b
@ -74,21 +74,19 @@ RUN build/console/generate-grpc.sh
|
|||||||
FROM scratch as npm-copy
|
FROM scratch as npm-copy
|
||||||
COPY --from=npm-base /console/src/app/proto/generated ./console/src/app/proto/generated
|
COPY --from=npm-base /console/src/app/proto/generated ./console/src/app/proto/generated
|
||||||
|
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
## anular dev build
|
## angular dev build
|
||||||
#######################
|
#######################
|
||||||
FROM npm-base as dev-angular-build
|
FROM npm-base as dev-angular-build
|
||||||
RUN npm install -g @angular/cli
|
RUN npm install -g @angular/cli
|
||||||
|
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
## anular prod build
|
## angular lint workspace and prod build
|
||||||
#######################
|
#######################
|
||||||
FROM npm-base as prod-angular-build
|
FROM npm-base as prod-angular-build
|
||||||
|
RUN npm run lint
|
||||||
RUN npm run prodbuild
|
RUN npm run prodbuild
|
||||||
|
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
## Go dependencies
|
## Go dependencies
|
||||||
## Speed up this step by mounting your local go mod pkg directory
|
## Speed up this step by mounting your local go mod pkg directory
|
||||||
|
@ -115,7 +115,8 @@
|
|||||||
"tsconfig.spec.json"
|
"tsconfig.spec.json"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"**/node_modules/**"
|
"**/node_modules/**",
|
||||||
|
"**/proto/generated/**"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
628
console/package-lock.json
generated
628
console/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@
|
|||||||
"@angular/service-worker": "~11.0.0",
|
"@angular/service-worker": "~11.0.0",
|
||||||
"@ngx-translate/core": "^13.0.0",
|
"@ngx-translate/core": "^13.0.0",
|
||||||
"@ngx-translate/http-loader": "^6.0.0",
|
"@ngx-translate/http-loader": "^6.0.0",
|
||||||
"@types/file-saver": "^2.0.1",
|
"@types/file-saver": "^2.0.2",
|
||||||
"@types/google-protobuf": "^3.7.4",
|
"@types/google-protobuf": "^3.7.4",
|
||||||
"@types/uuid": "^8.3.0",
|
"@types/uuid": "^8.3.0",
|
||||||
"angular-oauth2-oidc": "^10.0.3",
|
"angular-oauth2-oidc": "^10.0.3",
|
||||||
@ -32,29 +32,29 @@
|
|||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"google-proto-files": "^2.4.0",
|
"google-proto-files": "^2.4.0",
|
||||||
"google-protobuf": "^3.15.7",
|
"google-protobuf": "^3.15.8",
|
||||||
"grpc": "^1.24.5",
|
"grpc": "^1.24.5",
|
||||||
"grpc-web": "^1.2.1",
|
"grpc-web": "^1.2.1",
|
||||||
"libphonenumber-js": "^1.9.13",
|
"libphonenumber-js": "^1.9.16",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"ngx-quicklink": "^0.2.6",
|
"ngx-quicklink": "^0.2.6",
|
||||||
"rxjs": "~6.6.3",
|
"rxjs": "~6.6.7",
|
||||||
"ts-protoc-gen": "^0.14.0",
|
"ts-protoc-gen": "^0.14.0",
|
||||||
"tslib": "^2.2.0",
|
"tslib": "^2.2.0",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"zone.js": "~0.11.3"
|
"zone.js": "~0.11.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/cli": "~11.2.7",
|
"@angular-devkit/build-angular": "~0.1102.8",
|
||||||
"@angular-devkit/build-angular": "~0.1102.7",
|
"@angular/cli": "~11.2.8",
|
||||||
"@angular/compiler-cli": "~11.0.0",
|
"@angular/compiler-cli": "~11.0.0",
|
||||||
"@types/jasmine": "~3.6.3",
|
"@types/jasmine": "~3.6.9",
|
||||||
"@angular/language-service": "~11.2.8",
|
"@angular/language-service": "~11.2.9",
|
||||||
"@types/jasminewd2": "~2.0.3",
|
"@types/jasminewd2": "~2.0.3",
|
||||||
"@types/node": "^14.14.37",
|
"@types/node": "^14.14.37",
|
||||||
"codelyzer": "^6.0.0",
|
"codelyzer": "^6.0.0",
|
||||||
"jasmine-core": "~3.6.0",
|
"jasmine-core": "~3.7.1",
|
||||||
"jasmine-spec-reporter": "~6.0.0",
|
"jasmine-spec-reporter": "~7.0.0",
|
||||||
"karma": "~6.3.2",
|
"karma": "~6.3.2",
|
||||||
"karma-chrome-launcher": "~3.1.0",
|
"karma-chrome-launcher": "~3.1.0",
|
||||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||||
|
@ -18,7 +18,7 @@ const routes: Routes = [
|
|||||||
canActivate: [AuthGuard, RoleGuard],
|
canActivate: [AuthGuard, RoleGuard],
|
||||||
data: {
|
data: {
|
||||||
roles: ['iam.write'],
|
roles: ['iam.write'],
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'granted-projects',
|
path: 'granted-projects',
|
||||||
|
@ -179,8 +179,12 @@
|
|||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
|
|
||||||
<div class="toc-line">
|
<div class="toc-line">
|
||||||
<a class="toc" href="https://zitadel.ch/pdf/agb.pdf" alt="Terms and Conditions"
|
<a class="toc" [href]="language == 'de' ? 'https://zitadel.ch/pdf/agb.pdf' : 'https://zitadel.ch/pdf/tos.pdf'" alt="Terms and Conditions"
|
||||||
target="_blank">{{'MENU.TOC'
|
target="_blank">{{'MENU.TOS'
|
||||||
|
| translate}}</a>
|
||||||
|
<span class="slash">|</span>
|
||||||
|
<a class="toc" [href]="language == 'de' ? 'https://zitadel.ch/pdf/datenschutz.pdf' : 'https://zitadel.ch/pdf/privacy.pdf'" alt="Terms and Conditions"
|
||||||
|
target="_blank">{{'MENU.PRIVACY'
|
||||||
| translate}}</a>
|
| translate}}</a>
|
||||||
<span> </span>
|
<span> </span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
|
|
||||||
.org-button {
|
.org-button {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding-right: .5rem;
|
padding-right: .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
@ -168,36 +168,18 @@
|
|||||||
margin: 2rem 2rem;
|
margin: 2rem 2rem;
|
||||||
|
|
||||||
.toc {
|
.toc {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--grey);
|
color: var(--grey);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sp-status {
|
.slash {
|
||||||
font-size: 12px;
|
margin: 0 .5rem;
|
||||||
color: var(--grey);
|
color: var(--grey);
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sp-status .sp-status-badge.sp-status-ok {
|
|
||||||
background: darkgreen;
|
|
||||||
}
|
|
||||||
.sp-status .sp-status-badge.sp-status-scheduled {
|
|
||||||
background: darkblue;
|
|
||||||
}
|
|
||||||
.sp-status .sp-status-badge.sp-status-minor {
|
|
||||||
background: darkorange;
|
|
||||||
}
|
|
||||||
.sp-status .sp-status-badge.sp-status-major {
|
|
||||||
background: darkred;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ export class AppComponent implements OnDestroy {
|
|||||||
private orgSub: Subscription = new Subscription();
|
private orgSub: Subscription = new Subscription();
|
||||||
|
|
||||||
public hideAdminWarn: boolean = true;
|
public hideAdminWarn: boolean = true;
|
||||||
|
public language: string = 'en';
|
||||||
constructor(
|
constructor(
|
||||||
public viewPortScroller: ViewportScroller,
|
public viewPortScroller: ViewportScroller,
|
||||||
@Inject('windowObject') public window: Window,
|
@Inject('windowObject') public window: Window,
|
||||||
@ -196,6 +197,7 @@ export class AppComponent implements OnDestroy {
|
|||||||
|
|
||||||
this.translate.onLangChange.subscribe((language: LangChangeEvent) => {
|
this.translate.onLangChange.subscribe((language: LangChangeEvent) => {
|
||||||
this.document.documentElement.lang = language.lang;
|
this.document.documentElement.lang = language.lang;
|
||||||
|
this.language = language.lang;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.filterControl.valueChanges.pipe(debounceTime(300)).subscribe(value => {
|
this.filterControl.valueChanges.pipe(debounceTime(300)).subscribe(value => {
|
||||||
@ -266,8 +268,12 @@ export class AppComponent implements OnDestroy {
|
|||||||
const cropped = navigator.language.split('-')[0] ?? 'en';
|
const cropped = navigator.language.split('-')[0] ?? 'en';
|
||||||
const fallbackLang = cropped.match(/en|de/) ? cropped : 'en';
|
const fallbackLang = cropped.match(/en|de/) ? cropped : 'en';
|
||||||
|
|
||||||
const lang = userprofile?.human?.profile?.preferredLanguage.match(/en|de/) ? userprofile.human.profile?.preferredLanguage : fallbackLang;
|
const lang =
|
||||||
|
userprofile?.human?.profile?.preferredLanguage.match(/en|de/) ?
|
||||||
|
userprofile.human.profile?.preferredLanguage :
|
||||||
|
fallbackLang;
|
||||||
this.translate.use(lang);
|
this.translate.use(lang);
|
||||||
|
this.language = lang;
|
||||||
this.document.documentElement.lang = lang;
|
this.document.documentElement.lang = lang;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -4,8 +4,8 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
|||||||
import { KeyType } from 'src/app/proto/generated/zitadel/auth_n_key_pb';
|
import { KeyType } from 'src/app/proto/generated/zitadel/auth_n_key_pb';
|
||||||
|
|
||||||
export enum AddKeyDialogType {
|
export enum AddKeyDialogType {
|
||||||
MACHINE = "MACHINE",
|
MACHINE = 'MACHINE',
|
||||||
AUTHNKEY = "AUTHNKEY",
|
AUTHNKEY = 'AUTHNKEY',
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -100,8 +100,7 @@ export class MemberCreateDialogComponent {
|
|||||||
if (project.projectId && project.grantId) {
|
if (project.projectId && project.grantId) {
|
||||||
this.projectId = project.projectId;
|
this.projectId = project.projectId;
|
||||||
this.grantId = project.grantId;
|
this.grantId = project.grantId;
|
||||||
}
|
} else if (project.id) {
|
||||||
else if (project.id) {
|
|
||||||
this.projectId = project.id;
|
this.projectId = project.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,46 +10,46 @@
|
|||||||
/* stylelint-enable */
|
/* stylelint-enable */
|
||||||
|
|
||||||
.cnsl-app-card {
|
.cnsl-app-card {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
animation: all .2s;
|
animation: all .2s;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
height: 80px;
|
height: 80px;
|
||||||
width: 80px;
|
width: 80px;
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
background-color: $primary-dark;
|
background-color: $primary-dark;
|
||||||
transition: background-color box-shadow .3s ease-in;
|
transition: background-color box-shadow .3s ease-in;
|
||||||
|
|
||||||
&.web {
|
&.web {
|
||||||
background-color: rgb(80, 110, 110);
|
background-color: rgb(80, 110, 110);
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
|
||||||
|
|
||||||
&.native {
|
|
||||||
background-color: #595d80;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.useragent {
|
|
||||||
background-color: #6a506e;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.api {
|
|
||||||
background-color: #333;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.native {
|
||||||
|
background-color: #595d80;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.useragent {
|
||||||
|
background-color: #6a506e;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.api {
|
||||||
|
background-color: #333;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,14 @@
|
|||||||
@import '~@angular/material/theming';
|
@import '~@angular/material/theming';
|
||||||
|
|
||||||
.radio-button-wrapper {
|
.radio-button-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-bottom: .5rem;
|
padding-bottom: .5rem;
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin app-auth-method-radio-theme($theme) {
|
@mixin app-auth-method-radio-theme($theme) {
|
||||||
@ -17,7 +17,7 @@
|
|||||||
$primary-color: mat-color($primary, 500);
|
$primary-color: mat-color($primary, 500);
|
||||||
$is-dark-theme: map-get($theme, is-dark);
|
$is-dark-theme: map-get($theme, is-dark);
|
||||||
|
|
||||||
input[type="radio"]{
|
input[type="radio"] {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
display: none;
|
display: none;
|
||||||
@ -27,7 +27,7 @@
|
|||||||
border-color: if($is-dark-theme, white, var(--grey));
|
border-color: if($is-dark-theme, white, var(--grey));
|
||||||
|
|
||||||
.cnsl-radio-header span {
|
.cnsl-radio-header span {
|
||||||
color: if($is-dark-theme, white, white);
|
color: if($is-dark-theme, white, white);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,98 +43,98 @@
|
|||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
|
box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
|
||||||
|
|
||||||
&.first {
|
&.first {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.last {
|
&.last {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.recommended {
|
.recommended {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateY(50%) translateX(-50%);
|
transform: translateY(50%) translateX(-50%);
|
||||||
border-radius: 50vw;
|
border-radius: 50vw;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
background: white;
|
background: white;
|
||||||
color: black;
|
color: black;
|
||||||
padding: 3px 1rem;
|
padding: 3px 1rem;
|
||||||
box-shadow: 0 0 6px rgb(0 0 0 / 10%);
|
box-shadow: 0 0 6px rgb(0 0 0 / 10%);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
&.not {
|
&.not {
|
||||||
background: rgb(144 75 75);
|
background: rgb(144 75 75);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.cnsl-radio-header {
|
.cnsl-radio-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: rgb(80, 110, 110);
|
background: rgb(80, 110, 110);
|
||||||
border-top-left-radius: 6px;
|
border-top-left-radius: 6px;
|
||||||
border-top-right-radius: 6px;
|
border-top-right-radius: 6px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.current {
|
.current {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: .5rem;
|
bottom: .5rem;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
display: block;
|
display: block;
|
||||||
color: #ffffff60;
|
color: #ffffff60;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
margin: 2rem;
|
margin: 2rem;
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
color: if($is-dark-theme,#21222450, #ffffff50);
|
color: if($is-dark-theme, #21222450, #ffffff50);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.type-desc {
|
.type-desc {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--grey);
|
color: var(--grey);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fill-space {
|
.fill-space {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-specs {
|
.app-specs {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 1rem 0;
|
padding: 1rem 0;
|
||||||
margin: 0 1rem;
|
margin: 0 1rem;
|
||||||
|
|
||||||
.row {
|
.row {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--grey);
|
color: var(--grey);
|
||||||
margin: 3px 0;
|
margin: 3px 0;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
|
||||||
|
|
||||||
:first-child {
|
|
||||||
margin-right: 1rem;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:first-child {
|
||||||
|
margin-right: 1rem;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ export interface RadioItemAuthType {
|
|||||||
key: string;
|
key: string;
|
||||||
titleI18nKey: string;
|
titleI18nKey: string;
|
||||||
descI18nKey: string;
|
descI18nKey: string;
|
||||||
disabled: boolean,
|
disabled: boolean;
|
||||||
prefix: string;
|
prefix: string;
|
||||||
background: string;
|
background: string;
|
||||||
responseType?: OIDCResponseType;
|
responseType?: OIDCResponseType;
|
||||||
@ -36,4 +36,4 @@ export class AppAuthMethodRadioComponent {
|
|||||||
public emitChange(): void {
|
public emitChange(): void {
|
||||||
this.selectedMethod.emit(this.selected);
|
this.selectedMethod.emit(this.selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,18 +2,18 @@
|
|||||||
@import '~@angular/material/theming';
|
@import '~@angular/material/theming';
|
||||||
|
|
||||||
.radio-button-wrapper {
|
.radio-button-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin: 0 -0.5rem;
|
margin: 0 -.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin app-type-radio-theme($theme) {
|
@mixin app-type-radio-theme($theme) {
|
||||||
$primary: map-get($theme, primary);
|
$primary: map-get($theme, primary);
|
||||||
$primary-color: mat-color($primary, 500);
|
$primary-color: mat-color($primary, 500);
|
||||||
$is-dark-theme: map-get($theme, is-dark);
|
$is-dark-theme: map-get($theme, is-dark);
|
||||||
|
|
||||||
input[type="radio"]{
|
input[type="radio"] {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
display: none;
|
display: none;
|
||||||
@ -23,7 +23,7 @@
|
|||||||
border-color: if($is-dark-theme, white, var(--grey));
|
border-color: if($is-dark-theme, white, var(--grey));
|
||||||
|
|
||||||
.cnsl-type-radio-header span {
|
.cnsl-type-radio-header span {
|
||||||
color: if($is-dark-theme, white, white);
|
color: if($is-dark-theme, white, white);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,29 +40,29 @@
|
|||||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
|
box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
|
||||||
|
|
||||||
.cnsl-type-radio-header {
|
.cnsl-type-radio-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background: rgb(80, 110, 110);
|
background: rgb(80, 110, 110);
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
border-top-left-radius: 6px;
|
border-top-left-radius: 6px;
|
||||||
border-top-right-radius: 6px;
|
border-top-right-radius: 6px;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
margin: 2rem;
|
margin: 2rem;
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
color: if($is-dark-theme,#21222450, #ffffff50);
|
color: if($is-dark-theme, #21222450, #ffffff50);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.type-desc {
|
.type-desc {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--grey);
|
color: var(--grey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,4 @@ export class AppTypeRadioComponent {
|
|||||||
public emitChange(): void {
|
public emitChange(): void {
|
||||||
this.selectedType.emit(this.selected);
|
this.selectedType.emit(this.selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,123 +21,120 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@mixin changes-theme($theme) {
|
@mixin changes-theme($theme) {
|
||||||
$is-dark-theme: map-get($theme, is-dark);
|
$is-dark-theme: map-get($theme, is-dark);
|
||||||
|
|
||||||
.scroll-container {
|
.scroll-container {
|
||||||
max-height: 50vh;
|
max-height: 50vh;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
border-bottom: 1px solid if($is-dark-theme, #303131, #e3e8ee);
|
border-bottom: 1px solid if($is-dark-theme, #303131, #e3e8ee);
|
||||||
/* stylelint-enable */
|
margin-bottom: .5rem;
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
|
|
||||||
.date {
|
.date {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 0.8rem;
|
font-size: .8rem;
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: .5rem;
|
margin-bottom: .5rem;
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
display: block;
|
|
||||||
padding: 10px 0;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
|
|
||||||
.row {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
.spacer {
|
|
||||||
width: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-top: -0.5rem;
|
|
||||||
|
|
||||||
.action {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 32px;
|
|
||||||
display: inline-block;
|
|
||||||
height: 1.2rem;
|
|
||||||
line-height: 1.2rem;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
color: var(--grey);
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
flex: 1;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msg {
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.restore {
|
|
||||||
visibility: hidden;
|
|
||||||
display: none;
|
|
||||||
opacity: 0;
|
|
||||||
margin-left: 1rem;
|
|
||||||
transform: opacity 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.restore {
|
|
||||||
visibility: visible;
|
|
||||||
display: inline-block;
|
|
||||||
opacity: 1;
|
|
||||||
color: #81868a;
|
|
||||||
|
|
||||||
&[disabled] {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* stylelint-disable */
|
|
||||||
$primary: map-get($theme, primary);
|
|
||||||
$primary-dark: mat-color($primary, A800);
|
|
||||||
/* stylelint-enable */
|
|
||||||
|
|
||||||
&.change-item-back {
|
|
||||||
background-color: rgba($primary-dark, .93);
|
|
||||||
transition: background-color .3s cubic-bezier(.645, .045, .355, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sp-wrapper {
|
|
||||||
padding: .5rem;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.end-container {
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--grey);
|
|
||||||
font-size: 14px;
|
|
||||||
margin: 1rem 0 1rem 0;
|
|
||||||
display: block;
|
|
||||||
color: var(--grey);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
.item {
|
||||||
|
display: block;
|
||||||
|
padding: 10px 0;
|
||||||
|
font-size: .8rem;
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.spacer {
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: -.5rem;
|
||||||
|
|
||||||
|
.action {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 32px;
|
||||||
|
display: inline-block;
|
||||||
|
height: 1.2rem;
|
||||||
|
line-height: 1.2rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
flex: 1;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: .8rem;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.restore {
|
||||||
|
visibility: hidden;
|
||||||
|
display: none;
|
||||||
|
opacity: 0;
|
||||||
|
margin-left: 1rem;
|
||||||
|
transform: opacity .2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.restore {
|
||||||
|
visibility: visible;
|
||||||
|
display: inline-block;
|
||||||
|
opacity: 1;
|
||||||
|
color: #81868a;
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stylelint-disable */
|
||||||
|
$primary: map-get($theme, primary);
|
||||||
|
$primary-dark: mat-color($primary, A800);
|
||||||
|
/* stylelint-enable */
|
||||||
|
|
||||||
|
&.change-item-back {
|
||||||
|
background-color: rgba($primary-dark, .93);
|
||||||
|
transition: background-color .3s cubic-bezier(.645, .045, .355, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sp-wrapper {
|
||||||
|
padding: .5rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.end-container {
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 1rem 0 1rem 0;
|
||||||
|
display: block;
|
||||||
|
color: var(--grey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -23,7 +23,7 @@ export enum ChangeType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface MappedChange {
|
export interface MappedChange {
|
||||||
key: string,
|
key: string;
|
||||||
values: Array<{
|
values: Array<{
|
||||||
data: any[];
|
data: any[];
|
||||||
dates: Timestamp.AsObject[];
|
dates: Timestamp.AsObject[];
|
||||||
@ -34,7 +34,11 @@ export interface MappedChange {
|
|||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListChanges = ListMyUserChangesResponse.AsObject | ListUserChangesResponse.AsObject | ListProjectChangesResponse.AsObject | ListOrgChangesResponse.AsObject | ListAppChangesResponse.AsObject;
|
type ListChanges = ListMyUserChangesResponse.AsObject |
|
||||||
|
ListUserChangesResponse.AsObject |
|
||||||
|
ListProjectChangesResponse.AsObject |
|
||||||
|
ListOrgChangesResponse.AsObject |
|
||||||
|
ListAppChangesResponse.AsObject;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-changes',
|
selector: 'app-changes',
|
||||||
@ -171,11 +175,14 @@ export class ChangesComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mapChanges(changes: Change.AsObject[]) {
|
private mapChanges(changes: Change.AsObject[]): {
|
||||||
|
key: string; values: any[];
|
||||||
|
}[] {
|
||||||
const splitted: { [editorId: string]: any[]; } = {};
|
const splitted: { [editorId: string]: any[]; } = {};
|
||||||
changes.forEach((change) => {
|
changes.forEach((change) => {
|
||||||
if (change.changeDate) {
|
if (change.changeDate) {
|
||||||
const index = `${this.getDateString(change.changeDate)}`;//`${this.getDateString(change.changeDate)}:${change.editorId}`;
|
const index = `${this.getDateString(change.changeDate)}`;
|
||||||
|
// `${this.getDateString(change.changeDate)}:${change.editorId}`;
|
||||||
|
|
||||||
if (index) {
|
if (index) {
|
||||||
if (splitted[index]) {
|
if (splitted[index]) {
|
||||||
@ -209,7 +216,7 @@ export class ChangesComponent implements OnInit, OnDestroy {
|
|||||||
// data: [change.data],
|
// data: [change.data],
|
||||||
eventTypes: [change.eventType],
|
eventTypes: [change.eventType],
|
||||||
sequences: [change.sequence],
|
sequences: [change.sequence],
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,7 +233,7 @@ export class ChangesComponent implements OnInit, OnDestroy {
|
|||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDateString(ts: Timestamp.AsObject) {
|
getDateString(ts: Timestamp.AsObject): string {
|
||||||
const date = new Date(ts.seconds * 1000 + ts.nanos / 1000 / 1000);
|
const date = new Date(ts.seconds * 1000 + ts.nanos / 1000 / 1000);
|
||||||
return date.getUTCFullYear() + this.pad(date.getUTCMonth() + 1) + this.pad(date.getUTCDate());
|
return date.getUTCFullYear() + this.pad(date.getUTCMonth() + 1) + this.pad(date.getUTCDate());
|
||||||
}
|
}
|
||||||
@ -243,10 +250,10 @@ export class ChangesComponent implements OnInit, OnDestroy {
|
|||||||
// Order by ascending property value
|
// Order by ascending property value
|
||||||
valueAscOrder = (a: KeyValue<number, string>, b: KeyValue<number, string>): number => {
|
valueAscOrder = (a: KeyValue<number, string>, b: KeyValue<number, string>): number => {
|
||||||
return a.value.localeCompare(b.value);
|
return a.value.localeCompare(b.value);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Order by descending property key
|
// Order by descending property key
|
||||||
keyDescOrder = (a: KeyValue<number, string>, b: KeyValue<number, string>): number => {
|
keyDescOrder = (a: KeyValue<number, string>, b: KeyValue<number, string>): number => {
|
||||||
return a.key > b.key ? -1 : (b.key > a.key ? 1 : 0);
|
return a.key > b.key ? -1 : (b.key > a.key ? 1 : 0);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ import { ChangesComponent } from './changes.component';
|
|||||||
LocalizedDatePipeModule,
|
LocalizedDatePipeModule,
|
||||||
TimestampToDatePipeModule,
|
TimestampToDatePipeModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
AvatarModule
|
AvatarModule,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
ChangesComponent,
|
ChangesComponent,
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
<mat-paginator #paginator class="paginator" [length]="keyResult?.details?.totalResult || 0" [pageSize]="10"
|
<cnsl-paginator #paginator class="paginator" [timestamp]="keyResult?.details?.viewTimestamp" [length]="keyResult?.details?.totalResult || 0" [pageSize]="10"
|
||||||
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
|
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></cnsl-paginator>
|
||||||
</div>
|
</div>
|
||||||
</app-refresh-table>
|
</app-refresh-table>
|
@ -1,7 +1,6 @@
|
|||||||
import { SelectionModel } from '@angular/cdk/collections';
|
import { SelectionModel } from '@angular/cdk/collections';
|
||||||
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
||||||
@ -14,6 +13,8 @@ import { ListAppKeysResponse } from 'src/app/proto/generated/zitadel/management_
|
|||||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
|
import { PageEvent, PaginatorComponent } from '../paginator/paginator.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-client-keys',
|
selector: 'app-client-keys',
|
||||||
templateUrl: './client-keys.component.html',
|
templateUrl: './client-keys.component.html',
|
||||||
@ -23,7 +24,7 @@ export class ClientKeysComponent implements OnInit {
|
|||||||
@Input() projectId!: string;
|
@Input() projectId!: string;
|
||||||
@Input() appId!: string;
|
@Input() appId!: string;
|
||||||
|
|
||||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||||
public dataSource: MatTableDataSource<Key.AsObject> = new MatTableDataSource<Key.AsObject>();
|
public dataSource: MatTableDataSource<Key.AsObject> = new MatTableDataSource<Key.AsObject>();
|
||||||
public selection: SelectionModel<Key.AsObject> = new SelectionModel<Key.AsObject>(true, []);
|
public selection: SelectionModel<Key.AsObject> = new SelectionModel<Key.AsObject>(true, []);
|
||||||
public keyResult!: ListAppKeysResponse.AsObject;
|
public keyResult!: ListAppKeysResponse.AsObject;
|
||||||
@ -95,7 +96,12 @@ export class ClientKeysComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type) {
|
if (type) {
|
||||||
return this.mgmtService.addAppKey(this.projectId, this.appId, type, date ? date : undefined).then((response) => {
|
return this.mgmtService.addAppKey(
|
||||||
|
this.projectId,
|
||||||
|
this.appId,
|
||||||
|
type,
|
||||||
|
date ? date : undefined,
|
||||||
|
).then((response) => {
|
||||||
if (response) {
|
if (response) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.refreshPage();
|
this.refreshPage();
|
||||||
@ -104,7 +110,7 @@ export class ClientKeysComponent implements OnInit {
|
|||||||
this.dialog.open(ShowKeyDialogComponent, {
|
this.dialog.open(ShowKeyDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
key: response,
|
key: response,
|
||||||
type: AddKeyDialogType.AUTHNKEY
|
type: AddKeyDialogType.AUTHNKEY,
|
||||||
},
|
},
|
||||||
width: '400px',
|
width: '400px',
|
||||||
});
|
});
|
||||||
|
@ -5,24 +5,24 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
|
||||||
import { CardModule } from '../card/card.module';
|
|
||||||
import { InputModule } from '../input/input.module';
|
|
||||||
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
|
||||||
|
|
||||||
import { ClientKeysComponent } from './client-keys.component';
|
|
||||||
import { ShowKeyDialogModule } from '../show-key-dialog/show-key-dialog.module';
|
|
||||||
import { AddKeyDialogModule } from 'src/app/modules/add-key-dialog/add-key-dialog.module';
|
import { AddKeyDialogModule } from 'src/app/modules/add-key-dialog/add-key-dialog.module';
|
||||||
import { RouterModule } from '@angular/router';
|
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 { 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 { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
|
||||||
|
|
||||||
|
import { CardModule } from '../card/card.module';
|
||||||
|
import { InputModule } from '../input/input.module';
|
||||||
|
import { PaginatorModule } from '../paginator/paginator.module';
|
||||||
|
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
||||||
|
import { ShowKeyDialogModule } from '../show-key-dialog/show-key-dialog.module';
|
||||||
|
import { ClientKeysComponent } from './client-keys.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -37,7 +37,7 @@ import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/
|
|||||||
HasRoleModule,
|
HasRoleModule,
|
||||||
CardModule,
|
CardModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatPaginatorModule,
|
PaginatorModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
|
@ -20,7 +20,7 @@ import { FeaturesComponent } from './features.component';
|
|||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
FeaturesComponent
|
FeaturesComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
FeaturesRoutingModule,
|
FeaturesRoutingModule,
|
||||||
@ -41,6 +41,6 @@ import { FeaturesComponent } from './features.component';
|
|||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
FeaturesComponent,
|
FeaturesComponent,
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
export class FeaturesModule { }
|
export class FeaturesModule { }
|
||||||
|
@ -82,7 +82,7 @@ export class IdpCreateComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public addIdp(): void {
|
public addIdp(): void {
|
||||||
if (this.serviceType == PolicyComponentServiceType.MGMT) {
|
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||||
const req = new AddOrgOIDCIDPRequest();
|
const req = new AddOrgOIDCIDPRequest();
|
||||||
|
|
||||||
req.setName(this.name?.value);
|
req.setName(this.name?.value);
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
[disabled]="serviceType==PolicyComponentServiceType.MGMT && idp?.owner == IDPOwnerType.IDP_OWNER_TYPE_SYSTEM"
|
[disabled]="serviceType==PolicyComponentServiceType.MGMT && idp?.owner == IDPOwnerType.IDP_OWNER_TYPE_SYSTEM"
|
||||||
(change)="$event ? selection.toggle(idp) : null" [checked]="selection.isSelected(idp)">
|
(change)="$event ? selection.toggle(idp) : null" [checked]="selection.isSelected(idp)">
|
||||||
<img src="../../../assets/images/google.png"
|
<img src="../../../assets/images/google.png"
|
||||||
*ngIf="idp.stylingType == IdpStylingType.IDPSTYLINGTYPE_GOOGLE" alt="google" />
|
*ngIf="idp.stylingType == IDPSTYLINGTYPE.IDPSTYLINGTYPE_GOOGLE" alt="google" />
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@ -100,6 +100,6 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<mat-paginator #paginator class="paginator" [length]="idpResult?.details?.totalResult || 0" [pageSize]="10"
|
<cnsl-paginator #paginator class="paginator" [timestamp]="idpResult?.details?.viewTimestamp" [length]="idpResult?.details?.totalResult || 0" [pageSize]="10"
|
||||||
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
|
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></cnsl-paginator>
|
||||||
</app-refresh-table>
|
</app-refresh-table>
|
@ -1,6 +1,7 @@
|
|||||||
.ar-button {
|
.ar-button {
|
||||||
margin-right: .5rem;
|
margin-right: .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-wrapper {
|
.table-wrapper {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -27,12 +28,12 @@ td {
|
|||||||
outline: none;
|
outline: none;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
margin-top: .5rem;
|
margin-top: .5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,15 +101,13 @@ tr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.date-block {
|
.date-block {
|
||||||
margin: .5rem 0;
|
margin: .5rem 0;
|
||||||
|
display: block;
|
||||||
|
min-width: 120px;
|
||||||
|
|
||||||
|
.date-sub {
|
||||||
|
font-size: 13px;
|
||||||
display: block;
|
display: block;
|
||||||
min-width: 120px;
|
}
|
||||||
|
|
||||||
.date-sub {
|
|
||||||
font-size: 13px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
|||||||
import { SelectionModel } from '@angular/cdk/collections';
|
import { SelectionModel } from '@angular/cdk/collections';
|
||||||
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
@ -13,6 +12,7 @@ import { AdminService } from 'src/app/services/admin.service';
|
|||||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
|
import { PageEvent, PaginatorComponent } from '../paginator/paginator.component';
|
||||||
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
|
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
|
||||||
import { WarnDialogComponent } from '../warn-dialog/warn-dialog.component';
|
import { WarnDialogComponent } from '../warn-dialog/warn-dialog.component';
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ export class IdpTableComponent implements OnInit {
|
|||||||
@Input() public serviceType!: PolicyComponentServiceType;
|
@Input() public serviceType!: PolicyComponentServiceType;
|
||||||
@Input() service!: AdminService | ManagementService;
|
@Input() service!: AdminService | ManagementService;
|
||||||
@Input() disabled: boolean = false;
|
@Input() disabled: boolean = false;
|
||||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||||
public dataSource: MatTableDataSource<IDP.AsObject>
|
public dataSource: MatTableDataSource<IDP.AsObject>
|
||||||
= new MatTableDataSource<IDP.AsObject>();
|
= new MatTableDataSource<IDP.AsObject>();
|
||||||
public selection: SelectionModel<IDP.AsObject>
|
public selection: SelectionModel<IDP.AsObject>
|
||||||
@ -36,7 +36,7 @@ export class IdpTableComponent implements OnInit {
|
|||||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||||
public IDPOwnerType: any = IDPOwnerType;
|
public IDPOwnerType: any = IDPOwnerType;
|
||||||
public IDPState: any = IDPState;
|
public IDPState: any = IDPState;
|
||||||
public IdpStylingType: any = IDPStylingType;
|
public IDPSTYLINGTYPE: any = IDPStylingType;
|
||||||
@Input() public displayedColumns: string[] = ['select', 'name', 'config', 'dates', 'state'];
|
@Input() public displayedColumns: string[] = ['select', 'name', 'config', 'dates', 'state'];
|
||||||
|
|
||||||
@Output() public changedSelection: EventEmitter<Array<IDP.AsObject>>
|
@Output() public changedSelection: EventEmitter<Array<IDP.AsObject>>
|
||||||
|
@ -4,7 +4,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
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 { MatPaginatorModule } from '@angular/material/paginator';
|
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
@ -15,6 +14,7 @@ import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/local
|
|||||||
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
|
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
|
||||||
import { TruncatePipeModule } from 'src/app/pipes/truncate-pipe/truncate-pipe.module';
|
import { TruncatePipeModule } from 'src/app/pipes/truncate-pipe/truncate-pipe.module';
|
||||||
|
|
||||||
|
import { PaginatorModule } from '../paginator/paginator.module';
|
||||||
import { IdpTableComponent } from './idp-table.component';
|
import { IdpTableComponent } from './idp-table.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -31,7 +31,7 @@ import { IdpTableComponent } from './idp-table.component';
|
|||||||
LocalizedDatePipeModule,
|
LocalizedDatePipeModule,
|
||||||
TimestampToDatePipeModule,
|
TimestampToDatePipeModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatPaginatorModule,
|
PaginatorModule,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
RefreshTableModule,
|
RefreshTableModule,
|
||||||
HasRoleModule,
|
HasRoleModule,
|
||||||
|
@ -26,8 +26,8 @@
|
|||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
|
|
||||||
.chip {
|
.chip {
|
||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.fullwidth {
|
&.fullwidth {
|
||||||
@ -40,21 +40,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.line {
|
.line {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.formfield {
|
.formfield {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
input {
|
input {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ export class IdpComponent implements OnInit, OnDestroy {
|
|||||||
})).subscribe((params) => {
|
})).subscribe((params) => {
|
||||||
const { id } = params;
|
const { id } = params;
|
||||||
if (id) {
|
if (id) {
|
||||||
if (this.serviceType == PolicyComponentServiceType.MGMT) {
|
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||||
(this.service as ManagementService).getOrgIDPByID(id).then(resp => {
|
(this.service as ManagementService).getOrgIDPByID(id).then(resp => {
|
||||||
if (resp.idp) {
|
if (resp.idp) {
|
||||||
const idpObject = resp.idp;
|
const idpObject = resp.idp;
|
||||||
@ -90,7 +90,7 @@ export class IdpComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (this.serviceType == PolicyComponentServiceType.ADMIN) {
|
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||||
(this.service as AdminService).getIDPByID(id).then(resp => {
|
(this.service as AdminService).getIDPByID(id).then(resp => {
|
||||||
if (resp.idp) {
|
if (resp.idp) {
|
||||||
const idpObject = resp.idp;
|
const idpObject = resp.idp;
|
||||||
@ -118,7 +118,7 @@ export class IdpComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public updateIdp(): void {
|
public updateIdp(): void {
|
||||||
if (this.serviceType == PolicyComponentServiceType.MGMT) {
|
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||||
const req = new UpdateOrgIDPRequest();
|
const req = new UpdateOrgIDPRequest();
|
||||||
|
|
||||||
req.setIdpId(this.id?.value);
|
req.setIdpId(this.id?.value);
|
||||||
@ -131,7 +131,7 @@ export class IdpComponent implements OnInit, OnDestroy {
|
|||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
this.toast.showError(error);
|
this.toast.showError(error);
|
||||||
});
|
});
|
||||||
} else if (this.serviceType == PolicyComponentServiceType.ADMIN) {
|
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||||
const req = new UpdateIDPRequest();
|
const req = new UpdateIDPRequest();
|
||||||
|
|
||||||
req.setIdpId(this.id?.value);
|
req.setIdpId(this.id?.value);
|
||||||
@ -148,7 +148,7 @@ export class IdpComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public updateOidcConfig(): void {
|
public updateOidcConfig(): void {
|
||||||
if (this.serviceType == PolicyComponentServiceType.MGMT) {
|
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||||
const req = new UpdateOrgIDPOIDCConfigRequest();
|
const req = new UpdateOrgIDPOIDCConfigRequest();
|
||||||
|
|
||||||
req.setIdpId(this.id?.value);
|
req.setIdpId(this.id?.value);
|
||||||
@ -165,7 +165,7 @@ export class IdpComponent implements OnInit, OnDestroy {
|
|||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
this.toast.showError(error);
|
this.toast.showError(error);
|
||||||
});
|
});
|
||||||
} else if (this.serviceType == PolicyComponentServiceType.ADMIN) {
|
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||||
const req = new UpdateIDPOIDCConfigRequest();
|
const req = new UpdateIDPOIDCConfigRequest();
|
||||||
|
|
||||||
req.setIdpId(this.id?.value);
|
req.setIdpId(this.id?.value);
|
||||||
|
@ -13,33 +13,33 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
||||||
.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: .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-section-content {
|
.info-section-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.info {
|
&.info {
|
||||||
background-color: if($is-dark-theme, #4f566b, #cbf4c9);
|
background-color: if($is-dark-theme, #4f566b, #cbf4c9);
|
||||||
color: if($is-dark-theme, #cbf4c9, #0e6245);
|
color: if($is-dark-theme, #cbf4c9, #0e6245);
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
color: $primary-color;
|
color: $primary-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.warn {
|
&.warn {
|
||||||
background-color: if($is-dark-theme, #4f566b, #ffc1c1);
|
background-color: if($is-dark-theme, #4f566b, #ffc1c1);
|
||||||
color: if($is-dark-theme, #ffc1c1, #620e0e);
|
color: if($is-dark-theme, #ffc1c1, #620e0e);
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
color: if($is-dark-theme, #ffc1c1, #620e0e);
|
color: if($is-dark-theme, #ffc1c1, #620e0e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,5 +12,5 @@ enum InfoSectionType {
|
|||||||
})
|
})
|
||||||
export class InfoSectionComponent {
|
export class InfoSectionComponent {
|
||||||
|
|
||||||
@Input() type = InfoSectionType.INFO;
|
@Input() type: InfoSectionType = InfoSectionType.INFO;
|
||||||
}
|
}
|
||||||
|
@ -1,59 +1,59 @@
|
|||||||
.next-steps {
|
.next-steps {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
h5 {
|
|
||||||
text-transform: uppercase;
|
h5 {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding-bottom: .5rem;
|
||||||
|
|
||||||
|
.step {
|
||||||
|
min-width: 220px;
|
||||||
|
max-width: 280px;
|
||||||
|
padding: 1rem;
|
||||||
|
margin: 0 .5rem;
|
||||||
|
border: 1px solid var(--grey);
|
||||||
|
border-radius: .5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
font-size: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0 0 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
text-align: center;
|
||||||
color: var(--grey);
|
color: var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fill-space {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.row {
|
}
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
overflow-x: auto;
|
|
||||||
padding-bottom: .5rem;
|
|
||||||
|
|
||||||
.step {
|
|
||||||
min-width: 220px;
|
|
||||||
max-width: 280px;
|
|
||||||
padding: 1rem;
|
|
||||||
margin: 0 .5rem;
|
|
||||||
border: 1px solid var(--grey);
|
|
||||||
border-radius: .5rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
box-sizing: border-box;
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
h6 {
|
|
||||||
font-size: 1rem;
|
|
||||||
text-align: center;
|
|
||||||
margin: 0 0 1rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 14px;
|
|
||||||
text-align: center;
|
|
||||||
color: var(--grey);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fill-space {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
display: block;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -8,7 +8,7 @@ describe('LinksComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ LinksComponent ]
|
declarations: [ LinksComponent ],
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
});
|
});
|
||||||
|
@ -12,7 +12,7 @@ export interface CnslLinks {
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'cnsl-links',
|
selector: 'cnsl-links',
|
||||||
templateUrl: './links.component.html',
|
templateUrl: './links.component.html',
|
||||||
styleUrls: ['./links.component.scss']
|
styleUrls: ['./links.component.scss'],
|
||||||
})
|
})
|
||||||
export class LinksComponent implements OnInit {
|
export class LinksComponent implements OnInit {
|
||||||
@Input() links: Array<CnslLinks> = [];
|
@Input() links: Array<CnslLinks> = [];
|
||||||
|
@ -19,6 +19,6 @@ import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
|||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
LinksComponent,
|
LinksComponent,
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
export class LinksModule { }
|
export class LinksModule { }
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
<mat-paginator #paginator class="paginator" [length]="keyResult?.details?.totalResult || 0" [pageSize]="10"
|
<cnsl-paginator #paginator class="paginator" [timestamp]="keyResult?.details?.viewTimestamp" [length]="keyResult?.details?.totalResult || 0" [pageSize]="10"
|
||||||
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
|
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></cnsl-paginator>
|
||||||
</div>
|
</div>
|
||||||
</app-refresh-table>
|
</app-refresh-table>
|
@ -1,7 +1,6 @@
|
|||||||
import { SelectionModel } from '@angular/cdk/collections';
|
import { SelectionModel } from '@angular/cdk/collections';
|
||||||
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
||||||
@ -14,6 +13,8 @@ import { ListMachineKeysResponse } from 'src/app/proto/generated/zitadel/managem
|
|||||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
|
import { PageEvent, PaginatorComponent } from '../paginator/paginator.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-machine-keys',
|
selector: 'app-machine-keys',
|
||||||
templateUrl: './machine-keys.component.html',
|
templateUrl: './machine-keys.component.html',
|
||||||
@ -22,7 +23,7 @@ import { ToastService } from 'src/app/services/toast.service';
|
|||||||
export class MachineKeysComponent implements OnInit {
|
export class MachineKeysComponent implements OnInit {
|
||||||
@Input() userId!: string;
|
@Input() userId!: string;
|
||||||
|
|
||||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||||
public dataSource: MatTableDataSource<Key.AsObject> = new MatTableDataSource<Key.AsObject>();
|
public dataSource: MatTableDataSource<Key.AsObject> = new MatTableDataSource<Key.AsObject>();
|
||||||
public selection: SelectionModel<Key.AsObject> = new SelectionModel<Key.AsObject>(true, []);
|
public selection: SelectionModel<Key.AsObject> = new SelectionModel<Key.AsObject>(true, []);
|
||||||
public keyResult!: ListMachineKeysResponse.AsObject;
|
public keyResult!: ListMachineKeysResponse.AsObject;
|
||||||
@ -103,7 +104,7 @@ export class MachineKeysComponent implements OnInit {
|
|||||||
this.dialog.open(ShowKeyDialogComponent, {
|
this.dialog.open(ShowKeyDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
key: response,
|
key: response,
|
||||||
type: AddKeyDialogType.MACHINE
|
type: AddKeyDialogType.MACHINE,
|
||||||
},
|
},
|
||||||
width: '400px',
|
width: '400px',
|
||||||
});
|
});
|
||||||
|
@ -5,24 +5,24 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
|
||||||
import { CardModule } from '../card/card.module';
|
|
||||||
import { InputModule } from '../input/input.module';
|
|
||||||
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
|
||||||
|
|
||||||
import { MachineKeysComponent } from './machine-keys.component';
|
|
||||||
import { ShowKeyDialogModule } from '../show-key-dialog/show-key-dialog.module';
|
|
||||||
import { AddKeyDialogModule } from 'src/app/modules/add-key-dialog/add-key-dialog.module';
|
import { AddKeyDialogModule } from 'src/app/modules/add-key-dialog/add-key-dialog.module';
|
||||||
import { RouterModule } from '@angular/router';
|
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 { 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 { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
|
||||||
|
|
||||||
|
import { CardModule } from '../card/card.module';
|
||||||
|
import { InputModule } from '../input/input.module';
|
||||||
|
import { PaginatorModule } from '../paginator/paginator.module';
|
||||||
|
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
||||||
|
import { ShowKeyDialogModule } from '../show-key-dialog/show-key-dialog.module';
|
||||||
|
import { MachineKeysComponent } from './machine-keys.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -37,7 +37,7 @@ import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/
|
|||||||
HasRoleModule,
|
HasRoleModule,
|
||||||
CardModule,
|
CardModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatPaginatorModule,
|
PaginatorModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
|
@ -91,7 +91,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<mat-paginator *ngIf="dataSource" class="paginator" #paginator [pageSize]="INITIALPAGESIZE"
|
<cnsl-paginator *ngIf="dataSource" class="paginator" #paginator [timestamp]="dataSource?.viewTimestamp" [pageSize]="INITIALPAGESIZE"
|
||||||
[length]="dataSource.totalResult" [pageSizeOptions]="[25, 50, 100, 250]" (page)="changePage($event)">
|
[length]="dataSource.totalResult" [pageSizeOptions]="[25, 50, 100, 250]" (page)="changePage($event)">
|
||||||
</mat-paginator>
|
</cnsl-paginator>
|
||||||
</app-refresh-table>
|
</app-refresh-table>
|
@ -1,6 +1,5 @@
|
|||||||
import { SelectionModel } from '@angular/cdk/collections';
|
import { SelectionModel } from '@angular/cdk/collections';
|
||||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
|
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
|
||||||
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
|
||||||
import { MatSelectChange } from '@angular/material/select';
|
import { MatSelectChange } from '@angular/material/select';
|
||||||
import { MatTable } from '@angular/material/table';
|
import { MatTable } from '@angular/material/table';
|
||||||
import { Observable, Subject } from 'rxjs';
|
import { Observable, Subject } from 'rxjs';
|
||||||
@ -9,6 +8,7 @@ import { IamMembersDataSource } from 'src/app/pages/iam/iam-members/iam-members-
|
|||||||
import { OrgMembersDataSource } from 'src/app/pages/orgs/org-members/org-members-datasource';
|
import { OrgMembersDataSource } from 'src/app/pages/orgs/org-members/org-members-datasource';
|
||||||
import { Member } from 'src/app/proto/generated/zitadel/member_pb';
|
import { Member } from 'src/app/proto/generated/zitadel/member_pb';
|
||||||
|
|
||||||
|
import { PageEvent, PaginatorComponent } from '../paginator/paginator.component';
|
||||||
import { ProjectMembersDataSource } from '../project-members/project-members-datasource';
|
import { ProjectMembersDataSource } from '../project-members/project-members-datasource';
|
||||||
|
|
||||||
type MemberDatasource = OrgMembersDataSource | ProjectMembersDataSource | IamMembersDataSource;
|
type MemberDatasource = OrgMembersDataSource | ProjectMembersDataSource | IamMembersDataSource;
|
||||||
@ -22,7 +22,7 @@ export class MembersTableComponent implements OnInit, OnDestroy {
|
|||||||
public INITIALPAGESIZE: number = 25;
|
public INITIALPAGESIZE: number = 25;
|
||||||
@Input() public canDelete: boolean = false;
|
@Input() public canDelete: boolean = false;
|
||||||
@Input() public canWrite: boolean = false;
|
@Input() public canWrite: boolean = false;
|
||||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||||
@ViewChild(MatTable) public table!: MatTable<Member.AsObject>;
|
@ViewChild(MatTable) public table!: MatTable<Member.AsObject>;
|
||||||
@Input() public dataSource!: MemberDatasource;
|
@Input() public dataSource!: MemberDatasource;
|
||||||
public selection: SelectionModel<any> = new SelectionModel<any>(true, []);
|
public selection: SelectionModel<any> = new SelectionModel<any>(true, []);
|
||||||
@ -70,7 +70,7 @@ export class MembersTableComponent implements OnInit, OnDestroy {
|
|||||||
this.dataSource.membersSubject.value.forEach(row => this.selection.select(row));
|
this.dataSource.membersSubject.value.forEach(row => this.selection.select(row));
|
||||||
}
|
}
|
||||||
|
|
||||||
public changePage(event?: PageEvent | MatPaginator): any {
|
public changePage(event?: PageEvent): any {
|
||||||
this.selection.clear();
|
this.selection.clear();
|
||||||
return this.factoryLoadFunc(event ?? this.paginator);
|
return this.factoryLoadFunc(event ?? this.paginator);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import { FormsModule } from '@angular/forms';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
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 { MatPaginatorModule } from '@angular/material/paginator';
|
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { MatSortModule } from '@angular/material/sort';
|
import { MatSortModule } from '@angular/material/sort';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
@ -14,6 +13,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
|||||||
import { InputModule } from 'src/app/modules/input/input.module';
|
import { InputModule } from 'src/app/modules/input/input.module';
|
||||||
|
|
||||||
import { AvatarModule } from '../avatar/avatar.module';
|
import { AvatarModule } from '../avatar/avatar.module';
|
||||||
|
import { PaginatorModule } from '../paginator/paginator.module';
|
||||||
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
||||||
import { MembersTableComponent } from './members-table.component';
|
import { MembersTableComponent } from './members-table.component';
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ import { MembersTableComponent } from './members-table.component';
|
|||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatPaginatorModule,
|
PaginatorModule,
|
||||||
MatSortModule,
|
MatSortModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
@import '~@angular/material/theming';
|
@import '~@angular/material/theming';
|
||||||
|
|
||||||
@mixin meta-theme($theme) {
|
@mixin meta-theme($theme) {
|
||||||
$is-dark-theme: map-get($theme, is-dark);
|
$is-dark-theme: map-get($theme, is-dark);
|
||||||
|
|
||||||
.meta-details {
|
.meta-details {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
@ -45,14 +45,14 @@
|
|||||||
&:not(.disabled) {
|
&:not(.disabled) {
|
||||||
&:hover {
|
&:hover {
|
||||||
.rm {
|
.rm {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
opacity: .5;
|
opacity: .5;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
box-shadow: inset 0 -1px if($is-dark-theme, #303131, #e3e8ee);
|
box-shadow: inset 0 -1px if($is-dark-theme, #303131, #e3e8ee);
|
||||||
|
|
||||||
.prev {
|
.prev {
|
||||||
background: $primary-color;
|
background: $primary-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.goto {
|
.goto {
|
||||||
@ -32,116 +32,116 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.split {
|
.split {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 0.5rem;
|
border-radius: .5rem;
|
||||||
box-shadow: 0 3px 8px 0 rgb(0 0 0 / 6%);
|
box-shadow: 0 3px 8px 0 rgb(0 0 0 / 6%);
|
||||||
|
|
||||||
@media only screen and (min-width: 1024px) {
|
@media only screen and (min-width: 1024px) {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
||||||
.right {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.left {
|
|
||||||
flex-basis: 300px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 1.5rem;
|
|
||||||
background: linear-gradient(40deg, rgb(80, 66, 121),rgb(177, 59, 122),rgb(225,53,81), rgb(230,107,86));
|
|
||||||
box-shadow: inset -2px 1px 15px -9px #000000;
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.firststeps {
|
|
||||||
color: #fad6e3;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
color: #fad6e3;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
.right {
|
||||||
padding: 1.5rem;
|
overflow: auto;
|
||||||
flex: 1;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
.desc {
|
|
||||||
color: var(--grey);
|
|
||||||
font-size: 20px;
|
|
||||||
margin-top: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.onboarding-row {
|
|
||||||
display: flex;
|
|
||||||
padding: 1rem 0;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.prev {
|
|
||||||
height: 40px;
|
|
||||||
width: 40px;
|
|
||||||
min-width: 40px;
|
|
||||||
border-radius: .5rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-right: 2rem;
|
|
||||||
color: white;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
box-shadow: 0 3px 8px 0 rgb(0 0 0 / 6%);
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 12px;
|
|
||||||
margin: 0;
|
|
||||||
color: var(--grey);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fill-space {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-row {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
.goto {
|
|
||||||
background-color: white;
|
|
||||||
padding: 2px 1rem;
|
|
||||||
color: black;
|
|
||||||
border-radius: 50vw;
|
|
||||||
font-size: 12px;
|
|
||||||
margin: .5rem 0 .5rem 1rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
flex-basis: 300px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 1.5rem;
|
||||||
|
background: linear-gradient(40deg, rgb(80, 66, 121), rgb(177, 59, 122), rgb(225, 53, 81), rgb(230, 107, 86));
|
||||||
|
box-shadow: inset -2px 1px 15px -9px #000;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firststeps {
|
||||||
|
color: #fad6e3;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #fad6e3;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
padding: 1.5rem;
|
||||||
|
flex: 1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
color: var(--grey);
|
||||||
|
font-size: 20px;
|
||||||
|
margin-top: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.onboarding-row {
|
||||||
|
display: flex;
|
||||||
|
padding: 1rem 0;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.prev {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
min-width: 40px;
|
||||||
|
border-radius: .5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 2rem;
|
||||||
|
color: white;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
box-shadow: 0 3px 8px 0 rgb(0 0 0 / 6%);
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 0;
|
||||||
|
color: var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fill-space {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
.goto {
|
||||||
|
background-color: white;
|
||||||
|
padding: 2px 1rem;
|
||||||
|
color: black;
|
||||||
|
border-radius: 50vw;
|
||||||
|
font-size: 12px;
|
||||||
|
margin: .5rem 0 .5rem 1rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,7 +8,7 @@ describe('OnboardingComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ OnboardingComponent ]
|
declarations: [ OnboardingComponent ],
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
});
|
});
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { AuthenticationService } from 'src/app/services/authentication.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cnsl-onboarding',
|
selector: 'cnsl-onboarding',
|
||||||
templateUrl: './onboarding.component.html',
|
templateUrl: './onboarding.component.html',
|
||||||
styleUrls: ['./onboarding.component.scss']
|
styleUrls: ['./onboarding.component.scss'],
|
||||||
})
|
})
|
||||||
export class OnboardingComponent {
|
export class OnboardingComponent {
|
||||||
public steps = [
|
public steps: Array<{
|
||||||
{ titleI18nKey: 'ONBOARDING.STEPS.1.TITLE', descI18nKey: 'ONBOARDING.STEPS.1.DESC', docs: "https://docs.zitadel.ch/use", link: ['/projects', 'create'] },
|
titleI18nKey: string;
|
||||||
{ titleI18nKey: 'ONBOARDING.STEPS.2.TITLE', descI18nKey: 'ONBOARDING.STEPS.2.DESC', docs: "https://docs.zitadel.ch/use", link: ['/projects'] },
|
descI18nKey: string,
|
||||||
{ titleI18nKey: 'ONBOARDING.STEPS.3.TITLE', descI18nKey: 'ONBOARDING.STEPS.3.DESC', link: ['/iam', 'policies'] },
|
docs?: string;
|
||||||
];
|
link?: string[];
|
||||||
constructor() { }
|
}> = [
|
||||||
|
{ titleI18nKey: 'ONBOARDING.STEPS.1.TITLE', descI18nKey: 'ONBOARDING.STEPS.1.DESC', docs: 'https://docs.zitadel.ch/use', link: ['/projects', 'create'] },
|
||||||
|
{ titleI18nKey: 'ONBOARDING.STEPS.2.TITLE', descI18nKey: 'ONBOARDING.STEPS.2.DESC', docs: 'https://docs.zitadel.ch/use', link: ['/projects'] },
|
||||||
|
{ titleI18nKey: 'ONBOARDING.STEPS.3.TITLE', descI18nKey: 'ONBOARDING.STEPS.3.DESC', link: ['/iam', 'policies'] },
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
20
console/src/app/modules/paginator/paginator.component.html
Normal file
20
console/src/app/modules/paginator/paginator.component.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<div class="paginator">
|
||||||
|
<div class="col">
|
||||||
|
<p class="length"><span>{{length}} </span>{{'PAGINATOR.COUNT' | translate}}</p>
|
||||||
|
<p class="ts" *ngIf="timestamp">{{timestamp | timestampToDate | localizedDate: 'EEEE dd. MMM YYYY, HH:mm'}}</p>
|
||||||
|
</div>
|
||||||
|
<span class="fill-space"></span>
|
||||||
|
<span class="pos">{{pageIndex * pageSize}} - {{pageIndex * pageSize + pageSize}} </span>
|
||||||
|
<div class="row">
|
||||||
|
<cnsl-form-field class="size" appearance="outline">
|
||||||
|
<mat-select [(ngModel)]="pageSize" (selectionChange)="emitChange()">
|
||||||
|
<mat-option *ngFor="let sizeOption of pageSizeOptions" [value]="sizeOption">
|
||||||
|
{{sizeOption}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</cnsl-form-field>
|
||||||
|
<button (click)="previous()" [disabled]="!previousPossible" mat-button>{{'PAGINATOR.PREVIOUS' |
|
||||||
|
translate}}</button>
|
||||||
|
<button (click)="next()" [disabled]="!nextPossible" mat-button>{{'PAGINATOR.NEXT' | translate}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
62
console/src/app/modules/paginator/paginator.component.scss
Normal file
62
console/src/app/modules/paginator/paginator.component.scss
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
.paginator {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-top: .5rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
|
||||||
|
@media only screen and (min-width: 500px) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col {
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.length {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ts {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--grey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fill-space {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pos {
|
||||||
|
font-size: 12px;
|
||||||
|
margin: .5rem 1rem .5rem 1rem;
|
||||||
|
color: var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
.size {
|
||||||
|
transform: translateY(1px);
|
||||||
|
margin-right: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 0 .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stylelint-disable */
|
||||||
|
::ng-deep .mat-select {
|
||||||
|
min-width: 60px;
|
||||||
|
height: 36px !important;
|
||||||
|
padding-top: 8px !important;
|
||||||
|
}
|
||||||
|
/* stylelint-enable */
|
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PaginatorComponent } from './paginator.component';
|
||||||
|
|
||||||
|
describe('PaginatorComponent', () => {
|
||||||
|
let component: PaginatorComponent;
|
||||||
|
let fixture: ComponentFixture<PaginatorComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ PaginatorComponent ],
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PaginatorComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
57
console/src/app/modules/paginator/paginator.component.ts
Normal file
57
console/src/app/modules/paginator/paginator.component.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
import { Timestamp } from 'src/app/proto/generated/google/protobuf/timestamp_pb';
|
||||||
|
|
||||||
|
export interface PageEvent {
|
||||||
|
length: number;
|
||||||
|
pageSize: number;
|
||||||
|
pageIndex: number;
|
||||||
|
pageSizeOptions: Array<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'cnsl-paginator',
|
||||||
|
templateUrl: './paginator.component.html',
|
||||||
|
styleUrls: ['./paginator.component.scss'],
|
||||||
|
})
|
||||||
|
export class PaginatorComponent {
|
||||||
|
@Input() public timestamp!: Timestamp.AsObject;
|
||||||
|
@Input() public length: number = 0;
|
||||||
|
@Input() public pageSize: number = 10;
|
||||||
|
@Input() public pageIndex: number = 0;
|
||||||
|
@Input() public pageSizeOptions: Array<number> = [10, 25, 50];
|
||||||
|
@Output() public page: EventEmitter<PageEvent> = new EventEmitter();
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
public previous(): void {
|
||||||
|
if (this.previousPossible) {
|
||||||
|
this.pageIndex = this.pageIndex - 1;
|
||||||
|
this.emitChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public next(): void {
|
||||||
|
if (this.nextPossible) {
|
||||||
|
this.pageIndex = this.pageIndex + 1;
|
||||||
|
this.emitChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get previousPossible(): boolean {
|
||||||
|
const temp = this.pageIndex - 1;
|
||||||
|
return (temp >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
get nextPossible(): boolean {
|
||||||
|
const temp = this.pageIndex + 1;
|
||||||
|
return (temp <= (this.length / this.pageSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
public emitChange(): void {
|
||||||
|
this.page.emit({
|
||||||
|
length: this.length,
|
||||||
|
pageSize: this.pageSize,
|
||||||
|
pageIndex: this.pageIndex,
|
||||||
|
pageSizeOptions: this.pageSizeOptions,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
31
console/src/app/modules/paginator/paginator.module.ts
Normal file
31
console/src/app/modules/paginator/paginator.module.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
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 { FormFieldModule } from '../form-field/form-field.module';
|
||||||
|
import { PaginatorComponent } from './paginator.component';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [PaginatorComponent],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
FormsModule,
|
||||||
|
TranslateModule,
|
||||||
|
MatButtonModule,
|
||||||
|
TimestampToDatePipeModule,
|
||||||
|
FormFieldModule,
|
||||||
|
MatSelectModule,
|
||||||
|
LocalizedDatePipeModule,
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
PaginatorComponent,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class PaginatorModule { }
|
@ -24,7 +24,6 @@ export class AddIdpDialogComponent {
|
|||||||
|
|
||||||
public idp: IDP.AsObject | undefined = undefined;
|
public idp: IDP.AsObject | undefined = undefined;
|
||||||
public availableIdps: Array<IDP.AsObject[] | IDP.AsObject> | string[] = [];
|
public availableIdps: Array<IDP.AsObject[] | IDP.AsObject> | string[] = [];
|
||||||
public IdpProviderType: any = IDPOwnerType;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private mgmtService: ManagementService,
|
private mgmtService: ManagementService,
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,25 +51,25 @@
|
|||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
.line {
|
.line {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
* {
|
* {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,13 +116,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:not(.disabled) {
|
&:not(.disabled) {
|
||||||
&:hover {
|
&:hover {
|
||||||
.rm {
|
.rm {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -195,7 +195,7 @@ export class LoginPolicyComponent implements OnDestroy {
|
|||||||
});
|
});
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(resp => {
|
dialogRef.afterClosed().subscribe(resp => {
|
||||||
if (resp && resp.idp) {
|
if (resp && resp.idp && resp.type) {
|
||||||
this.addIdp(resp.idp, resp.type).then(() => {
|
this.addIdp(resp.idp, resp.type).then(() => {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -208,12 +208,10 @@ export class LoginPolicyComponent implements OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private addIdp(idp: IDP.AsObject | IDP.AsObject, ownerType?: IDPOwnerType): Promise<any> {
|
private addIdp(idp: IDP.AsObject | IDP.AsObject, ownerType: IDPOwnerType): Promise<any> {
|
||||||
switch (this.serviceType) {
|
switch (this.serviceType) {
|
||||||
case PolicyComponentServiceType.MGMT:
|
case PolicyComponentServiceType.MGMT:
|
||||||
if (ownerType) {
|
return (this.service as ManagementService).addIDPToLoginPolicy(idp.id, ownerType);
|
||||||
return (this.service as ManagementService).addIDPToLoginPolicy(idp.id, ownerType);
|
|
||||||
}
|
|
||||||
case PolicyComponentServiceType.ADMIN:
|
case PolicyComponentServiceType.ADMIN:
|
||||||
return (this.service as AdminService).addIDPToLoginPolicy(idp.id);
|
return (this.service as AdminService).addIDPToLoginPolicy(idp.id);
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ import { OrgIamPolicyComponent } from './org-iam-policy.component';
|
|||||||
InfoSectionModule,
|
InfoSectionModule,
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
DetailLayoutModule,
|
DetailLayoutModule,
|
||||||
LinksModule
|
LinksModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class OrgIamPolicyModule { }
|
export class OrgIamPolicyModule { }
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
padding: .3rem 0;
|
padding: .3rem 0;
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-desc {
|
.left-desc {
|
||||||
|
@ -66,7 +66,8 @@ export class PasswordLockoutPolicyComponent implements OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getData(): Promise<AdminGetPasswordLockoutPolicyResponse.AsObject | MgmtGetPasswordLockoutPolicyResponse.AsObject> {
|
private getData():
|
||||||
|
Promise<AdminGetPasswordLockoutPolicyResponse.AsObject | MgmtGetPasswordLockoutPolicyResponse.AsObject> {
|
||||||
switch (this.serviceType) {
|
switch (this.serviceType) {
|
||||||
case PolicyComponentServiceType.MGMT:
|
case PolicyComponentServiceType.MGMT:
|
||||||
return (this.service as ManagementService).getPasswordLockoutPolicy();
|
return (this.service as ManagementService).getPasswordLockoutPolicy();
|
||||||
|
@ -68,14 +68,15 @@ h2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.warn {
|
.warn {
|
||||||
margin-bottom: .5rem;
|
margin-bottom: .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icons {
|
.icons {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
.icon {
|
|
||||||
margin-right: .5rem;
|
.icon {
|
||||||
}
|
margin-right: .5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fill-space {
|
.fill-space {
|
||||||
|
@ -24,13 +24,13 @@ export class PolicyGridComponent implements OnInit {
|
|||||||
constructor(private mgmtService: ManagementService, private adminService: AdminService) { }
|
constructor(private mgmtService: ManagementService, private adminService: AdminService) { }
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
if (this.type == PolicyGridType.ORG) {
|
if (this.type === PolicyGridType.ORG) {
|
||||||
this.mgmtService.getPasswordComplexityPolicy().then((resp) => {
|
this.mgmtService.getPasswordComplexityPolicy().then((resp) => {
|
||||||
if (resp.policy) {
|
if (resp.policy) {
|
||||||
this.complexityPolicy = resp.policy;
|
this.complexityPolicy = resp.policy;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (this.type == PolicyGridType.IAM) {
|
} else if (this.type === PolicyGridType.IAM) {
|
||||||
this.adminService.getPasswordComplexityPolicy().then((resp) => {
|
this.adminService.getPasswordComplexityPolicy().then((resp) => {
|
||||||
if (resp.policy) {
|
if (resp.policy) {
|
||||||
this.complexityPolicy = resp.policy;
|
this.complexityPolicy = resp.policy;
|
||||||
|
@ -7,8 +7,8 @@ import { Member } from 'src/app/proto/generated/zitadel/member_pb';
|
|||||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||||
|
|
||||||
export enum ProjectType {
|
export enum ProjectType {
|
||||||
PROJECTTYPE_OWNED = "OWNED",
|
PROJECTTYPE_OWNED = 'OWNED',
|
||||||
PROJECTTYPE_GRANTED = "GRANTED"
|
PROJECTTYPE_GRANTED = 'GRANTED',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,7 +35,10 @@ export class ProjectMembersDataSource extends DataSource<Member.AsObject> {
|
|||||||
|
|
||||||
this.loadingSubject.next(true);
|
this.loadingSubject.next(true);
|
||||||
|
|
||||||
const promise: Promise<ListProjectMembersResponse.AsObject> | Promise<ListProjectGrantMembersResponse.AsObject> | undefined =
|
const promise:
|
||||||
|
Promise<ListProjectMembersResponse.AsObject> |
|
||||||
|
Promise<ListProjectGrantMembersResponse.AsObject>
|
||||||
|
| undefined =
|
||||||
projectType === ProjectType.PROJECTTYPE_OWNED ?
|
projectType === ProjectType.PROJECTTYPE_OWNED ?
|
||||||
this.mgmtService.listProjectMembers(projectId, pageSize, offset) :
|
this.mgmtService.listProjectMembers(projectId, pageSize, offset) :
|
||||||
projectType === ProjectType.PROJECTTYPE_GRANTED && grantId ?
|
projectType === ProjectType.PROJECTTYPE_GRANTED && grantId ?
|
||||||
|
@ -111,18 +111,22 @@ export class ProjectMembersComponent {
|
|||||||
public removeProjectMemberSelection(): void {
|
public removeProjectMemberSelection(): void {
|
||||||
Promise.all(this.selection.map(member => {
|
Promise.all(this.selection.map(member => {
|
||||||
if (this.projectType === ProjectType.PROJECTTYPE_OWNED) {
|
if (this.projectType === ProjectType.PROJECTTYPE_OWNED) {
|
||||||
return this.mgmtService.removeProjectMember((this.project as Project.AsObject).id, member.userId).then(() => {
|
return this.mgmtService.removeProjectMember((this.project as Project.AsObject).id, member.userId)
|
||||||
this.toast.showInfo('PROJECT.TOAST.MEMBERREMOVED', true);
|
.then(() => {
|
||||||
}).catch(error => {
|
|
||||||
this.toast.showError(error);
|
|
||||||
});
|
|
||||||
} else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) {
|
|
||||||
return this.mgmtService.removeProjectGrantMember((this.project as GrantedProject.AsObject).projectId, this.grantId,
|
|
||||||
member.userId).then(() => {
|
|
||||||
this.toast.showInfo('PROJECT.TOAST.MEMBERREMOVED', true);
|
this.toast.showInfo('PROJECT.TOAST.MEMBERREMOVED', true);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
this.toast.showError(error);
|
this.toast.showError(error);
|
||||||
});
|
});
|
||||||
|
} else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) {
|
||||||
|
return this.mgmtService.removeProjectGrantMember(
|
||||||
|
(this.project as GrantedProject.AsObject).projectId,
|
||||||
|
this.grantId,
|
||||||
|
member.userId,
|
||||||
|
).then(() => {
|
||||||
|
this.toast.showInfo('PROJECT.TOAST.MEMBERREMOVED', true);
|
||||||
|
}).catch(error => {
|
||||||
|
this.toast.showError(error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})).then(() => {
|
})).then(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -173,8 +177,12 @@ export class ProjectMembersComponent {
|
|||||||
return this.mgmtService.addProjectMember((this.project as Project.AsObject).id, user.id, roles);
|
return this.mgmtService.addProjectMember((this.project as Project.AsObject).id, user.id, roles);
|
||||||
|
|
||||||
} else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) {
|
} else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) {
|
||||||
return this.mgmtService.addProjectGrantMember((this.project as GrantedProject.AsObject).projectId, this.grantId,
|
return this.mgmtService.addProjectGrantMember(
|
||||||
user.id, roles);
|
(this.project as GrantedProject.AsObject).projectId,
|
||||||
|
this.grantId,
|
||||||
|
user.id,
|
||||||
|
roles,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
})).then(() => {
|
})).then(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -72,8 +72,8 @@
|
|||||||
<span>{{'PROJECT.ROLE.EMPTY' | translate}}</span>
|
<span>{{'PROJECT.ROLE.EMPTY' | translate}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-paginator #paginator [length]="dataSource.totalResult" [pageSize]="50"
|
<cnsl-paginator #paginator [timestamp]="dataSource?.viewTimestamp" [length]="dataSource.totalResult" [pageSize]="50" (page)="changePage()"
|
||||||
[pageSizeOptions]="[25, 50, 100, 250]">
|
[pageSizeOptions]="[25, 50, 100, 250]">
|
||||||
</mat-paginator>
|
</cnsl-paginator>
|
||||||
</div>
|
</div>
|
||||||
</app-refresh-table>
|
</app-refresh-table>
|
@ -43,16 +43,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
tr {
|
tr {
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|
||||||
|
button {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
button {
|
button {
|
||||||
visibility: hidden;
|
visibility: visible;
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
button {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { SelectionModel } from '@angular/cdk/collections';
|
import { SelectionModel } from '@angular/cdk/collections';
|
||||||
import { AfterViewInit, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { MatPaginator } from '@angular/material/paginator';
|
|
||||||
import { MatTable } from '@angular/material/table';
|
import { MatTable } from '@angular/material/table';
|
||||||
import { tap } from 'rxjs/operators';
|
import { tap } from 'rxjs/operators';
|
||||||
import { Role } from 'src/app/proto/generated/zitadel/project_pb';
|
import { Role } from 'src/app/proto/generated/zitadel/project_pb';
|
||||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
|
import { PaginatorComponent } from '../paginator/paginator.component';
|
||||||
import { ProjectRoleDetailComponent } from './project-role-detail/project-role-detail.component';
|
import { ProjectRoleDetailComponent } from './project-role-detail/project-role-detail.component';
|
||||||
import { ProjectRolesDataSource } from './project-roles-datasource';
|
import { ProjectRolesDataSource } from './project-roles-datasource';
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
|
|||||||
@Input() public projectId: string = '';
|
@Input() public projectId: string = '';
|
||||||
@Input() public disabled: boolean = false;
|
@Input() public disabled: boolean = false;
|
||||||
@Input() public actionsVisible: boolean = false;
|
@Input() public actionsVisible: boolean = false;
|
||||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||||
@ViewChild(MatTable) public table!: MatTable<Role.AsObject>;
|
@ViewChild(MatTable) public table!: MatTable<Role.AsObject>;
|
||||||
public dataSource!: ProjectRolesDataSource;
|
public dataSource!: ProjectRolesDataSource;
|
||||||
public selection: SelectionModel<Role.AsObject> = new SelectionModel<Role.AsObject>(true, []);
|
public selection: SelectionModel<Role.AsObject> = new SelectionModel<Role.AsObject>(true, []);
|
||||||
@ -64,6 +64,11 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public changePage(): void {
|
||||||
|
this.selection.clear();
|
||||||
|
this.loadRolesPage();
|
||||||
|
}
|
||||||
|
|
||||||
public isAllSelected(): boolean {
|
public isAllSelected(): boolean {
|
||||||
const numSelected = this.selection.selected.length;
|
const numSelected = this.selection.selected.length;
|
||||||
const numRows = this.dataSource.rolesSubject.value.length;
|
const numRows = this.dataSource.rolesSubject.value.length;
|
||||||
|
@ -6,7 +6,6 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
|
|||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
@ -18,6 +17,7 @@ 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 { 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 { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
|
||||||
|
|
||||||
|
import { PaginatorModule } from '../paginator/paginator.module';
|
||||||
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
||||||
import { ProjectRoleDetailComponent } from './project-role-detail/project-role-detail.component';
|
import { ProjectRoleDetailComponent } from './project-role-detail/project-role-detail.component';
|
||||||
import { ProjectRolesComponent } from './project-roles.component';
|
import { ProjectRolesComponent } from './project-roles.component';
|
||||||
@ -30,7 +30,7 @@ import { ProjectRolesComponent } from './project-roles.component';
|
|||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
HasRoleModule,
|
HasRoleModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatPaginatorModule,
|
PaginatorModule,
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
InputModule,
|
InputModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
<div class="table-header-row">
|
<div class="table-header-row">
|
||||||
<div class="col">
|
<div class="row" *ngIf="selection.hasValue()">
|
||||||
<span *ngIf="!selection.hasValue()" class="count">{{dataSize}}</span>
|
<div>
|
||||||
<span *ngIf="selection.hasValue()" class="count">{{selection?.selected?.length}}</span>
|
<span class="count">{{selection?.selected?.length}}</span>
|
||||||
<div class="desc">
|
<span class="desc" >{{'ORG_DETAIL.TABLE.SELECTION' | translate}}</span>
|
||||||
<span *ngIf="!selection.hasValue()">{{'ORG_DETAIL.TABLE.TOTAL' | translate}}</span>
|
</div>
|
||||||
<span *ngIf="selection.hasValue()">{{'ORG_DETAIL.TABLE.SELECTION' | translate}}</span>
|
<span class="slash">|</span>
|
||||||
<span *ngIf="timestamp">{{timestamp | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'}}</span>
|
<a (click)="selection.clear()">{{'ORG_DETAIL.TABLE.CLEAR' | translate}}</a>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
<mat-spinner class="spinner" *ngIf="loading" diameter="20"></mat-spinner>
|
<mat-spinner class="spinner" *ngIf="loading" diameter="20"></mat-spinner>
|
||||||
|
@ -3,23 +3,28 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.col {
|
.row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
|
|
||||||
.desc {
|
|
||||||
font-size: .8rem;
|
|
||||||
color: var(--grey);
|
|
||||||
margin-right: 1rem;
|
|
||||||
|
|
||||||
span {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.count {
|
.count {
|
||||||
font-size: 2rem;
|
margin-right: .5rem;
|
||||||
|
color: var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slash {
|
||||||
|
margin: 0 .5rem;
|
||||||
|
color: var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,12 @@ import { MatIconModule } from '@angular/material/icon';
|
|||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { PaginatorModule } from 'src/app/modules/paginator/paginator.module';
|
||||||
import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-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';
|
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
|
||||||
|
|
||||||
import { RefreshTableComponent } from './refresh-table.component';
|
import { RefreshTableComponent } from './refresh-table.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [RefreshTableComponent],
|
declarations: [RefreshTableComponent],
|
||||||
imports: [
|
imports: [
|
||||||
@ -24,6 +24,7 @@ import { RefreshTableComponent } from './refresh-table.component';
|
|||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
TimestampToDatePipeModule,
|
TimestampToDatePipeModule,
|
||||||
LocalizedDatePipeModule,
|
LocalizedDatePipeModule,
|
||||||
|
PaginatorModule,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
RefreshTableComponent,
|
RefreshTableComponent,
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
[emitRefreshOnPreviousRoutes]="refreshOnPreviousRoutes" [timestamp]="dataSource?.viewTimestamp"
|
[emitRefreshOnPreviousRoutes]="refreshOnPreviousRoutes" [timestamp]="dataSource?.viewTimestamp"
|
||||||
[dataSize]="dataSource?.totalResult" [selection]="selection">
|
[dataSize]="dataSource?.totalResult" [selection]="selection">
|
||||||
<cnsl-form-field @appearfade *ngIf="userGrantListSearchKey != undefined" actions class="filtername">
|
<cnsl-form-field @appearfade *ngIf="userGrantListSearchKey != undefined" actions class="filtername">
|
||||||
<input cnslInput (keyup)="applyFilter($event)"
|
<input class="filterinput" cnslInput (keyup)="applyFilter($event)"
|
||||||
[placeholder]="('USER.TABLE.FILTER.' + userGrantListSearchKey.toString()) | translate" #input>
|
[placeholder]="('USER.GRANTS.FILTER.' + userGrantListSearchKey.toString()) | translate" #input>
|
||||||
</cnsl-form-field>
|
</cnsl-form-field>
|
||||||
|
|
||||||
<button color="warn" matTooltip="{{'GRANTS.DELETE' | translate}}" class="icon-button" mat-icon-button actions
|
<button color="warn" matTooltip="{{'GRANTS.DELETE' | translate}}" class="icon-button" mat-icon-button actions
|
||||||
@ -78,6 +78,20 @@
|
|||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="creationDate">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{'PROJECT.GRANT.CREATIONDATE' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let grant">
|
||||||
|
<span>{{grant.details.creationDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }}</span>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="changeDate">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.CHANGEDATE' | translate }} </th>
|
||||||
|
<td mat-cell *matCellDef="let grant">
|
||||||
|
<span>{{grant.details.changeDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }}</span>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="roleNamesList">
|
<ng-container matColumnDef="roleNamesList">
|
||||||
<th mat-header-cell *matHeaderCellDef class="role-data">
|
<th mat-header-cell *matHeaderCellDef class="role-data">
|
||||||
{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}
|
{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}
|
||||||
@ -106,7 +120,6 @@
|
|||||||
<ng-container
|
<ng-container
|
||||||
*ngIf="(context === UserGrantContext.OWNED_PROJECT || context === UserGrantContext.USER || context === UserGrantContext.NONE) && grantToEdit == grant.id && loadedProjectId && loadedProjectId === grant.projectId">
|
*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-form-field class="form-field" appearance="outline">
|
||||||
<!-- <cnsl-label>{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}</cnsl-label> -->
|
|
||||||
<mat-select [(ngModel)]="grant.roleKeysList" multiple
|
<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?.id] : []) | hasRole | async))"
|
[disabled]="disableWrite || !((['user.grant.write$'] | hasRole | async) || ((context === UserGrantContext.OWNED_PROJECT ? ['user.grant.write:' + grant?.projectId] : context === UserGrantContext.GRANTED_PROJECT ? ['user.grant.write:' + grant?.id] : []) | hasRole | async))"
|
||||||
(selectionChange)="updateRoles(grant, $event)">
|
(selectionChange)="updateRoles(grant, $event)">
|
||||||
@ -125,7 +138,6 @@
|
|||||||
<ng-container
|
<ng-container
|
||||||
*ngIf="(context === UserGrantContext.GRANTED_PROJECT || context === UserGrantContext.USER || context === UserGrantContext.NONE) && loadedId && loadedId === grant.id && grantToEdit == grant.id">
|
*ngIf="(context === UserGrantContext.GRANTED_PROJECT || context === UserGrantContext.USER || context === UserGrantContext.NONE) && loadedId && loadedId === grant.id && grantToEdit == grant.id">
|
||||||
<cnsl-form-field class="form-field" appearance="outline">
|
<cnsl-form-field class="form-field" appearance="outline">
|
||||||
<!-- <cnsl-label>{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}</cnsl-label> -->
|
|
||||||
<mat-select [(ngModel)]="grant.roleKeysList" multiple
|
<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?.id] : []) | hasRole | async))"
|
[disabled]="disableWrite || !((['user.grant.write$'] | hasRole | async) || ((context === UserGrantContext.OWNED_PROJECT ? ['user.grant.write:' + grant?.projectId] : context === UserGrantContext.GRANTED_PROJECT ? ['user.grant.write:' + grant?.id] : []) | hasRole | async))"
|
||||||
(selectionChange)="updateRoles(grant, $event)">
|
(selectionChange)="updateRoles(grant, $event)">
|
||||||
@ -153,9 +165,9 @@
|
|||||||
<i class="las la-exclamation"></i>
|
<i class="las la-exclamation"></i>
|
||||||
<span>{{'GRANTS.EMPTY' | translate}}</span>
|
<span>{{'GRANTS.EMPTY' | translate}}</span>
|
||||||
</div>
|
</div>
|
||||||
<mat-paginator class="paginator" #paginator [length]="dataSource.totalResult" [pageSize]="INITIAL_PAGE_SIZE"
|
<cnsl-paginator class="paginator" #paginator [timestamp]="dataSource?.viewTimestamp" [length]="dataSource.totalResult" [pageSize]="INITIAL_PAGE_SIZE"
|
||||||
[length]="dataSource.totalResult" [pageSizeOptions]="[2, 3, 25, 50, 100, 250]" (page)="changePage($event)">
|
[length]="dataSource.totalResult" [pageSizeOptions]="[2, 3, 25, 50, 100, 250]" (page)="changePage($event)">
|
||||||
</mat-paginator>
|
</cnsl-paginator>
|
||||||
</div>
|
</div>
|
||||||
</app-refresh-table>
|
</app-refresh-table>
|
||||||
|
|
||||||
|
@ -109,5 +109,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filtername {
|
.filtername {
|
||||||
|
flex: 1;
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
|
|
||||||
|
.filterinput {
|
||||||
|
height: 36px;
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { SelectionModel } from '@angular/cdk/collections';
|
import { SelectionModel } from '@angular/cdk/collections';
|
||||||
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||||
import { MatInput } from '@angular/material/input';
|
import { MatInput } from '@angular/material/input';
|
||||||
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
|
||||||
import { MatSelectChange } from '@angular/material/select';
|
import { MatSelectChange } from '@angular/material/select';
|
||||||
import { MatTable } from '@angular/material/table';
|
import { MatTable } from '@angular/material/table';
|
||||||
import { tap } from 'rxjs/operators';
|
import { tap } from 'rxjs/operators';
|
||||||
@ -19,6 +18,7 @@ import {
|
|||||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
|
import { PageEvent, PaginatorComponent } from '../paginator/paginator.component';
|
||||||
import { UserGrantContext, UserGrantsDataSource } from './user-grants-datasource';
|
import { UserGrantContext, UserGrantsDataSource } from './user-grants-datasource';
|
||||||
|
|
||||||
export enum UserGrantListSearchKey {
|
export enum UserGrantListSearchKey {
|
||||||
@ -45,7 +45,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
|||||||
|
|
||||||
public dataSource!: UserGrantsDataSource;
|
public dataSource!: UserGrantsDataSource;
|
||||||
public selection: SelectionModel<UserGrant.AsObject> = new SelectionModel<UserGrant.AsObject>(true, []);
|
public selection: SelectionModel<UserGrant.AsObject> = new SelectionModel<UserGrant.AsObject>(true, []);
|
||||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||||
@ViewChild(MatTable) public table!: MatTable<UserGrant.AsObject>;
|
@ViewChild(MatTable) public table!: MatTable<UserGrant.AsObject>;
|
||||||
|
|
||||||
@Input() disableWrite: boolean = false;
|
@Input() disableWrite: boolean = false;
|
||||||
@ -75,7 +75,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
|||||||
@Input() public displayedColumns: string[] = ['select',
|
@Input() public displayedColumns: string[] = ['select',
|
||||||
'user',
|
'user',
|
||||||
'org',
|
'org',
|
||||||
'projectId', 'dates', 'roleNamesList'];
|
'projectId', 'creationDate', 'changeDate', 'roleNamesList'];
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
this.dataSource = new UserGrantsDataSource(this.userService);
|
this.dataSource = new UserGrantsDataSource(this.userService);
|
||||||
|
@ -4,7 +4,6 @@ import { FormsModule } from '@angular/forms';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
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 { MatPaginatorModule } from '@angular/material/paginator';
|
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
@ -18,6 +17,7 @@ import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/
|
|||||||
|
|
||||||
import { InputModule } from '../../modules/input/input.module';
|
import { InputModule } from '../../modules/input/input.module';
|
||||||
import { AvatarModule } from '../avatar/avatar.module';
|
import { AvatarModule } from '../avatar/avatar.module';
|
||||||
|
import { PaginatorModule } from '../paginator/paginator.module';
|
||||||
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
||||||
import { UserGrantsComponent } from './user-grants.component';
|
import { UserGrantsComponent } from './user-grants.component';
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ import { UserGrantsComponent } from './user-grants.component';
|
|||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
HasRoleModule,
|
HasRoleModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatPaginatorModule,
|
PaginatorModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<div class="max-width-container">
|
<div class="enlarged-container">
|
||||||
<h1>{{ 'GRANTS.TITLE' | translate }}</h1>
|
<h1>{{ 'GRANTS.TITLE' | translate }}</h1>
|
||||||
<p class="desc">{{'GRANTS.DESC' | translate }}</p>
|
<p class="desc">{{'GRANTS.DESC' | translate }}</p>
|
||||||
<app-user-grants [displayedColumns]="['select', 'user', 'org', 'projectId', 'dates', 'roleNamesList']"
|
<app-user-grants [displayedColumns]="['select', 'user', 'org', 'projectId', 'creationDate','changeDate', 'roleNamesList']"
|
||||||
[disableWrite]="((['user.grant.write$'] | hasRole) | async) == false"
|
[disableWrite]="((['user.grant.write$'] | hasRole) | async) == false"
|
||||||
[disableDelete]="((['user.grant.delete$'] | hasRole) | async) == false"
|
[disableDelete]="((['user.grant.delete$'] | hasRole) | async) == false"
|
||||||
[refreshOnPreviousRoutes]="['/grant-create']">
|
[refreshOnPreviousRoutes]="['/grant-create']">
|
||||||
|
@ -34,74 +34,74 @@
|
|||||||
|
|
||||||
.onboard,
|
.onboard,
|
||||||
.quickstart {
|
.quickstart {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex: 1 0 45%;
|
flex: 1 0 45%;
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: 0.5rem;
|
border-radius: .5rem;
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
box-shadow: 0 3px 8px 0 rgb(0 0 0 / 6%);
|
box-shadow: 0 3px 8px 0 rgb(0 0 0 / 6%);
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.first-steps {
|
.first-steps {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
visibility: hidden;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
i {
|
||||||
|
color: white;
|
||||||
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
.close {
|
.close {
|
||||||
visibility: hidden;
|
visibility: visible;
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
|
|
||||||
i {
|
|
||||||
color: white;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.close {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.onboard {
|
.onboard {
|
||||||
background: linear-gradient(40deg, rgb(80, 66, 121),rgb(177, 59, 122),rgb(225,53,81), rgb(230,107,86));
|
background: linear-gradient(40deg, rgb(80, 66, 121), rgb(177, 59, 122), rgb(225, 53, 81), rgb(230, 107, 86));
|
||||||
|
|
||||||
p {
|
p {
|
||||||
color: #fad6e3;
|
color: #fad6e3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.quickstart {
|
.quickstart {
|
||||||
background: linear-gradient(30deg, #2283a6,#6c8f59);
|
background: linear-gradient(30deg, #2283a6, #6c8f59);
|
||||||
|
|
||||||
p {
|
p {
|
||||||
color: #d6f3fa;
|
color: #d6f3fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo-cloud {
|
.logo-cloud {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin: -0.5rem;
|
margin: -.5rem;
|
||||||
|
|
||||||
i {
|
i {
|
||||||
font-size: 40px;
|
font-size: 40px;
|
||||||
padding: .5rem;
|
padding: .5rem;
|
||||||
border: 1px solid #ffffff50;
|
border: 1px solid #ffffff50;
|
||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
margin: 0.5rem;
|
margin: .5rem;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
|
@ -15,8 +15,8 @@ export class HomeComponent {
|
|||||||
const theme = localStorage.getItem('theme');
|
const theme = localStorage.getItem('theme');
|
||||||
this.dark = theme === 'dark-theme' ? true : theme === 'light-theme' ? false : true;
|
this.dark = theme === 'dark-theme' ? true : theme === 'light-theme' ? false : true;
|
||||||
|
|
||||||
this.firstStepsDismissed = localStorage.getItem('firstStartDismissed') == 'true' ? true : false;
|
this.firstStepsDismissed = localStorage.getItem('firstStartDismissed') === 'true' ? true : false;
|
||||||
this.quickstartsDismissed = localStorage.getItem('quickstartsDismissed') == 'true' ? true : false;
|
this.quickstartsDismissed = localStorage.getItem('quickstartsDismissed') === 'true' ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dismissFirstSteps(event: Event): void {
|
dismissFirstSteps(event: Event): void {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class="max-width-container">
|
<div class="enlarged-container">
|
||||||
<h1>{{ 'IAM.EVENTSTORE.TITLE' | translate }}</h1>
|
<h1>{{ 'IAM.EVENTSTORE.TITLE' | translate }}</h1>
|
||||||
<p class="desc">{{'IAM.EVENTSTORE.DESCRIPTION' | translate }}</p>
|
<p class="desc">{{'IAM.EVENTSTORE.DESCRIPTION' | translate }}</p>
|
||||||
<app-card title="{{ 'IAM.VIEWS.TITLE' | translate }}" description="{{ 'IAM.VIEWS.DESCRIPTION' | translate }}">
|
<app-card title="{{ 'IAM.VIEWS.TITLE' | translate }}" description="{{ 'IAM.VIEWS.DESCRIPTION' | translate }}">
|
||||||
|
@ -39,7 +39,7 @@ const routes: Routes = [
|
|||||||
// canActivate: [RoleGuard],
|
// canActivate: [RoleGuard],
|
||||||
data: {
|
data: {
|
||||||
roles: ['iam.features.read'],
|
roles: ['iam.features.read'],
|
||||||
serviceType: FeatureServiceType.ADMIN
|
serviceType: FeatureServiceType.ADMIN,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -26,16 +26,17 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="lastSuccessfulSpoolerRun">
|
<ng-container matColumnDef="lastSuccessfulSpoolerRun">
|
||||||
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.VIEWS.LASTSPOOL' | 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?.lastSuccessfulSpoolerRun | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
|
<span>{{view?.lastSuccessfulSpoolerRun | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'
|
||||||
</td>
|
}}</span>
|
||||||
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="actions" stickyEnd>
|
<ng-container matColumnDef="actions" stickyEnd>
|
||||||
<th mat-header-cell *matHeaderCellDef></th>
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
<td mat-cell *matCellDef="let view">
|
<td mat-cell *matCellDef="let view">
|
||||||
<button mat-icon-button matTooltip="{{'IAM.VIEWS.CLEAR' | translate}}"
|
<button mat-icon-button matTooltip="{{'IAM.VIEWS.CLEAR' | translate}}" color="warn"
|
||||||
(click)="cancelView(view.viewName, view.database)">
|
(click)="cancelView(view.viewName, view.database)">
|
||||||
<mat-icon svgIcon="mdi_broom"></mat-icon>
|
<mat-icon svgIcon="mdi_broom"></mat-icon>
|
||||||
</button>
|
</button>
|
||||||
@ -48,4 +49,4 @@
|
|||||||
<mat-paginator class="paginator" [pageSize]="10" #paginator [pageSizeOptions]="[10, 20, 100, 250]">
|
<mat-paginator class="paginator" [pageSize]="10" #paginator [pageSizeOptions]="[10, 20, 100, 250]">
|
||||||
</mat-paginator>
|
</mat-paginator>
|
||||||
</app-refresh-table>
|
</app-refresh-table>
|
||||||
</div>
|
</div>
|
@ -6,7 +6,7 @@
|
|||||||
<h2>{{'FEATURES.TITLE' | translate}}</h2>
|
<h2>{{'FEATURES.TITLE' | translate}}</h2>
|
||||||
<p class="top-desc">{{'FEATURES.DESCRIPTION' | translate}}</p>
|
<p class="top-desc">{{'FEATURES.DESCRIPTION' | translate}}</p>
|
||||||
<div *ngIf="features" class="tier">
|
<div *ngIf="features" class="tier">
|
||||||
<mat-icon>stars</mat-icon>
|
<mat-icon class="icon">stars</mat-icon>
|
||||||
<div class="text" *ngIf="features.tier">
|
<div class="text" *ngIf="features.tier">
|
||||||
<p class="title"><strong>ZITADEL {{features.tier.name}}</strong></p>
|
<p class="title"><strong>ZITADEL {{features.tier.name}}</strong></p>
|
||||||
<p>{{features.tier?.description}}</p>
|
<p>{{features.tier?.description}}</p>
|
||||||
|
@ -13,46 +13,48 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
letter-spacing: .05em;
|
letter-spacing: .05em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tier {
|
.tier {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: .5rem;
|
||||||
|
color: white;
|
||||||
|
background-color: rgb(245, 203, 99);
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
|
||||||
|
.ext {
|
||||||
|
margin-right: .5rem;
|
||||||
|
align-self: center;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-right: 1rem;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
padding: 1rem;
|
|
||||||
border-radius: .5rem;
|
|
||||||
color: white;
|
|
||||||
background-color: rgb(245, 203, 99);
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
|
|
||||||
.ext {
|
p {
|
||||||
margin-right: .5rem;
|
margin: 0;
|
||||||
align-self: center;
|
font-size: 14px;
|
||||||
color: inherit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mat-icon {
|
.title {
|
||||||
margin-right: 1rem;
|
font-size: 16px;
|
||||||
font-size: 2rem;
|
margin-bottom: .5rem;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.text {
|
.fill-space {
|
||||||
display: flex;
|
flex: 1;
|
||||||
flex-direction: column;
|
}
|
||||||
p {
|
}
|
||||||
margin: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.title {
|
|
||||||
font-size: 16px;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fill-space {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
<h2>{{'FEATURES.TITLE' | translate}}</h2>
|
<h2>{{'FEATURES.TITLE' | translate}}</h2>
|
||||||
<p class="top-desc">{{'FEATURES.DESCRIPTION' | translate}}</p>
|
<p class="top-desc">{{'FEATURES.DESCRIPTION' | translate}}</p>
|
||||||
<div *ngIf="features" class="tier">
|
<div *ngIf="features" class="tier">
|
||||||
<mat-icon>stars</mat-icon>
|
<mat-icon class="icon">stars</mat-icon>
|
||||||
<div class="text" *ngIf="features.tier">
|
<div class="text" *ngIf="features.tier">
|
||||||
<p class="title"><strong>ZITADEL {{features.tier.name}}</strong></p>
|
<p class="title"><strong>ZITADEL {{features.tier.name}}</strong></p>
|
||||||
<p>{{features.tier?.description}}</p>
|
<p>{{features.tier?.description}}</p>
|
||||||
|
@ -8,7 +8,7 @@ h2 {
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-desc {
|
.top-desc {
|
||||||
color: var(--grey);
|
color: var(--grey);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@ -20,43 +20,43 @@ h2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tier {
|
.tier {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: .5rem;
|
||||||
|
color: white;
|
||||||
|
background-color: rgb(245, 203, 99);
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
|
||||||
|
.ext {
|
||||||
|
margin-right: .5rem;
|
||||||
|
align-self: center;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-right: 1rem;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
padding: 1rem;
|
|
||||||
border-radius: .5rem;
|
|
||||||
color: white;
|
|
||||||
background-color: rgb(245, 203, 99);
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
|
|
||||||
.ext {
|
p {
|
||||||
margin-right: .5rem;
|
margin: 0;
|
||||||
align-self: center;
|
font-size: 14px;
|
||||||
color: inherit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mat-icon {
|
.title {
|
||||||
margin-right: 1rem;
|
font-size: 16px;
|
||||||
font-size: 2rem;
|
margin-bottom: .5rem;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.text {
|
.fill-space {
|
||||||
display: flex;
|
flex: 1;
|
||||||
flex-direction: column;
|
}
|
||||||
p {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.title {
|
|
||||||
font-size: 16px;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.fill-space {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.domain {
|
.domain {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class="max-width-container">
|
<div class="enlarged-container">
|
||||||
<h1>{{ 'ORG.PAGES.LIST' | translate }}</h1>
|
<h1>{{ 'ORG.PAGES.LIST' | translate }}</h1>
|
||||||
<p class="top-desc">{{'ORG.PAGES.LISTDESCRIPTION' | translate}}</p>
|
<p class="top-desc">{{'ORG.PAGES.LISTDESCRIPTION' | translate}}</p>
|
||||||
|
|
||||||
|
@ -23,6 +23,10 @@ h1 {
|
|||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pointer {
|
.pointer {
|
||||||
|
@ -11,7 +11,7 @@ import { Org, OrgNameQuery, OrgQuery } from 'src/app/proto/generated/zitadel/org
|
|||||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||||
|
|
||||||
enum OrgListSearchKey {
|
enum OrgListSearchKey {
|
||||||
NAME = "NAME",
|
NAME = 'NAME',
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -53,7 +53,7 @@ export class OrgListComponent implements AfterViewInit {
|
|||||||
this.loadingSubject.next(true);
|
this.loadingSubject.next(true);
|
||||||
let query;
|
let query;
|
||||||
if (filter) {
|
if (filter) {
|
||||||
const query = new OrgQuery();
|
query = new OrgQuery();
|
||||||
const orgNameQuery = new OrgNameQuery();
|
const orgNameQuery = new OrgNameQuery();
|
||||||
orgNameQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
orgNameQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
||||||
orgNameQuery.setName(filter);
|
orgNameQuery.setName(filter);
|
||||||
|
@ -51,7 +51,7 @@ p.desc {
|
|||||||
margin: 0 -1.5rem;
|
margin: 0 -1.5rem;
|
||||||
|
|
||||||
.formfield {
|
.formfield {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-title {
|
.step-title {
|
||||||
@ -126,4 +126,4 @@ p.desc {
|
|||||||
padding: .5rem 4rem;
|
padding: .5rem 4rem;
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,11 +78,17 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// set to oidc first
|
// set to oidc first
|
||||||
public authMethodTypes: { type: OIDCAuthMethodType | APIAuthMethodType, checked: boolean, disabled: boolean; api?: boolean; oidc?: boolean; }[] = [
|
public authMethodTypes: {
|
||||||
{ type: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_BASIC, checked: false, disabled: false, oidc: true },
|
type: OIDCAuthMethodType | APIAuthMethodType,
|
||||||
{ type: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE, checked: false, disabled: false, oidc: true },
|
checked: boolean,
|
||||||
{ type: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_POST, checked: false, disabled: false, oidc: true },
|
disabled: boolean;
|
||||||
];
|
api?: boolean;
|
||||||
|
oidc?: boolean;
|
||||||
|
}[] = [
|
||||||
|
{ type: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_BASIC, checked: false, disabled: false, oidc: true },
|
||||||
|
{ type: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE, checked: false, disabled: false, oidc: true },
|
||||||
|
{ type: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_POST, checked: false, disabled: false, oidc: true },
|
||||||
|
];
|
||||||
|
|
||||||
// stepper
|
// stepper
|
||||||
firstFormGroup!: FormGroup;
|
firstFormGroup!: FormGroup;
|
||||||
@ -196,11 +202,18 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
const partialConfig = getPartialConfigFromAuthMethod(form.authMethod);
|
const partialConfig = getPartialConfigFromAuthMethod(form.authMethod);
|
||||||
|
|
||||||
if (this.isStepperOIDC && partialConfig && partialConfig.oidc) {
|
if (this.isStepperOIDC && partialConfig && partialConfig.oidc) {
|
||||||
this.oidcAppRequest.responseTypesList = partialConfig.oidc?.responseTypesList ?? [];
|
this.oidcAppRequest.responseTypesList = partialConfig.oidc?.responseTypesList
|
||||||
this.oidcAppRequest.grantTypesList = partialConfig.oidc?.grantTypesList ?? [];
|
?? [];
|
||||||
this.oidcAppRequest.authMethodType = partialConfig.oidc?.authMethodType ?? OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE;
|
|
||||||
|
this.oidcAppRequest.grantTypesList = partialConfig.oidc?.grantTypesList
|
||||||
|
?? [];
|
||||||
|
|
||||||
|
this.oidcAppRequest.authMethodType = partialConfig.oidc?.authMethodType
|
||||||
|
?? OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE;
|
||||||
|
|
||||||
} else if (this.isStepperAPI && partialConfig && partialConfig.api) {
|
} else if (this.isStepperAPI && partialConfig && partialConfig.api) {
|
||||||
this.apiAppRequest.authMethodType = partialConfig.api?.authMethodType ?? APIAuthMethodType.API_AUTH_METHOD_TYPE_BASIC;
|
this.apiAppRequest.authMethodType = partialConfig.api?.authMethodType
|
||||||
|
?? APIAuthMethodType.API_AUTH_METHOD_TYPE_BASIC;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -265,10 +278,10 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
this.form.updateValueAndValidity();
|
this.form.updateValueAndValidity();
|
||||||
}
|
}
|
||||||
|
|
||||||
public changeStep(event: StepperSelectionEvent) {
|
public changeStep(event: StepperSelectionEvent): void {
|
||||||
if (event.selectedIndex >= 2) {
|
if (event.selectedIndex >= 2) {
|
||||||
this.requestRedirectValuesSubject$.next();
|
this.requestRedirectValuesSubject$.next();
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getData({ projectid }: Params): Promise<void> {
|
private async getData({ projectid }: Params): Promise<void> {
|
||||||
@ -335,8 +348,8 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
const dialogRef = this.dialog.open(AppSecretDialogComponent, {
|
const dialogRef = this.dialog.open(AppSecretDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
clientSecret: clientSecret,
|
clientSecret: clientSecret,
|
||||||
clientId: clientId
|
clientId: clientId,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(() => {
|
dialogRef.afterClosed().subscribe(() => {
|
||||||
@ -382,19 +395,19 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get isDevOIDC(): boolean {
|
get isDevOIDC(): boolean {
|
||||||
return (this.formappType?.value as RadioItemAppType).createType == AppCreateType.OIDC;
|
return (this.formappType?.value as RadioItemAppType).createType === AppCreateType.OIDC;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isStepperOIDC(): boolean {
|
get isStepperOIDC(): boolean {
|
||||||
return (this.appType?.value as RadioItemAppType).createType == AppCreateType.OIDC;
|
return (this.appType?.value as RadioItemAppType).createType === AppCreateType.OIDC;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isDevAPI(): boolean {
|
get isDevAPI(): boolean {
|
||||||
return (this.formappType?.value as RadioItemAppType).createType == AppCreateType.API;
|
return (this.formappType?.value as RadioItemAppType).createType === AppCreateType.API;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isStepperAPI(): boolean {
|
get isStepperAPI(): boolean {
|
||||||
return (this.appType?.value as RadioItemAppType).createType == AppCreateType.API;
|
return (this.appType?.value as RadioItemAppType).createType === AppCreateType.API;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<ng-template appHasRole [appHasRole]="['project.app.write:'+projectId, 'project.app.write']">
|
<ng-template appHasRole [appHasRole]="['project.app.write:'+projectId, 'project.app.write']">
|
||||||
|
|
||||||
<button *ngIf="!editState" matTooltip="{{'ACTIONS.EDIT' | translate}}" mat-icon-button
|
<button *ngIf="!editState" matTooltip="{{'ACTIONS.EDIT' | translate}}" mat-icon-button
|
||||||
(click)="editState = !editState" aria-label="edit app name">
|
(click)="editState = !editState" aria-label="edit app name">
|
||||||
<i class="las la-edit"></i>
|
<i class="las la-edit"></i>
|
||||||
</button>
|
</button>
|
||||||
<button *ngIf="editState" (click)="saveApp()" [disabled]="appNameForm.invalid || name?.disabled"
|
<button *ngIf="editState" (click)="saveApp()" [disabled]="appNameForm.invalid || name?.disabled"
|
||||||
@ -22,22 +22,24 @@
|
|||||||
<i class="las la-save"></i>
|
<i class="las la-save"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<ng-template appHasRole [appHasRole]="['project.app.delete:'+projectId, 'project.app.delete']">
|
||||||
|
<button matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" mat-icon-button
|
||||||
|
(click)="deleteApp()" aria-label="delete app">
|
||||||
|
<i class="las la-trash"></i>
|
||||||
|
</button>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<span class="fill-space"></span>
|
||||||
|
|
||||||
<button class="state-button" mat-stroked-button color="warn"
|
<button class="state-button" mat-stroked-button color="warn"
|
||||||
*ngIf="app.state !== undefined && app?.state !== AppState.APP_STATE_INACTIVE"
|
*ngIf="app && app.state !== undefined && app?.state !== AppState.APP_STATE_INACTIVE"
|
||||||
(click)="changeState(AppState.APP_STATE_INACTIVE)">
|
(click)="changeState(AppState.APP_STATE_INACTIVE)">
|
||||||
{{'ACTIONS.DEACTIVATE' | translate}}
|
{{'ACTIONS.DEACTIVATE' | translate}}
|
||||||
</button>
|
</button>
|
||||||
<button class="state-button" mat-stroked-button
|
<button class="state-button" mat-stroked-button
|
||||||
*ngIf="app.state !== undefined && app?.state !== AppState.APP_STATE_ACTIVE"
|
*ngIf="app && app.state !== undefined && app?.state !== AppState.APP_STATE_ACTIVE"
|
||||||
(click)="changeState(AppState.APP_STATE_ACTIVE)">
|
(click)="changeState(AppState.APP_STATE_ACTIVE)">
|
||||||
{{'ACTIONS.REACTIVATE' | translate}}
|
{{'ACTIONS.REACTIVATE' | translate}}
|
||||||
</button>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<ng-template appHasRole [appHasRole]="['project.app.delete:'+projectId, 'project.app.delete']">
|
|
||||||
<button matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" mat-icon-button
|
|
||||||
(click)="deleteApp()" aria-label="delete app">
|
|
||||||
<i class="las la-trash"></i>
|
|
||||||
</button>
|
</button>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@ -112,7 +114,7 @@
|
|||||||
</cnsl-info-section>
|
</cnsl-info-section>
|
||||||
|
|
||||||
<cnsl-info-section class="step-description"
|
<cnsl-info-section class="step-description"
|
||||||
*ngIf="OIDCAppType?.value == OIDCAppType.OIDC_APP_TYPE_WEB || appType?.value == OIDCAppType.OIDC_APP_TYPE_USER_AGENT">
|
*ngIf="appType?.value == OIDCAppType.OIDC_APP_TYPE_WEB || appType?.value == OIDCAppType.OIDC_APP_TYPE_USER_AGENT">
|
||||||
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}
|
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}
|
||||||
</cnsl-info-section>
|
</cnsl-info-section>
|
||||||
|
|
||||||
@ -142,7 +144,7 @@
|
|||||||
<app-client-keys [projectId]="projectId" [appId]="app.id"></app-client-keys>
|
<app-client-keys [projectId]="projectId" [appId]="app.id"></app-client-keys>
|
||||||
</app-card>
|
</app-card>
|
||||||
|
|
||||||
<div *ngIf="oidcForm && app?.apiConfig" class="btn-container">
|
<div *ngIf="apiForm && app?.apiConfig" class="btn-container">
|
||||||
<button class="submit-button" (click)="saveAPIApp()" color="primary"
|
<button class="submit-button" (click)="saveAPIApp()" color="primary"
|
||||||
[disabled]="apiForm.invalid || !canWrite" mat-raised-button>
|
[disabled]="apiForm.invalid || !canWrite" mat-raised-button>
|
||||||
{{ 'ACTIONS.SAVE' | translate }}
|
{{ 'ACTIONS.SAVE' | translate }}
|
||||||
|
@ -11,20 +11,23 @@
|
|||||||
.title-col {
|
.title-col {
|
||||||
margin-left: 2rem;
|
margin-left: 2rem;
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
min-width: 200px;
|
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
margin: 0 0 0 0;
|
margin: 0 0 0 0;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--grey);
|
color: var(--grey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fill-space {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.desc {
|
.desc {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
@ -39,7 +42,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.state-button {
|
.state-button {
|
||||||
margin: 0 .5rem;
|
margin-left: .5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,43 +52,44 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.environment-wrapper {
|
.environment-wrapper {
|
||||||
padding: 1rem 0;
|
padding: 1rem 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
.environment {
|
.environment {
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
|
|
||||||
.key {
|
.key {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--grey);
|
color: var(--grey);
|
||||||
}
|
|
||||||
.environment-row {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
overflow: hidden;
|
|
||||||
height: 30px;
|
|
||||||
|
|
||||||
button {
|
|
||||||
transition: opacity .15s ease-in-out;
|
|
||||||
visibility: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
&[disabled] {
|
|
||||||
visibility: visible;
|
|
||||||
color: white;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
button {
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.environment-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 30px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
transition: opacity .15s ease-in-out;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
visibility: visible;
|
||||||
|
color: white;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
button {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.compliance .problem {
|
.compliance .problem {
|
||||||
@ -147,8 +151,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.redirect-section {
|
.redirect-section {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin: 0 .5rem;
|
margin: 0 .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.formfield {
|
.formfield {
|
||||||
@ -159,9 +163,9 @@
|
|||||||
flex-basis: 100%;
|
flex-basis: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
margin: 1.5rem 0 0 0;
|
margin: 1.5rem 0 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-width {
|
.full-width {
|
||||||
|
@ -192,7 +192,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
}, {
|
}, {
|
||||||
i18nTitle: 'APP.PAGES.NEXTSTEPS.2.TITLE',
|
i18nTitle: 'APP.PAGES.NEXTSTEPS.2.TITLE',
|
||||||
i18nDesc: 'APP.PAGES.NEXTSTEPS.2.DESC',
|
i18nDesc: 'APP.PAGES.NEXTSTEPS.2.DESC',
|
||||||
href: 'https://docs.zitadel.ch'
|
href: 'https://docs.zitadel.ch',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -205,91 +205,94 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
this.mgmtService.getIAM().then(iam => {
|
this.mgmtService.getIAM().then(iam => {
|
||||||
this.isZitadel = iam.iamProjectId === this.projectId;
|
this.isZitadel = iam.iamProjectId === this.projectId;
|
||||||
});
|
});
|
||||||
this.authService.isAllowed(['project.app.write$', 'project.app.write:' + projectid]).pipe(take(1)).subscribe((allowed) => {
|
this.authService.isAllowed(['project.app.write$', 'project.app.write:' + projectid])
|
||||||
this.canWrite = allowed;
|
.pipe(take(1))
|
||||||
this.mgmtService.getAppByID(projectid, id).then(app => {
|
.subscribe((allowed) => {
|
||||||
if (app.app) {
|
this.canWrite = allowed;
|
||||||
this.app = app.app;
|
this.mgmtService.getAppByID(projectid, id).then(app => {
|
||||||
this.appNameForm.patchValue(this.app);
|
if (app.app) {
|
||||||
|
this.app = app.app;
|
||||||
|
this.appNameForm.patchValue(this.app);
|
||||||
|
|
||||||
if (this.app.oidcConfig) {
|
if (this.app.oidcConfig) {
|
||||||
this.getAuthMethodOptions('OIDC');
|
this.getAuthMethodOptions('OIDC');
|
||||||
|
|
||||||
this.initialAuthMethod = this.authMethodFromPartialConfig({ oidc: this.app.oidcConfig });
|
this.initialAuthMethod = this.authMethodFromPartialConfig({ oidc: this.app.oidcConfig });
|
||||||
this.currentAuthMethod = this.initialAuthMethod;
|
this.currentAuthMethod = this.initialAuthMethod;
|
||||||
if (this.initialAuthMethod === CUSTOM_METHOD.key) {
|
if (this.initialAuthMethod === CUSTOM_METHOD.key) {
|
||||||
if (!this.authMethods.includes(CUSTOM_METHOD)) {
|
if (!this.authMethods.includes(CUSTOM_METHOD)) {
|
||||||
this.authMethods.push(CUSTOM_METHOD);
|
this.authMethods.push(CUSTOM_METHOD);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.authMethods = this.authMethods.filter(element => element !== CUSTOM_METHOD);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (this.app.apiConfig) {
|
||||||
this.authMethods = this.authMethods.filter(element => element != CUSTOM_METHOD);
|
this.getAuthMethodOptions('API');
|
||||||
}
|
|
||||||
} else if (this.app.apiConfig) {
|
|
||||||
this.getAuthMethodOptions('API');
|
|
||||||
|
|
||||||
this.initialAuthMethod = this.authMethodFromPartialConfig({ api: this.app.apiConfig });
|
this.initialAuthMethod = this.authMethodFromPartialConfig({ api: this.app.apiConfig });
|
||||||
this.currentAuthMethod = this.initialAuthMethod;
|
this.currentAuthMethod = this.initialAuthMethod;
|
||||||
if (this.initialAuthMethod === CUSTOM_METHOD.key) {
|
if (this.initialAuthMethod === CUSTOM_METHOD.key) {
|
||||||
if (!this.authMethods.includes(CUSTOM_METHOD)) {
|
if (!this.authMethods.includes(CUSTOM_METHOD)) {
|
||||||
this.authMethods.push(CUSTOM_METHOD);
|
this.authMethods.push(CUSTOM_METHOD);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.authMethods = this.authMethods.filter(element => element !== CUSTOM_METHOD);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.authMethods = this.authMethods.filter(element => element != CUSTOM_METHOD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allowed) {
|
|
||||||
this.appNameForm.enable();
|
|
||||||
this.oidcForm.enable();
|
|
||||||
this.apiForm.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.app.oidcConfig?.redirectUrisList) {
|
|
||||||
this.redirectUrisList = this.app.oidcConfig.redirectUrisList;
|
|
||||||
}
|
|
||||||
if (this.app.oidcConfig?.postLogoutRedirectUrisList) {
|
|
||||||
this.postLogoutRedirectUrisList = this.app.oidcConfig.postLogoutRedirectUrisList;
|
|
||||||
}
|
|
||||||
if (this.app.oidcConfig?.clockSkew) {
|
|
||||||
const inSecs = this.app.oidcConfig?.clockSkew.seconds + this.app.oidcConfig?.clockSkew.nanos / 100000;
|
|
||||||
this.oidcForm.controls['clockSkewSeconds'].setValue(inSecs);
|
|
||||||
}
|
|
||||||
if (this.app.oidcConfig) {
|
|
||||||
this.oidcForm.patchValue(this.app.oidcConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.oidcForm.valueChanges.subscribe((oidcConfig) => {
|
|
||||||
this.initialAuthMethod = this.authMethodFromPartialConfig({ oidc: oidcConfig });
|
|
||||||
if (this.initialAuthMethod === CUSTOM_METHOD.key) {
|
|
||||||
if (!this.authMethods.includes(CUSTOM_METHOD)) {
|
|
||||||
this.authMethods.push(CUSTOM_METHOD);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.authMethods = this.authMethods.filter(element => element != CUSTOM_METHOD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showSaveSnack();
|
if (allowed) {
|
||||||
});
|
this.appNameForm.enable();
|
||||||
|
this.oidcForm.enable();
|
||||||
this.apiForm.valueChanges.subscribe((apiConfig) => {
|
this.apiForm.enable();
|
||||||
this.initialAuthMethod = this.authMethodFromPartialConfig({ api: apiConfig });
|
|
||||||
if (this.initialAuthMethod === CUSTOM_METHOD.key) {
|
|
||||||
if (!this.authMethods.includes(CUSTOM_METHOD)) {
|
|
||||||
this.authMethods.push(CUSTOM_METHOD);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.authMethods = this.authMethods.filter(element => element != CUSTOM_METHOD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showSaveSnack();
|
if (this.app.oidcConfig?.redirectUrisList) {
|
||||||
});
|
this.redirectUrisList = this.app.oidcConfig.redirectUrisList;
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
if (this.app.oidcConfig?.postLogoutRedirectUrisList) {
|
||||||
console.error(error);
|
this.postLogoutRedirectUrisList = this.app.oidcConfig.postLogoutRedirectUrisList;
|
||||||
this.toast.showError(error);
|
}
|
||||||
this.errorMessage = error.message;
|
if (this.app.oidcConfig?.clockSkew) {
|
||||||
|
const inSecs = this.app.oidcConfig?.clockSkew.seconds +
|
||||||
|
this.app.oidcConfig?.clockSkew.nanos / 100000;
|
||||||
|
this.oidcForm.controls['clockSkewSeconds'].setValue(inSecs);
|
||||||
|
}
|
||||||
|
if (this.app.oidcConfig) {
|
||||||
|
this.oidcForm.patchValue(this.app.oidcConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.oidcForm.valueChanges.subscribe((oidcConfig) => {
|
||||||
|
this.initialAuthMethod = this.authMethodFromPartialConfig({ oidc: oidcConfig });
|
||||||
|
if (this.initialAuthMethod === CUSTOM_METHOD.key) {
|
||||||
|
if (!this.authMethods.includes(CUSTOM_METHOD)) {
|
||||||
|
this.authMethods.push(CUSTOM_METHOD);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.authMethods = this.authMethods.filter(element => element !== CUSTOM_METHOD);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showSaveSnack();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.apiForm.valueChanges.subscribe((apiConfig) => {
|
||||||
|
this.initialAuthMethod = this.authMethodFromPartialConfig({ api: apiConfig });
|
||||||
|
if (this.initialAuthMethod === CUSTOM_METHOD.key) {
|
||||||
|
if (!this.authMethods.includes(CUSTOM_METHOD)) {
|
||||||
|
this.authMethods.push(CUSTOM_METHOD);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.authMethods = this.authMethods.filter(element => element !== CUSTOM_METHOD);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showSaveSnack();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
console.error(error);
|
||||||
|
this.toast.showError(error);
|
||||||
|
this.errorMessage = error.message;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
this.docs = (await this.mgmtService.getOIDCInformation());
|
this.docs = (await this.mgmtService.getOIDCInformation());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +311,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getAuthMethodOptions(type: string): void {
|
private getAuthMethodOptions(type: string): void {
|
||||||
if (type == 'OIDC') {
|
if (type === 'OIDC') {
|
||||||
switch (this.app.oidcConfig?.appType) {
|
switch (this.app.oidcConfig?.appType) {
|
||||||
case OIDCAppType.OIDC_APP_TYPE_NATIVE:
|
case OIDCAppType.OIDC_APP_TYPE_NATIVE:
|
||||||
this.authMethods = [
|
this.authMethods = [
|
||||||
@ -332,7 +335,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type == 'API') {
|
if (type === 'API') {
|
||||||
this.authMethods = [
|
this.authMethods = [
|
||||||
PK_JWT_METHOD,
|
PK_JWT_METHOD,
|
||||||
BASIC_AUTH_METHOD,
|
BASIC_AUTH_METHOD,
|
||||||
@ -348,12 +351,24 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
public setPartialConfigFromAuthMethod(authMethod: string): void {
|
public setPartialConfigFromAuthMethod(authMethod: string): void {
|
||||||
const partialConfig = getPartialConfigFromAuthMethod(authMethod);
|
const partialConfig = getPartialConfigFromAuthMethod(authMethod);
|
||||||
if (partialConfig && partialConfig.oidc && this.app.oidcConfig) {
|
if (partialConfig && partialConfig.oidc && this.app.oidcConfig) {
|
||||||
this.app.oidcConfig.responseTypesList = (partialConfig.oidc as Partial<OIDCConfig.AsObject>).responseTypesList ?? [];
|
this.app.oidcConfig.responseTypesList =
|
||||||
this.app.oidcConfig.grantTypesList = (partialConfig.oidc as Partial<OIDCConfig.AsObject>).grantTypesList ?? [];
|
(partialConfig.oidc as Partial<OIDCConfig.AsObject>).responseTypesList
|
||||||
this.app.oidcConfig.authMethodType = (partialConfig.oidc as Partial<OIDCConfig.AsObject>).authMethodType ?? OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE;
|
?? [];
|
||||||
|
|
||||||
|
this.app.oidcConfig.grantTypesList =
|
||||||
|
(partialConfig.oidc as Partial<OIDCConfig.AsObject>).grantTypesList
|
||||||
|
?? [];
|
||||||
|
|
||||||
|
this.app.oidcConfig.authMethodType =
|
||||||
|
(partialConfig.oidc as Partial<OIDCConfig.AsObject>).authMethodType
|
||||||
|
?? OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE;
|
||||||
|
|
||||||
this.oidcForm.patchValue(this.app.oidcConfig);
|
this.oidcForm.patchValue(this.app.oidcConfig);
|
||||||
} else if (partialConfig && partialConfig.api && this.app.apiConfig) {
|
} else if (partialConfig && partialConfig.api && this.app.apiConfig) {
|
||||||
this.app.apiConfig.authMethodType = (partialConfig.api as Partial<APIConfig.AsObject>).authMethodType ?? APIAuthMethodType.API_AUTH_METHOD_TYPE_BASIC;
|
this.app.apiConfig.authMethodType =
|
||||||
|
(partialConfig.api as Partial<APIConfig.AsObject>).authMethodType
|
||||||
|
?? APIAuthMethodType.API_AUTH_METHOD_TYPE_BASIC;
|
||||||
|
|
||||||
this.apiAuthMethodType?.setValue(this.app.apiConfig.authMethodType);
|
this.apiAuthMethodType?.setValue(this.app.apiConfig.authMethodType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ export function getPartialConfigFromAuthMethod(authMethod: string): {
|
|||||||
responseTypesList: [OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
responseTypesList: [OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
||||||
grantTypesList: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
grantTypesList: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
||||||
authMethodType: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
authMethodType: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
return config;
|
return config;
|
||||||
case POST_METHOD.key:
|
case POST_METHOD.key:
|
||||||
@ -125,7 +125,7 @@ export function getPartialConfigFromAuthMethod(authMethod: string): {
|
|||||||
responseTypesList: [OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
responseTypesList: [OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
||||||
grantTypesList: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
grantTypesList: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
||||||
authMethodType: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_POST,
|
authMethodType: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_POST,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
return config;
|
return config;
|
||||||
case PK_JWT_METHOD.key:
|
case PK_JWT_METHOD.key:
|
||||||
@ -137,7 +137,7 @@ export function getPartialConfigFromAuthMethod(authMethod: string): {
|
|||||||
},
|
},
|
||||||
api: {
|
api: {
|
||||||
authMethodType: APIAuthMethodType.API_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT,
|
authMethodType: APIAuthMethodType.API_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
return config;
|
return config;
|
||||||
case BASIC_AUTH_METHOD.key:
|
case BASIC_AUTH_METHOD.key:
|
||||||
@ -147,7 +147,7 @@ export function getPartialConfigFromAuthMethod(authMethod: string): {
|
|||||||
},
|
},
|
||||||
api: {
|
api: {
|
||||||
authMethodType: APIAuthMethodType.API_AUTH_METHOD_TYPE_BASIC,
|
authMethodType: APIAuthMethodType.API_AUTH_METHOD_TYPE_BASIC,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
return config;
|
return config;
|
||||||
case IMPLICIT_METHOD.key:
|
case IMPLICIT_METHOD.key:
|
||||||
@ -159,7 +159,7 @@ export function getPartialConfigFromAuthMethod(authMethod: string): {
|
|||||||
},
|
},
|
||||||
api: {
|
api: {
|
||||||
authMethodType: APIAuthMethodType.API_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT,
|
authMethodType: APIAuthMethodType.API_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
return config;
|
return config;
|
||||||
default:
|
default:
|
||||||
@ -167,7 +167,12 @@ export function getPartialConfigFromAuthMethod(authMethod: string): {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAuthMethodFromPartialConfig(config: { oidc?: Partial<OIDCConfig.AsObject>, api?: Partial<APIConfig.AsObject>; }): string {
|
export function getAuthMethodFromPartialConfig(
|
||||||
|
config: {
|
||||||
|
oidc?: Partial<OIDCConfig.AsObject>,
|
||||||
|
api?: Partial<APIConfig.AsObject>,
|
||||||
|
},
|
||||||
|
): string {
|
||||||
if (config?.oidc) {
|
if (config?.oidc) {
|
||||||
const toCheck = [config.oidc.responseTypesList, config.oidc.grantTypesList, config.oidc.authMethodType];
|
const toCheck = [config.oidc.responseTypesList, config.oidc.grantTypesList, config.oidc.authMethodType];
|
||||||
const code = JSON.stringify(
|
const code = JSON.stringify(
|
||||||
@ -175,7 +180,7 @@ export function getAuthMethodFromPartialConfig(config: { oidc?: Partial<OIDCConf
|
|||||||
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
||||||
[OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
[OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
||||||
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_BASIC,
|
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_BASIC,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const pkce = JSON.stringify(
|
const pkce = JSON.stringify(
|
||||||
@ -183,7 +188,7 @@ export function getAuthMethodFromPartialConfig(config: { oidc?: Partial<OIDCConf
|
|||||||
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
||||||
[OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
[OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
||||||
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const post = JSON.stringify(
|
const post = JSON.stringify(
|
||||||
@ -191,15 +196,15 @@ export function getAuthMethodFromPartialConfig(config: { oidc?: Partial<OIDCConf
|
|||||||
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
||||||
[OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
[OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
||||||
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_POST,
|
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_POST,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const pk_jwt = JSON.stringify(
|
const pkjwt = JSON.stringify(
|
||||||
[
|
[
|
||||||
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
||||||
[OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
[OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
||||||
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT,
|
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const implicit = JSON.stringify(
|
const implicit = JSON.stringify(
|
||||||
@ -207,14 +212,14 @@ export function getAuthMethodFromPartialConfig(config: { oidc?: Partial<OIDCConf
|
|||||||
[OIDCResponseType.OIDC_RESPONSE_TYPE_ID_TOKEN_TOKEN],
|
[OIDCResponseType.OIDC_RESPONSE_TYPE_ID_TOKEN_TOKEN],
|
||||||
[OIDCGrantType.OIDC_GRANT_TYPE_IMPLICIT],
|
[OIDCGrantType.OIDC_GRANT_TYPE_IMPLICIT],
|
||||||
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
switch (JSON.stringify(toCheck)) {
|
switch (JSON.stringify(toCheck)) {
|
||||||
case code: return CODE_METHOD.key;
|
case code: return CODE_METHOD.key;
|
||||||
case pkce: return PKCE_METHOD.key;
|
case pkce: return PKCE_METHOD.key;
|
||||||
case post: return POST_METHOD.key;
|
case post: return POST_METHOD.key;
|
||||||
case pk_jwt: return PK_JWT_METHOD.key;
|
case pkjwt: return PK_JWT_METHOD.key;
|
||||||
case implicit: return IMPLICIT_METHOD.key;
|
case implicit: return IMPLICIT_METHOD.key;
|
||||||
default:
|
default:
|
||||||
return CUSTOM_METHOD.key;
|
return CUSTOM_METHOD.key;
|
||||||
@ -229,4 +234,4 @@ export function getAuthMethodFromPartialConfig(config: { oidc?: Partial<OIDCConf
|
|||||||
} else {
|
} else {
|
||||||
return CUSTOM_METHOD.key;
|
return CUSTOM_METHOD.key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@ import { OIDCAppType } from 'src/app/proto/generated/zitadel/app_pb';
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
export enum AppCreateType {
|
export enum AppCreateType {
|
||||||
API = "API",
|
API = 'API',
|
||||||
OIDC = "OIDC"
|
OIDC = 'OIDC',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RadioItemAppType {
|
export interface RadioItemAppType {
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
<span class="uri"
|
<span class="uri"
|
||||||
[ngClass]="{'green': !devMode && uri?.startsWith('https://'), 'red': !devMode && !uri?.startsWith('https://')}">{{uri}}</span>
|
[ngClass]="{'green': !devMode && uri?.startsWith('https://'), 'red': !devMode && !uri?.startsWith('https://')}">{{uri}}</span>
|
||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
<i *ngIf="!devMode && !(uri | redirect : isNative)" class="las la-exclamation red"></i>
|
<i *ngIf="!devMode && !(uri | redirect : isNative)" class="las la-exclamation red" [matTooltip]="isNative ? ('APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate) : ('APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate)"></i>
|
||||||
|
|
||||||
<button matTooltip="{{'ACTIONS.DELETE' | translate}}" mat-icon-button (click)="remove(uri)" class="icon-button">
|
<button matTooltip="{{'ACTIONS.DELETE' | translate}}" mat-icon-button (click)="remove(uri)" class="icon-button">
|
||||||
<mat-icon>cancel</mat-icon>
|
<mat-icon class="icon">cancel</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,61 +1,62 @@
|
|||||||
.form {
|
.form {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
|
|
||||||
.formfield {
|
.formfield {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
margin-right: -0.5rem;
|
margin-right: -.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.uri-list {
|
.uri-list {
|
||||||
margin: 0 .5rem;
|
margin: 0 .5rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.uri-line {
|
.uri-line {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.uri {
|
.uri {
|
||||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
|
||||||
|
|
||||||
.fill-space {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.green {
|
|
||||||
font-size: 1rem;
|
|
||||||
line-height: 35px;
|
|
||||||
height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.red {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
height: 30px;
|
|
||||||
line-height: 30px;
|
|
||||||
|
|
||||||
mat-icon {
|
|
||||||
font-size: 1rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(:hover) {
|
|
||||||
color: var(--grey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fill-space {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.green {
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 35px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.red {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button {
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:hover) {
|
||||||
|
color: var(--grey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #f44336;
|
color: #f44336;
|
||||||
margin: 0 .5rem 1.5rem .5rem;
|
margin: 0 .5rem 1.5rem .5rem;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ describe('RedirectUrisComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ RedirectUrisComponent ]
|
declarations: [ RedirectUrisComponent ],
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
});
|
});
|
||||||
|
@ -5,7 +5,7 @@ import { Observable, Subscription } from 'rxjs';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'cnsl-redirect-uris',
|
selector: 'cnsl-redirect-uris',
|
||||||
templateUrl: './redirect-uris.component.html',
|
templateUrl: './redirect-uris.component.html',
|
||||||
styleUrls: ['./redirect-uris.component.scss']
|
styleUrls: ['./redirect-uris.component.scss'],
|
||||||
})
|
})
|
||||||
export class RedirectUrisComponent implements OnInit, OnDestroy {
|
export class RedirectUrisComponent implements OnInit, OnDestroy {
|
||||||
@Input() title: string = '';
|
@Input() title: string = '';
|
||||||
|
@ -74,8 +74,8 @@
|
|||||||
<i class="las la-exclamation"></i>
|
<i class="las la-exclamation"></i>
|
||||||
<span>{{'PROJECT.TABLE.EMPTY' | translate}}</span>
|
<span>{{'PROJECT.TABLE.EMPTY' | translate}}</span>
|
||||||
</div>
|
</div>
|
||||||
<mat-paginator class="paginator" #paginator [length]="totalResult" [pageSize]="10"
|
<cnsl-paginator class="paginator" #paginator [timestamp]="viewTimestamp" [length]="totalResult" [pageSize]="10"
|
||||||
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
|
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></cnsl-paginator>
|
||||||
</div>
|
</div>
|
||||||
</app-refresh-table>
|
</app-refresh-table>
|
||||||
</div>
|
</div>
|
@ -1,12 +1,12 @@
|
|||||||
import { animate, animateChild, query, stagger, style, transition, trigger } from '@angular/animations';
|
import { animate, animateChild, query, stagger, style, transition, trigger } from '@angular/animations';
|
||||||
import { SelectionModel } from '@angular/cdk/collections';
|
import { SelectionModel } from '@angular/cdk/collections';
|
||||||
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||||
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
||||||
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
|
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
|
||||||
|
import { PageEvent, PaginatorComponent } from 'src/app/modules/paginator/paginator.component';
|
||||||
import { GrantedProject } from 'src/app/proto/generated/zitadel/project_pb';
|
import { GrantedProject } from 'src/app/proto/generated/zitadel/project_pb';
|
||||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
@ -41,7 +41,7 @@ export class GrantedProjectListComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
public dataSource: MatTableDataSource<GrantedProject.AsObject> =
|
public dataSource: MatTableDataSource<GrantedProject.AsObject> =
|
||||||
new MatTableDataSource<GrantedProject.AsObject>();
|
new MatTableDataSource<GrantedProject.AsObject>();
|
||||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||||
|
|
||||||
public grantedProjectList: GrantedProject.AsObject[] = [];
|
public grantedProjectList: GrantedProject.AsObject[] = [];
|
||||||
public displayedColumns: string[] = ['select', 'name', 'resourceOwnerName', 'state', 'creationDate', 'changeDate'];
|
public displayedColumns: string[] = ['select', 'name', 'resourceOwnerName', 'state', 'creationDate', 'changeDate'];
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class="max-width-container">
|
<div class="enlarged-container">
|
||||||
<h1>{{ 'PROJECT.PAGES.LIST' | translate }}</h1>
|
<h1>{{ 'PROJECT.PAGES.LIST' | translate }}</h1>
|
||||||
<p class="sub">{{ 'PROJECT.PAGES.LISTDESCRIPTION' | translate }}</p>
|
<p class="sub">{{ 'PROJECT.PAGES.LISTDESCRIPTION' | translate }}</p>
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
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 { MatPaginatorModule } from '@angular/material/paginator';
|
|
||||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
@ -20,6 +19,7 @@ import { ChangesModule } from 'src/app/modules/changes/changes.module';
|
|||||||
import { ContributorsModule } from 'src/app/modules/contributors/contributors.module';
|
import { ContributorsModule } from 'src/app/modules/contributors/contributors.module';
|
||||||
import { InputModule } from 'src/app/modules/input/input.module';
|
import { InputModule } from 'src/app/modules/input/input.module';
|
||||||
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
|
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
|
||||||
|
import { PaginatorModule } from 'src/app/modules/paginator/paginator.module';
|
||||||
import { ProjectRolesModule } from 'src/app/modules/project-roles/project-roles.module';
|
import { ProjectRolesModule } from 'src/app/modules/project-roles/project-roles.module';
|
||||||
import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.module';
|
import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.module';
|
||||||
import { SharedModule } from 'src/app/modules/shared/shared.module';
|
import { SharedModule } from 'src/app/modules/shared/shared.module';
|
||||||
@ -51,7 +51,7 @@ import { GrantedProjectsComponent } from './granted-projects.component';
|
|||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
HasRoleModule,
|
HasRoleModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatPaginatorModule,
|
PaginatorModule,
|
||||||
InputModule,
|
InputModule,
|
||||||
ChangesModule,
|
ChangesModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user