mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:17:23 +00:00
fix(console): intercept navigator.language, set browser lang as default for user without explicit setting, user table outline, member create dialog import (#820)
* i18n interceptor, set language to browser lang * nullcheck * rm external idp log * fix module imports, rm user displayname from i18n * Update console/src/assets/i18n/de.json Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
parent
0bbc9c7c49
commit
286bba1c70
@ -220,7 +220,9 @@ export class AppComponent implements OnDestroy {
|
||||
|
||||
this.authService.user.subscribe(userprofile => {
|
||||
this.profile = userprofile;
|
||||
const lang = userprofile.preferredLanguage.match(/en|de/) ? userprofile.preferredLanguage : 'en';
|
||||
const cropped = navigator.language.split('-')[0] ?? 'en';
|
||||
const fallbackLang = cropped.match(/en|de/) ? cropped : 'en';
|
||||
const lang = userprofile.preferredLanguage.match(/en|de/) ? userprofile.preferredLanguage : fallbackLang;
|
||||
this.translate.use(lang);
|
||||
this.document.documentElement.lang = lang;
|
||||
});
|
||||
|
@ -40,6 +40,7 @@ import { GrpcAuthService } from './services/grpc-auth.service';
|
||||
import { GrpcService } from './services/grpc.service';
|
||||
import { AuthInterceptor } from './services/interceptors/auth.interceptor';
|
||||
import { GRPC_INTERCEPTORS } from './services/interceptors/grpc-interceptor';
|
||||
import { I18nInterceptor } from './services/interceptors/i18n.interceptor';
|
||||
import { OrgInterceptor } from './services/interceptors/org.interceptor';
|
||||
import { RefreshService } from './services/refresh.service';
|
||||
import { StatehandlerProcessorService, StatehandlerProcessorServiceImpl } from './services/statehandler-processor.service';
|
||||
@ -156,6 +157,11 @@ const authConfig: AuthConfig = {
|
||||
multi: true,
|
||||
useClass: AuthInterceptor,
|
||||
},
|
||||
{
|
||||
provide: GRPC_INTERCEPTORS,
|
||||
multi: true,
|
||||
useClass: I18nInterceptor,
|
||||
},
|
||||
{
|
||||
provide: GRPC_INTERCEPTORS,
|
||||
multi: true,
|
||||
|
@ -2,8 +2,10 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { SearchUserAutocompleteModule } from 'src/app/modules/search-user-autocomplete/search-user-autocomplete.module';
|
||||
@ -21,6 +23,8 @@ import { MemberCreateDialogComponent } from './member-create-dialog.component';
|
||||
CommonModule,
|
||||
MatDialogModule,
|
||||
MatButtonModule,
|
||||
MatChipsModule,
|
||||
MatInputModule,
|
||||
TranslateModule,
|
||||
MatFormFieldModule,
|
||||
MatSelectModule,
|
||||
|
@ -4,12 +4,12 @@
|
||||
<button (click)="deactivateSelectedIdps()" matTooltip="{{'IDP.DEACTIVATE' | translate}}" class="icon-button"
|
||||
mat-icon-button *ngIf="selection.hasValue() && serviceType!=PolicyComponentServiceType.MGMT"
|
||||
[disabled]="disabled">
|
||||
<mat-icon svgIcon="mdi_account_cancel"></mat-icon>
|
||||
<mat-icon>block</mat-icon>
|
||||
</button>
|
||||
<button (click)="reactivateSelectedIdps()" matTooltip="{{'IDP.ACTIVATE' | translate}}" class="icon-button"
|
||||
mat-icon-button *ngIf="selection.hasValue() && serviceType!=PolicyComponentServiceType.MGMT"
|
||||
[disabled]="disabled">
|
||||
<mat-icon svgIcon="mdi_account_check_outline"></mat-icon>
|
||||
<mat-icon>play_circle_outline</mat-icon>
|
||||
</button>
|
||||
<button color="warn" (click)="removeSelectedIdps()" matTooltip="{{'IDP.DELETE' | translate}}"
|
||||
class="icon-button" mat-icon-button
|
||||
|
@ -10,6 +10,7 @@ import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.
|
||||
import { MembersTableModule } from 'src/app/modules/members-table/members-table.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { MemberCreateDialogModule } from '../add-member-dialog/member-create-dialog.module';
|
||||
import { ProjectMembersRoutingModule } from './project-members-routing.module';
|
||||
import { ProjectMembersComponent } from './project-members.component';
|
||||
|
||||
@ -27,6 +28,7 @@ import { ProjectMembersComponent } from './project-members.component';
|
||||
MatDialogModule,
|
||||
MembersTableModule,
|
||||
HasRolePipeModule,
|
||||
MemberCreateDialogModule,
|
||||
],
|
||||
})
|
||||
export class ProjectMembersModule { }
|
||||
|
@ -5,6 +5,7 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { MemberCreateDialogModule } from 'src/app/modules/add-member-dialog/member-create-dialog.module';
|
||||
import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module';
|
||||
import { MembersTableModule } from 'src/app/modules/members-table/members-table.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
@ -26,6 +27,7 @@ import { IamMembersComponent } from './iam-members.component';
|
||||
TranslateModule,
|
||||
MembersTableModule,
|
||||
HasRolePipeModule,
|
||||
MemberCreateDialogModule,
|
||||
],
|
||||
})
|
||||
export class IamMembersModule { }
|
||||
|
@ -6,6 +6,7 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { MemberCreateDialogModule } from 'src/app/modules/add-member-dialog/member-create-dialog.module';
|
||||
import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module';
|
||||
import { MembersTableModule } from 'src/app/modules/members-table/members-table.module';
|
||||
import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.module';
|
||||
@ -30,6 +31,7 @@ import { OrgMembersComponent } from './org-members.component';
|
||||
RefreshTableModule,
|
||||
MembersTableModule,
|
||||
HasRolePipeModule,
|
||||
MemberCreateDialogModule,
|
||||
],
|
||||
})
|
||||
export class OrgMembersModule { }
|
||||
|
@ -47,7 +47,6 @@ import { PolicyGridComponent } from './policy-grid/policy-grid.component';
|
||||
MetaLayoutModule,
|
||||
MatTabsModule,
|
||||
MatTooltipModule,
|
||||
MatDialogModule,
|
||||
WarnDialogModule,
|
||||
MemberCreateDialogModule,
|
||||
MatMenuModule,
|
||||
|
@ -67,7 +67,6 @@ export class ExternalIdpsComponent implements OnInit {
|
||||
promise.then(resp => {
|
||||
this.externalIdpResult = resp.toObject();
|
||||
this.dataSource.data = this.externalIdpResult.resultList;
|
||||
console.log(this.externalIdpResult.resultList);
|
||||
this.loadingSubject.next(false);
|
||||
}).catch((error: any) => {
|
||||
this.toast.showError(error);
|
||||
|
@ -199,8 +199,6 @@ export class UserDetailComponent implements OnInit, OnDestroy {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'USER.DIALOG.DELETE_TITLE',
|
||||
descriptionParam: this.user.human ??
|
||||
this.user.machine ? { displayName: this.user.machine?.name } : { displayName: '' },
|
||||
descriptionKey: 'USER.DIALOG.DELETE_DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
|
@ -126,7 +126,7 @@
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let user">
|
||||
<button [disabled]="(['user.delete$', 'user.delete:'+user.id] | hasRole | async) == false"
|
||||
color="warn" mat-icon-button matTooltip="{{'IAM.VIEWS.DELETE' | translate}}"
|
||||
color="warn" mat-icon-button matTooltip="{{'USER.PAGES.DELETE' | translate}}"
|
||||
(click)="deleteUser(user)">
|
||||
<i class="las la-trash"></i>
|
||||
</button>
|
||||
|
@ -8,6 +8,7 @@
|
||||
td,
|
||||
th {
|
||||
padding: .5rem;
|
||||
outline: none;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 0;
|
||||
@ -27,8 +28,6 @@
|
||||
}
|
||||
|
||||
tr {
|
||||
outline: none;
|
||||
|
||||
button {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
@ -152,7 +152,6 @@ export class UserTableComponent implements OnInit {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'USER.DIALOG.DELETE_TITLE',
|
||||
descriptionParam: user.human ?? user.machine ? { displayName: user.machine?.name } : { displayName: '' },
|
||||
descriptionKey: 'USER.DIALOG.DELETE_DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
|
@ -9,6 +9,7 @@ import { AuthServicePromiseClient } from '../proto/generated/auth_grpc_web_pb';
|
||||
import { ManagementServicePromiseClient } from '../proto/generated/management_grpc_web_pb';
|
||||
import { AuthenticationService } from './authentication.service';
|
||||
import { AuthInterceptor } from './interceptors/auth.interceptor';
|
||||
import { I18nInterceptor } from './interceptors/i18n.interceptor';
|
||||
import { OrgInterceptor } from './interceptors/org.interceptor';
|
||||
import { StorageService } from './storage.service';
|
||||
|
||||
@ -37,6 +38,7 @@ export class GrpcService {
|
||||
unaryInterceptors: [
|
||||
new OrgInterceptor(this.storageService),
|
||||
new AuthInterceptor(this.authenticationService, this.storageService, this.dialog),
|
||||
new I18nInterceptor(),
|
||||
],
|
||||
};
|
||||
|
||||
|
27
console/src/app/services/interceptors/i18n.interceptor.ts
Normal file
27
console/src/app/services/interceptors/i18n.interceptor.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Request, UnaryInterceptor, UnaryResponse } from 'grpc-web';
|
||||
|
||||
|
||||
const i18nHeader = 'Accept-Language';
|
||||
@Injectable({ providedIn: 'root' })
|
||||
/**
|
||||
* Set the navigator language as header to all grpc requests
|
||||
*/
|
||||
export class I18nInterceptor<TReq = unknown, TResp = unknown> implements UnaryInterceptor<TReq, TResp> {
|
||||
constructor() { }
|
||||
|
||||
public async intercept(request: Request<TReq, TResp>, invoker: any): Promise<UnaryResponse<TReq, TResp>> {
|
||||
const metadata = request.getMetadata();
|
||||
|
||||
const navLang = navigator.language;
|
||||
if (navLang) {
|
||||
metadata[i18nHeader] = navLang;
|
||||
}
|
||||
|
||||
return invoker(request).then((response: any) => {
|
||||
return response;
|
||||
}).catch((error: any) => {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
}
|
@ -94,7 +94,7 @@
|
||||
},
|
||||
"DIALOG": {
|
||||
"DELETE_TITLE":"User löschen",
|
||||
"DELETE_DESCRIPTION":"Sie sind im Begriff den Benutzer {{displayName}} entgültig zu löschen. Wollen Sie dies wirklich tun?"
|
||||
"DELETE_DESCRIPTION":"Sie sind im Begriff einen Benutzer endgültig zu löschen. Wollen Sie dies wirklich tun?"
|
||||
},
|
||||
"TABLE":{
|
||||
"DEACTIVATE":"Deaktivieren",
|
||||
|
@ -94,7 +94,7 @@
|
||||
},
|
||||
"DIALOG": {
|
||||
"DELETE_TITLE":"Delete User",
|
||||
"DELETE_DESCRIPTION":"You are about to permanently delete the user {{displayName}}. Are you sure?"
|
||||
"DELETE_DESCRIPTION":"You are about to permanently delete a user. Are you sure?"
|
||||
},
|
||||
"TABLE":{
|
||||
"DEACTIVATE":"Deactivate",
|
||||
|
Loading…
x
Reference in New Issue
Block a user