diff --git a/package-lock.json b/package-lock.json index ef859d4..a841db1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,11 +23,11 @@ "@ngneat/falso": "^6.4.0", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", - "@onecx/accelerator": "^4.1.0", - "@onecx/integration-interface": "^4.1.0", - "@onecx/keycloak-auth": "^4.1.0", - "@onecx/portal-integration-angular": "^4.1.0", - "@onecx/portal-layout-styles": "^4.1.0", + "@onecx/accelerator": "^4.1.2", + "@onecx/integration-interface": "^4.1.2", + "@onecx/keycloak-auth": "^4.1.2", + "@onecx/portal-integration-angular": "^4.1.2", + "@onecx/portal-layout-styles": "^4.1.2", "file-saver": "^2.0.5", "i18n-iso-countries": "^7.6.0", "ngx-color": "^8.0.3", @@ -6613,18 +6613,18 @@ } }, "node_modules/@onecx/accelerator": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@onecx/accelerator/-/accelerator-4.1.0.tgz", - "integrity": "sha512-sEaFwDjxQm/yo38lt3fD2vWJwnoyxRVJO/eceH3aH03FnEAjrPFkZrZEwh3fcI6WfBiOgBHzD3Lcs2GtdVXPRA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@onecx/accelerator/-/accelerator-4.1.2.tgz", + "integrity": "sha512-PujQII1motqpXwPUN0H+x6aN3BkHkmQBbQTkv+be+xlAnZD2qu7Y1gtDTfrESyj5FXBLvGw7+vIM7Bmf0NpPtA==", "peerDependencies": { "rxjs": "7.8.1", "tslib": "^2.3.0" } }, "node_modules/@onecx/integration-interface": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@onecx/integration-interface/-/integration-interface-4.1.0.tgz", - "integrity": "sha512-W9UCAuW5o+gGucEUyuSkbPB7A3wavzY9A3/G/FK61fJ4YdasF5wJ7z5K0iEJT+dK31/KiPTNxJjKE8BrfcDEVA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@onecx/integration-interface/-/integration-interface-4.1.2.tgz", + "integrity": "sha512-XED3fNOiD+dnVEDSz8haGvfgaNVCeQjn9ECAftTJ4SZ+laD5dkdv0uI21UH9ZpTTt6jUUtfNhHZZ8wChNcYdRg==", "peerDependencies": { "@onecx/accelerator": "~4", "rxjs": "7.8.1", @@ -6632,9 +6632,9 @@ } }, "node_modules/@onecx/keycloak-auth": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@onecx/keycloak-auth/-/keycloak-auth-4.1.0.tgz", - "integrity": "sha512-oR6AtafPELCC6lW0bY5jpnQhvuEC3Vv0PYu5iW/fASixowUPh5DBet9hH/4N2KtRAwuaexvrbiu2n37nZWATaw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@onecx/keycloak-auth/-/keycloak-auth-4.1.2.tgz", + "integrity": "sha512-pXrz/KHudCHVhIKqX31D3qeu513jErsqEAMmCix48MpcG/ZfFIibbLU0SAZtzp7uCIa+KcQL5MJhbsWMHb1vZA==", "dependencies": { "tslib": "^2.3.0" }, @@ -6648,9 +6648,9 @@ } }, "node_modules/@onecx/portal-integration-angular": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@onecx/portal-integration-angular/-/portal-integration-angular-4.1.0.tgz", - "integrity": "sha512-YNrBbbIHyzvYpByUo5nuK9Nr5wDIcMG08wn3Rxx88IkExMSOQm+vH2p7m5nv7v3Eovcy2jVrmTHKvtlFWxcgwA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@onecx/portal-integration-angular/-/portal-integration-angular-4.1.2.tgz", + "integrity": "sha512-dtGK9bqeDIf9RTqevQfr05Fxzfutr8xtP2nbYblAuKW4/D6xonUl6f0DS4ij40fW9745k+3MFg99FXA635fFqw==", "dependencies": { "tslib": "^2.3.0" }, @@ -6680,9 +6680,9 @@ } }, "node_modules/@onecx/portal-layout-styles": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@onecx/portal-layout-styles/-/portal-layout-styles-4.1.0.tgz", - "integrity": "sha512-CqzsuwJRhHny4ITsrFghw5E2nff961K0uwQBP0Xh0Y5LlsnyoKkfVitFBhnsh92th5F07SfA5grKVeSdDeZ4hQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@onecx/portal-layout-styles/-/portal-layout-styles-4.1.2.tgz", + "integrity": "sha512-9rDqAkbJyN3OmBEuSXZuHL6VmVuZJkTyNOW3VGHuIsy0dBrbPiqToQ6E8aNdz78FztG3RXSceyhq/Ot05IXaOQ==", "peerDependencies": { "tslib": "^2.5.0" } diff --git a/package.json b/package.json index ac7eb49..486af2b 100644 --- a/package.json +++ b/package.json @@ -49,11 +49,11 @@ "@ngneat/falso": "^6.4.0", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", - "@onecx/accelerator": "^4.1.0", - "@onecx/integration-interface": "^4.1.0", - "@onecx/keycloak-auth": "^4.1.0", - "@onecx/portal-integration-angular": "^4.1.0", - "@onecx/portal-layout-styles": "^4.1.0", + "@onecx/accelerator": "^4.1.2", + "@onecx/integration-interface": "^4.1.2", + "@onecx/keycloak-auth": "^4.1.2", + "@onecx/portal-integration-angular": "^4.1.2", + "@onecx/portal-layout-styles": "^4.1.2", "file-saver": "^2.0.5", "i18n-iso-countries": "^7.6.0", "ngx-color": "^8.0.3", diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 406a5e2..f9c1a63 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -1,7 +1,8 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core' import { TestBed } from '@angular/core/testing' -import { AppComponent } from './app.component' import { RouterTestingModule } from '@angular/router/testing' -import { NO_ERRORS_SCHEMA } from '@angular/core' + +import { AppComponent } from './app.component' describe('AppComponent', () => { beforeEach(async () => { diff --git a/src/app/onecx-theme-remote.module.ts b/src/app/onecx-theme-remote.module.ts index 2ecec81..fb0d00a 100644 --- a/src/app/onecx-theme-remote.module.ts +++ b/src/app/onecx-theme-remote.module.ts @@ -1,7 +1,16 @@ +import { HttpClient } from '@angular/common/http' import { NgModule } from '@angular/core' import { RouterModule, Routes } from '@angular/router' +import { MissingTranslationHandler, TranslateLoader, TranslateModule } from '@ngx-translate/core' -import { addInitializeModuleGuard, InitializeModuleGuard, PortalCoreModule } from '@onecx/portal-integration-angular' +import { + addInitializeModuleGuard, + AppStateService, + ConfigurationService, + createTranslateLoader, + PortalCoreModule, + PortalMissingTranslationHandler +} from '@onecx/portal-integration-angular' const routes: Routes = [ { @@ -10,9 +19,21 @@ const routes: Routes = [ } ] @NgModule({ - imports: [PortalCoreModule.forMicroFrontend(), RouterModule.forChild(addInitializeModuleGuard(routes))], + imports: [ + PortalCoreModule.forMicroFrontend(), + RouterModule.forChild(addInitializeModuleGuard(routes)), + TranslateModule.forRoot({ + isolate: true, + loader: { + provide: TranslateLoader, + useFactory: createTranslateLoader, + deps: [HttpClient, AppStateService] + }, + missingTranslationHandler: { provide: MissingTranslationHandler, useClass: PortalMissingTranslationHandler } + }) + ], exports: [], - providers: [InitializeModuleGuard], + providers: [ConfigurationService], schemas: [] }) export class OneCXThemeModule { diff --git a/src/app/shared/label.resolver.ts b/src/app/shared/label.resolver.ts index cc6206f..c09047b 100644 --- a/src/app/shared/label.resolver.ts +++ b/src/app/shared/label.resolver.ts @@ -1,14 +1,15 @@ import { Injectable } from '@angular/core' import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router' import { TranslateService } from '@ngx-translate/core' -import { Observable } from 'rxjs' +import { Observable, map } from 'rxjs' //dont use `providedIn root` - wont work when we are in shell @Injectable() export class LabelResolver implements Resolve { constructor(private translate: TranslateService) {} - /* eslint-disable @typescript-eslint/no-unused-vars */ - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): string | Observable | Promise { - return route.data['breadcrumb'] ? this.translate.instant(route.data['breadcrumb']) : route.routeConfig?.path + resolve(route: ActivatedRouteSnapshot, _state: RouterStateSnapshot): string | Observable | Promise { + return route.data['breadcrumb'] + ? this.translate.get(route.data['breadcrumb']).pipe(map((t) => t.toString())) + : route.routeConfig?.path ?? '' } } diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 96a45df..62b2bdd 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -1,14 +1,7 @@ import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, NgModule } from '@angular/core' import { CommonModule } from '@angular/common' -import { HttpClient } from '@angular/common/http' import { FormsModule, ReactiveFormsModule } from '@angular/forms' -import { - MissingTranslationHandler, - MissingTranslationHandlerParams, - TranslateLoader, - TranslateModule, - TranslateService -} from '@ngx-translate/core' +import { TranslateModule, TranslateService } from '@ngx-translate/core' import { ColorSketchModule } from 'ngx-color/sketch' import { ErrorTailorModule } from '@ngneat/error-tailor' @@ -37,14 +30,13 @@ import { ToastModule } from 'primeng/toast' import { AppStateService, ConfigurationService, - createTranslateLoader, PortalDialogService, PortalApiConfiguration } from '@onecx/portal-integration-angular' -import { Configuration } from '../generated' +import { Configuration } from 'src/app/generated' import { LabelResolver } from './label.resolver' -import { environment } from '../../environments/environment' +import { environment } from 'src/environments/environment' import { ImageContainerComponent } from './image-container/image-container.component' import { ThemeColorBoxComponent } from './theme-color-box/theme-color-box.component' @@ -52,13 +44,6 @@ export function apiConfigProvider(configService: ConfigurationService, appStateS return new PortalApiConfiguration(Configuration, environment.apiPrefix, configService, appStateService) } -export class MyMissingTranslationHandler implements MissingTranslationHandler { - handle(params: MissingTranslationHandlerParams) { - console.log(`Missing translation for ${params.key}`) - return params.key - } -} - @NgModule({ declarations: [ImageContainerComponent, ThemeColorBoxComponent], imports: [ @@ -86,15 +71,7 @@ export class MyMissingTranslationHandler implements MissingTranslationHandler { TabViewModule, TableModule, ToastModule, - TranslateModule.forRoot({ - isolate: true, - loader: { - provide: TranslateLoader, - useFactory: createTranslateLoader, - deps: [HttpClient, AppStateService] - }, - missingTranslationHandler: { provide: MissingTranslationHandler, useClass: MyMissingTranslationHandler } - }), + TranslateModule, ErrorTailorModule.forRoot({ controlErrorsOn: { async: true, blur: true, change: true }, errors: { diff --git a/src/app/theme/theme-designer/theme-designer.component.html b/src/app/theme/theme-designer/theme-designer.component.html index 600b450..1cd0e82 100644 --- a/src/app/theme/theme-designer/theme-designer.component.html +++ b/src/app/theme/theme-designer/theme-designer.component.html @@ -2,7 +2,7 @@ diff --git a/src/app/theme/theme-designer/theme-designer.component.ts b/src/app/theme/theme-designer/theme-designer.component.ts index 1fb5c27..95bb288 100644 --- a/src/app/theme/theme-designer/theme-designer.component.ts +++ b/src/app/theme/theme-designer/theme-designer.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit, ViewChild, ElementRef } from '@angular/core' import { ActivatedRoute, Router } from '@angular/router' import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms' -import { Observable, debounceTime, switchMap } from 'rxjs' +import { Observable, debounceTime, map, switchMap } from 'rxjs' import { TranslateService } from '@ngx-translate/core' import { ConfirmationService, SelectItem } from 'primeng/api' @@ -21,34 +21,35 @@ export class ThemeDesignerComponent implements OnInit { @ViewChild('selectedFileInputLogo') selectedFileInputLogo: ElementRef | undefined @ViewChild('selectedFileInputFavicon') selectedFileInputFavicon: ElementRef | undefined - public actions: Action[] = [] - themes: Theme[] = [] - theme: Theme | undefined - themeId: string | null - themeVars = themeVariables - themeTemplates!: SelectItem[] - themeTemplateSelectedId = '' - themeIsCurrentUsedTheme = false + public actions: Action[] = [] // TODO: remove if tests using actions$ + public actions$: Observable | undefined + public themes: Theme[] = [] + public theme: Theme | undefined + public themeId: string | null + public themeVars = themeVariables + public themeTemplates!: SelectItem[] + public themeTemplateSelectedId = '' + public themeIsCurrentUsedTheme = false + public fetchingLogoUrl?: string + public fetchingFaviconUrl?: string - mode: 'EDIT' | 'NEW' = 'NEW' - autoApply = false - saveAsNewPopupDisplay = false - fetchingLogoUrl?: string - fetchingFaviconUrl?: string + public mode: 'EDIT' | 'NEW' = 'NEW' + public autoApply = false + public saveAsNewPopupDisplay = false + public displayFileTypeErrorLogo = false + public displayFileTypeErrorFavicon = false - fontForm: FormGroup - basicForm: FormGroup - sidebarForm: FormGroup - topbarForm: FormGroup - generalForm: FormGroup - propertiesForm: FormGroup - groups: { + public fontForm: FormGroup + public basicForm: FormGroup + public sidebarForm: FormGroup + public topbarForm: FormGroup + public generalForm: FormGroup + public propertiesForm: FormGroup + public groups: { title: string formGroup: FormGroup key: keyof typeof themeVariables }[] - public displayFileTypeErrorLogo = false - public displayFileTypeErrorFavicon = false constructor( private fb: FormBuilder, @@ -64,19 +65,8 @@ export class ThemeDesignerComponent implements OnInit { ) { this.mode = route.snapshot.paramMap.has('id') ? 'EDIT' : 'NEW' this.themeId = route.snapshot.paramMap.get('id') - //this.themeIsCurrentUsedTheme = this.themeId === this.appStateService.currentPortal$.getValue()?.themeId - this.translate - .get([ - 'ACTIONS.CANCEL', - 'ACTIONS.TOOLTIPS.CANCEL_AND_CLOSE', - 'ACTIONS.SAVE', - 'ACTIONS.TOOLTIPS.SAVE', - 'ACTIONS.SAVE_AS', - 'ACTIONS.TOOLTIPS.SAVE_AS' - ]) - .subscribe((data) => { - this.prepareActionButtons(data) - }) + this.themeIsCurrentUsedTheme = this.themeId === this.appStateService.currentPortal$.getValue()?.themeId + this.prepareActionButtons() this.fontForm = new FormGroup({}) this.topbarForm = new FormGroup({}) this.generalForm = new FormGroup({}) @@ -89,7 +79,7 @@ export class ThemeDesignerComponent implements OnInit { }, { key: 'topbar', - title: 'Topbar - Portal Header', + title: 'Topbar - Workspace Header', formGroup: this.topbarForm }, { @@ -171,36 +161,48 @@ export class ThemeDesignerComponent implements OnInit { this.loadThemeTemplates() } - private prepareActionButtons(data: any): void { - this.actions = [] // provoke change event - this.actions.push( - { - label: data['ACTIONS.CANCEL'], - title: data['ACTIONS.TOOLTIPS.CANCEL_AND_CLOSE'], - actionCallback: () => this.close(), - icon: 'pi pi-times', - show: 'always', - permission: 'THEME#VIEW' - }, - { - label: data['ACTIONS.SAVE'], - title: data['ACTIONS.TOOLTIPS.SAVE'], - actionCallback: () => this.updateTheme(), - icon: 'pi pi-save', - show: 'always', - conditional: true, - showCondition: this.mode === 'EDIT', - permission: 'THEME#SAVE' - }, - { - label: data['ACTIONS.SAVE_AS'], - title: data['ACTIONS.TOOLTIPS.SAVE_AS'], - actionCallback: () => this.saveAsNewPopup(), - icon: 'pi pi-plus-circle', - show: 'always', - permission: 'THEME#CREATE' - } - ) + private prepareActionButtons(): void { + this.actions$ = this.translate + .get([ + 'ACTIONS.CANCEL', + 'ACTIONS.TOOLTIPS.CANCEL_AND_CLOSE', + 'ACTIONS.SAVE', + 'ACTIONS.TOOLTIPS.SAVE', + 'ACTIONS.SAVE_AS', + 'ACTIONS.TOOLTIPS.SAVE_AS' + ]) + .pipe( + map((data) => { + return [ + { + label: data['ACTIONS.CANCEL'], + title: data['ACTIONS.TOOLTIPS.CANCEL_AND_CLOSE'], + actionCallback: () => this.close(), + icon: 'pi pi-times', + show: 'always', + permission: 'THEME#VIEW' + }, + { + label: data['ACTIONS.SAVE'], + title: data['ACTIONS.TOOLTIPS.SAVE'], + actionCallback: () => this.updateTheme(), + icon: 'pi pi-save', + show: 'always', + conditional: true, + showCondition: this.mode === 'EDIT', + permission: 'THEME#SAVE' + }, + { + label: data['ACTIONS.SAVE_AS'], + title: data['ACTIONS.TOOLTIPS.SAVE_AS'], + actionCallback: () => this.saveAsNewPopup(), + icon: 'pi pi-plus-circle', + show: 'always', + permission: 'THEME#CREATE' + } + ] + }) + ) } // DropDown Theme Template