diff --git a/package-lock.json b/package-lock.json
index dffb9f0..d7421a6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -47,13 +47,13 @@
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.2",
"@angular-devkit/core": "^18.1.2",
- "@angular-devkit/schematics": "^18.1.2",
+ "@angular-devkit/schematics": "^18.1.3",
"@angular-eslint/builder": "^18.1.0",
"@angular-eslint/eslint-plugin": "^18.1.0",
"@angular-eslint/eslint-plugin-template": "^18.1.0",
"@angular-eslint/schematics": "^18.1.0",
"@angular-eslint/template-parser": "^18.1.0",
- "@angular/cli": "~18.1.2",
+ "@angular/cli": "~18.1.3",
"@angular/compiler-cli": "^18.1.2",
"@angular/language-service": "^18.1.2",
"@commitlint/cli": "^19.3.0",
@@ -557,13 +557,13 @@
}
},
"node_modules/@angular-devkit/schematics": {
- "version": "18.1.2",
- "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.2.tgz",
- "integrity": "sha512-v8aCJ1tPPzXsdiCoZxkc6YzLGhzJgC/6QauT03/Z6wWo8uI6DKibQQwQBawRE5FN5lKDpuGlNDv40EDtVYkQSA==",
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.3.tgz",
+ "integrity": "sha512-ElzCfiYW9P3xPRNRbPRSrOTGm+G7X8ta1ce3srqi00yPX39Y0WSM95SACqqF8j9dxL6BqazBMyAgNQUaVSbWjw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@angular-devkit/core": "18.1.2",
+ "@angular-devkit/core": "18.1.3",
"jsonc-parser": "3.3.1",
"magic-string": "0.30.10",
"ora": "5.4.1",
@@ -575,6 +575,34 @@
"yarn": ">= 1.13.0"
}
},
+ "node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.1.3.tgz",
+ "integrity": "sha512-S0UzNNVLbHPaiSVXHjCd2wX+eERj/YR7jJCc40PHs1gINA7Gtd2q3VDm3bUEWe4P6fP6GNp43qSXmWJFQD0+Yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "8.16.0",
+ "ajv-formats": "3.0.1",
+ "jsonc-parser": "3.3.1",
+ "picomatch": "4.0.2",
+ "rxjs": "7.8.1",
+ "source-map": "0.7.4"
+ },
+ "engines": {
+ "node": "^18.19.1 || ^20.11.1 || >=22.0.0",
+ "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+ "yarn": ">= 1.13.0"
+ },
+ "peerDependencies": {
+ "chokidar": "^3.5.2"
+ },
+ "peerDependenciesMeta": {
+ "chokidar": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@angular-eslint/builder": {
"version": "18.1.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.1.0.tgz",
@@ -905,18 +933,18 @@
}
},
"node_modules/@angular/cli": {
- "version": "18.1.2",
- "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.1.2.tgz",
- "integrity": "sha512-5H0scWgJcDE3NSM6/j/xSwNfAQBVOhVjXuj+nZOaEkJC0Bxh6AoEdWpQdzmZ6qSlx4LMlJYI6P/sH0kiBlFfgA==",
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.1.3.tgz",
+ "integrity": "sha512-vsEc3cGDUYcc+adfvBHSqKdI8uiaa86Y9pLWGHfqaD+N0q/k17d/47AFvXTDKLmKucMZrto/4088Y1y+yM9eOg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@angular-devkit/architect": "0.1801.2",
- "@angular-devkit/core": "18.1.2",
- "@angular-devkit/schematics": "18.1.2",
+ "@angular-devkit/architect": "0.1801.3",
+ "@angular-devkit/core": "18.1.3",
+ "@angular-devkit/schematics": "18.1.3",
"@inquirer/prompts": "5.0.7",
"@listr2/prompt-adapter-inquirer": "2.0.13",
- "@schematics/angular": "18.1.2",
+ "@schematics/angular": "18.1.3",
"@yarnpkg/lockfile": "1.1.0",
"ini": "4.1.3",
"jsonc-parser": "3.3.1",
@@ -938,6 +966,67 @@
"yarn": ">= 1.13.0"
}
},
+ "node_modules/@angular/cli/node_modules/@angular-devkit/architect": {
+ "version": "0.1801.3",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1801.3.tgz",
+ "integrity": "sha512-4yba7x315GKim7OuBgv89ZtG50hE3hw64KuRLSGuW+RvwcwLV24VanmdWmFiLC4RKYNSH13E0wZqDNJkrMQepw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@angular-devkit/core": "18.1.3",
+ "rxjs": "7.8.1"
+ },
+ "engines": {
+ "node": "^18.19.1 || ^20.11.1 || >=22.0.0",
+ "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+ "yarn": ">= 1.13.0"
+ }
+ },
+ "node_modules/@angular/cli/node_modules/@angular-devkit/core": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.1.3.tgz",
+ "integrity": "sha512-S0UzNNVLbHPaiSVXHjCd2wX+eERj/YR7jJCc40PHs1gINA7Gtd2q3VDm3bUEWe4P6fP6GNp43qSXmWJFQD0+Yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "8.16.0",
+ "ajv-formats": "3.0.1",
+ "jsonc-parser": "3.3.1",
+ "picomatch": "4.0.2",
+ "rxjs": "7.8.1",
+ "source-map": "0.7.4"
+ },
+ "engines": {
+ "node": "^18.19.1 || ^20.11.1 || >=22.0.0",
+ "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+ "yarn": ">= 1.13.0"
+ },
+ "peerDependencies": {
+ "chokidar": "^3.5.2"
+ },
+ "peerDependenciesMeta": {
+ "chokidar": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@angular/cli/node_modules/@schematics/angular": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.1.3.tgz",
+ "integrity": "sha512-VyoL7O+3eL+BazmoWzexFpVy9k0MoOAmff3XqKLhP3/V7eXPc9s7znIDpPp28QF0V/Y2xMaGDWhqTx2CFcz4Qg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@angular-devkit/core": "18.1.3",
+ "@angular-devkit/schematics": "18.1.3",
+ "jsonc-parser": "3.3.1"
+ },
+ "engines": {
+ "node": "^18.19.1 || ^20.11.1 || >=22.0.0",
+ "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+ "yarn": ">= 1.13.0"
+ }
+ },
"node_modules/@angular/cli/node_modules/semver": {
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
@@ -7411,6 +7500,25 @@
"yarn": ">= 1.13.0"
}
},
+ "node_modules/@schematics/angular/node_modules/@angular-devkit/schematics": {
+ "version": "18.1.2",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.2.tgz",
+ "integrity": "sha512-v8aCJ1tPPzXsdiCoZxkc6YzLGhzJgC/6QauT03/Z6wWo8uI6DKibQQwQBawRE5FN5lKDpuGlNDv40EDtVYkQSA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@angular-devkit/core": "18.1.2",
+ "jsonc-parser": "3.3.1",
+ "magic-string": "0.30.10",
+ "ora": "5.4.1",
+ "rxjs": "7.8.1"
+ },
+ "engines": {
+ "node": "^18.19.1 || ^20.11.1 || >=22.0.0",
+ "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+ "yarn": ">= 1.13.0"
+ }
+ },
"node_modules/@sideway/address": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
diff --git a/package.json b/package.json
index f37e7d0..94ea9fe 100644
--- a/package.json
+++ b/package.json
@@ -74,13 +74,13 @@
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.2",
"@angular-devkit/core": "^18.1.2",
- "@angular-devkit/schematics": "^18.1.2",
+ "@angular-devkit/schematics": "^18.1.3",
"@angular-eslint/builder": "^18.1.0",
"@angular-eslint/eslint-plugin": "^18.1.0",
"@angular-eslint/eslint-plugin-template": "^18.1.0",
"@angular-eslint/schematics": "^18.1.0",
"@angular-eslint/template-parser": "^18.1.0",
- "@angular/cli": "~18.1.2",
+ "@angular/cli": "~18.1.3",
"@angular/compiler-cli": "^18.1.2",
"@angular/language-service": "^18.1.2",
"@commitlint/cli": "^19.3.0",
diff --git a/src/_mixins.scss b/src/_mixins.scss
index 83ff89c..d28c39f 100644
--- a/src/_mixins.scss
+++ b/src/_mixins.scss
@@ -221,3 +221,13 @@
}
}
}
+
+@mixin displaying-text-responsive {
+ :host ::ng-deep {
+ .text-responsive {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ }
+}
diff --git a/src/app/product-store/app-detail/app-detail.component.html b/src/app/product-store/app-detail/app-detail.component.html
index 97cd128..70f264c 100644
--- a/src/app/product-store/app-detail/app-detail.component.html
+++ b/src/app/product-store/app-detail/app-detail.component.html
@@ -8,7 +8,7 @@
[modal]="true"
[showHeader]="true"
[contentStyleClass]="'border-round'"
- [style]="{ 'max-width': '750px' }"
+ [style]="{ 'max-width': '1050px', 'max-height': '800px' }"
[breakpoints]="{
'992px': '80vw',
'750px': '90vw',
@@ -19,7 +19,7 @@
- {{ this.dialogTitelKey | translate }}
+ {{ this.dialogTitleKey | translate }}
-
+ >
+ {{ 'APP.GROUP.REMOTE_MODULE' | translate }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
- {{ 'APP.GROUP.INTERNALS' | translate }}
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/src/app/product-store/app-detail/app-detail.component.spec.ts b/src/app/product-store/app-detail/app-detail.component.spec.ts
index d42664e..d6b1309 100644
--- a/src/app/product-store/app-detail/app-detail.component.spec.ts
+++ b/src/app/product-store/app-detail/app-detail.component.spec.ts
@@ -27,6 +27,8 @@ const form = new FormGroup
({
type: new FormControl(''),
remoteBaseUrl: new FormControl(''),
remoteEntry: new FormControl(''),
+ remoteName: new FormControl(''),
+ tagName: new FormControl(''),
exposedModule: new FormControl(''),
classifications: new FormControl(''),
contact: new FormControl(''),
@@ -50,6 +52,8 @@ const mfe: Microfrontend = {
productName: 'productName',
appVersion: 'version',
remoteEntry: 'entry',
+ remoteName: 'remoteName',
+ tagName: 'tagName',
description: 'description',
technology: 'technology',
type: MicrofrontendType.Module,
@@ -241,348 +245,362 @@ describe('AppDetailComponent', () => {
expect(component.appChanged.emit).toHaveBeenCalledWith(false)
})
- it('should display error if form is invalid onSave', () => {
- component.appAbstract = appMfe
- component.formGroupMfe = new FormGroup({
- appId: new FormControl('i', Validators.minLength(2)),
- appName: new FormControl(''),
- appVersion: new FormControl(''),
- productName: new FormControl(''),
- description: new FormControl(''),
- technology: new FormControl(''),
- type: new FormControl(''),
- remoteBaseUrl: new FormControl(''),
- remoteEntry: new FormControl(''),
- exposedModule: new FormControl(''),
- classifications: new FormControl(''),
- contact: new FormControl(''),
- iconName: new FormControl(''),
- note: new FormControl('')
+ describe('onSave', () => {
+ it('should display error if form is invalid onSave', () => {
+ component.appAbstract = appMfe
+ component.formGroupMfe = new FormGroup({
+ appId: new FormControl('i', Validators.minLength(2)),
+ appName: new FormControl(''),
+ appVersion: new FormControl(''),
+ productName: new FormControl(''),
+ description: new FormControl(''),
+ technology: new FormControl(''),
+ type: new FormControl(''),
+ remoteBaseUrl: new FormControl(''),
+ remoteEntry: new FormControl(''),
+ remoteName: new FormControl(''),
+ tagName: new FormControl(''),
+ exposedModule: new FormControl(''),
+ classifications: new FormControl(''),
+ contact: new FormControl(''),
+ iconName: new FormControl(''),
+ note: new FormControl('')
+ })
+ component.changeMode = 'CREATE'
+
+ component.onSave()
+
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({ summaryKey: 'VALIDATION.FORM_INVALID' })
})
- component.changeMode = 'CREATE'
-
- component.onSave()
-
- expect(msgServiceSpy.error).toHaveBeenCalledWith({ summaryKey: 'VALIDATION.FORM_INVALID' })
- })
- it('should call createApp onSave in create mode', () => {
- mfeApiServiceSpy.createMicrofrontend.and.returnValue(of({}))
- component.appAbstract = appMfe
- component.formGroupMfe = form
- component.changeMode = 'CREATE'
+ it('should call createApp onSave in create mode', () => {
+ mfeApiServiceSpy.createMicrofrontend.and.returnValue(of({}))
+ component.appAbstract = appMfe
+ component.formGroupMfe = form
+ component.changeMode = 'CREATE'
- component.onSave()
+ component.onSave()
- expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.CREATE.APP.OK' })
- })
+ expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.CREATE.APP.OK' })
+ })
- it('should display save error in create mode', () => {
- const err = {
- error: {
- detail: 'Error',
- errorCode: 'PERSIST_ENTITY_FAILED'
+ it('should display save error in create mode', () => {
+ const err = {
+ error: {
+ detail: 'Error',
+ errorCode: 'PERSIST_ENTITY_FAILED'
+ }
}
- }
- mfeApiServiceSpy.createMicrofrontend.and.returnValue(throwError(() => err))
- component.appAbstract = appMfe
- component.formGroupMfe = form
- component.changeMode = 'CREATE'
-
- component.onSave()
-
- const expectedKey = ''
- expect(msgServiceSpy.error).toHaveBeenCalledWith({
- summaryKey: 'ACTIONS.CREATE.APP.NOK',
- detailKey: expectedKey
+ mfeApiServiceSpy.createMicrofrontend.and.returnValue(throwError(() => err))
+ component.appAbstract = appMfe
+ component.formGroupMfe = form
+ component.changeMode = 'CREATE'
+
+ component.onSave()
+
+ const expectedKey = ''
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({
+ summaryKey: 'ACTIONS.CREATE.APP.NOK',
+ detailKey: expectedKey
+ })
})
- })
- it('should call updateApp onSave in edit mode', () => {
- mfeApiServiceSpy.updateMicrofrontend.and.returnValue(of({}))
- component.appAbstract = appMfe
- component.formGroupMfe = form
- component.changeMode = 'EDIT'
+ it('should call updateApp onSave in edit mode', () => {
+ mfeApiServiceSpy.updateMicrofrontend.and.returnValue(of({}))
+ component.appAbstract = appMfe
+ component.formGroupMfe = form
+ component.changeMode = 'EDIT'
- component.onSave()
+ component.onSave()
- expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.EDIT.APP.OK' })
- })
+ expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.EDIT.APP.OK' })
+ })
- it('should display save error in edit mode: unique constraint mfe id', () => {
- const err = {
- error: {
- detail: 'error: microfrontend_app_id',
- errorCode: 'PERSIST_ENTITY_FAILED'
+ it('should display save error in edit mode: unique constraint mfe id', () => {
+ const err = {
+ error: {
+ detail: 'error: microfrontend_app_id',
+ errorCode: 'PERSIST_ENTITY_FAILED'
+ }
}
- }
- mfeApiServiceSpy.updateMicrofrontend.and.returnValue(throwError(() => err))
- component.appAbstract = appMfe
- component.formGroupMfe = form
- component.changeMode = 'EDIT'
-
- component.onSave()
-
- const expectedKey = 'VALIDATION.APP.UNIQUE_CONSTRAINT.APP_ID'
- expect(msgServiceSpy.error).toHaveBeenCalledWith({
- summaryKey: 'ACTIONS.EDIT.APP.NOK',
- detailKey: expectedKey
+ mfeApiServiceSpy.updateMicrofrontend.and.returnValue(throwError(() => err))
+ component.appAbstract = appMfe
+ component.formGroupMfe = form
+ component.changeMode = 'EDIT'
+
+ component.onSave()
+
+ const expectedKey = 'VALIDATION.APP.UNIQUE_CONSTRAINT.APP_ID'
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({
+ summaryKey: 'ACTIONS.EDIT.APP.NOK',
+ detailKey: expectedKey
+ })
})
- })
- it('should display save error in edit mode: unique constraint mfe id', () => {
- const err = {
- error: {
- detail: 'error: microfrontend_remote_module',
- errorCode: 'PERSIST_ENTITY_FAILED'
+ it('should display save error in edit mode: unique constraint mfe id', () => {
+ const err = {
+ error: {
+ detail: 'error: microfrontend_remote_module',
+ errorCode: 'PERSIST_ENTITY_FAILED'
+ }
}
- }
- mfeApiServiceSpy.updateMicrofrontend.and.returnValue(throwError(() => err))
- component.appAbstract = appMfe
- component.formGroupMfe = form
- component.changeMode = 'EDIT'
-
- component.onSave()
-
- const expectedKey = 'VALIDATION.APP.UNIQUE_CONSTRAINT.REMOTE_MODULE'
- expect(msgServiceSpy.error).toHaveBeenCalledWith({
- summaryKey: 'ACTIONS.EDIT.APP.NOK',
- detailKey: expectedKey
+ mfeApiServiceSpy.updateMicrofrontend.and.returnValue(throwError(() => err))
+ component.appAbstract = appMfe
+ component.formGroupMfe = form
+ component.changeMode = 'EDIT'
+
+ component.onSave()
+
+ const expectedKey = 'VALIDATION.APP.UNIQUE_CONSTRAINT.REMOTE_MODULE'
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({
+ summaryKey: 'ACTIONS.EDIT.APP.NOK',
+ detailKey: expectedKey
+ })
})
- })
- it('should display save error in edit mode: other internal error', () => {
- const err = {
- error: {
- detail: 'error: microfrontend_remote_module',
- errorCode: 'other'
+ it('should display save error in edit mode: other internal error', () => {
+ const err = {
+ error: {
+ detail: 'error: microfrontend_remote_module',
+ errorCode: 'other'
+ }
}
- }
- mfeApiServiceSpy.updateMicrofrontend.and.returnValue(throwError(() => err))
- component.appAbstract = appMfe
- component.formGroupMfe = form
- component.changeMode = 'EDIT'
-
- component.onSave()
-
- const expectedKey = 'VALIDATION.ERRORS.INTERNAL_ERROR'
- expect(msgServiceSpy.error).toHaveBeenCalledWith({
- summaryKey: 'ACTIONS.EDIT.APP.NOK',
- detailKey: expectedKey
+ mfeApiServiceSpy.updateMicrofrontend.and.returnValue(throwError(() => err))
+ component.appAbstract = appMfe
+ component.formGroupMfe = form
+ component.changeMode = 'EDIT'
+
+ component.onSave()
+
+ const expectedKey = 'VALIDATION.ERRORS.INTERNAL_ERROR'
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({
+ summaryKey: 'ACTIONS.EDIT.APP.NOK',
+ detailKey: expectedKey
+ })
})
- })
- it('should display error if form is invalid onSave', () => {
- component.appAbstract = appMfe
- component.formGroupMfe = new FormGroup({
- appId: new FormControl('i', Validators.minLength(2)),
- appName: new FormControl(''),
- appVersion: new FormControl(''),
- productName: new FormControl(''),
- description: new FormControl(''),
- technology: new FormControl(''),
- type: new FormControl(''),
- remoteBaseUrl: new FormControl(''),
- remoteEntry: new FormControl(''),
- exposedModule: new FormControl(''),
- classifications: new FormControl(''),
- contact: new FormControl(''),
- iconName: new FormControl(''),
- note: new FormControl('')
+ it('should display error if form is invalid onSave', () => {
+ component.appAbstract = appMfe
+ component.formGroupMfe = new FormGroup({
+ appId: new FormControl('i', Validators.minLength(2)),
+ appName: new FormControl(''),
+ appVersion: new FormControl(''),
+ productName: new FormControl(''),
+ description: new FormControl(''),
+ technology: new FormControl(''),
+ type: new FormControl(''),
+ remoteBaseUrl: new FormControl(''),
+ remoteEntry: new FormControl(''),
+ remoteName: new FormControl(''),
+ tagName: new FormControl(''),
+ exposedModule: new FormControl(''),
+ classifications: new FormControl(''),
+ contact: new FormControl(''),
+ iconName: new FormControl(''),
+ note: new FormControl('')
+ })
+ component.changeMode = 'CREATE'
+
+ component.onSave()
+
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({ summaryKey: 'VALIDATION.FORM_INVALID' })
})
- component.changeMode = 'CREATE'
-
- component.onSave()
-
- expect(msgServiceSpy.error).toHaveBeenCalledWith({ summaryKey: 'VALIDATION.FORM_INVALID' })
- })
- it('should call createApp onSave in create mode', () => {
- mfeApiServiceSpy.createMicrofrontend.and.returnValue(of({}))
- component.appAbstract = appMfe
- component.formGroupMfe = form
- component.changeMode = 'CREATE'
+ it('should call createApp onSave in create mode', () => {
+ mfeApiServiceSpy.createMicrofrontend.and.returnValue(of({}))
+ component.appAbstract = appMfe
+ component.formGroupMfe = form
+ component.changeMode = 'CREATE'
- component.onSave()
+ component.onSave()
- expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.CREATE.APP.OK' })
- })
+ expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.CREATE.APP.OK' })
+ })
- it('should display save error in create mode', () => {
- const err = {
- error: {
- detail: 'Error',
- errorCode: 'PERSIST_ENTITY_FAILED'
+ it('should display save error in create mode', () => {
+ const err = {
+ error: {
+ detail: 'Error',
+ errorCode: 'PERSIST_ENTITY_FAILED'
+ }
}
- }
- mfeApiServiceSpy.createMicrofrontend.and.returnValue(throwError(() => err))
- component.appAbstract = appMfe
- component.formGroupMfe = form
- component.changeMode = 'CREATE'
-
- component.onSave()
-
- const expectedKey = ''
- expect(msgServiceSpy.error).toHaveBeenCalledWith({
- summaryKey: 'ACTIONS.CREATE.APP.NOK',
- detailKey: expectedKey
+ mfeApiServiceSpy.createMicrofrontend.and.returnValue(throwError(() => err))
+ component.appAbstract = appMfe
+ component.formGroupMfe = form
+ component.changeMode = 'CREATE'
+
+ component.onSave()
+
+ const expectedKey = ''
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({
+ summaryKey: 'ACTIONS.CREATE.APP.NOK',
+ detailKey: expectedKey
+ })
})
- })
- it('should call updateApp onSave in edit mode', () => {
- mfeApiServiceSpy.updateMicrofrontend.and.returnValue(of({}))
- component.appAbstract = appMfe
- component.formGroupMfe = form
- component.changeMode = 'EDIT'
+ it('should call updateApp onSave in edit mode', () => {
+ mfeApiServiceSpy.updateMicrofrontend.and.returnValue(of({}))
+ component.appAbstract = appMfe
+ component.formGroupMfe = form
+ component.changeMode = 'EDIT'
- component.onSave()
+ component.onSave()
- expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.EDIT.APP.OK' })
- })
+ expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.EDIT.APP.OK' })
+ })
- it('should display save error in edit mode: unique constraint mfe id', () => {
- const err = {
- error: {
- detail: 'error: microfrontend_app_id',
- errorCode: 'PERSIST_ENTITY_FAILED'
+ it('should display save error in edit mode: unique constraint mfe id', () => {
+ const err = {
+ error: {
+ detail: 'error: microfrontend_app_id',
+ errorCode: 'PERSIST_ENTITY_FAILED'
+ }
}
- }
- mfeApiServiceSpy.updateMicrofrontend.and.returnValue(throwError(() => err))
- component.appAbstract = appMfe
- component.formGroupMfe = form
- component.changeMode = 'EDIT'
-
- component.onSave()
-
- const expectedKey = 'VALIDATION.APP.UNIQUE_CONSTRAINT.APP_ID'
- expect(msgServiceSpy.error).toHaveBeenCalledWith({
- summaryKey: 'ACTIONS.EDIT.APP.NOK',
- detailKey: expectedKey
+ mfeApiServiceSpy.updateMicrofrontend.and.returnValue(throwError(() => err))
+ component.appAbstract = appMfe
+ component.formGroupMfe = form
+ component.changeMode = 'EDIT'
+
+ component.onSave()
+
+ const expectedKey = 'VALIDATION.APP.UNIQUE_CONSTRAINT.APP_ID'
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({
+ summaryKey: 'ACTIONS.EDIT.APP.NOK',
+ detailKey: expectedKey
+ })
})
- })
- it('should display save error in edit mode: unique constraint mfe id', () => {
- const err = {
- error: {
- detail: 'error: microfrontend_remote_module',
- errorCode: 'PERSIST_ENTITY_FAILED'
+ it('should display save error in edit mode: unique constraint mfe id', () => {
+ const err = {
+ error: {
+ detail: 'error: microfrontend_remote_module',
+ errorCode: 'PERSIST_ENTITY_FAILED'
+ }
}
- }
- mfeApiServiceSpy.updateMicrofrontend.and.returnValue(throwError(() => err))
- component.appAbstract = appMfe
- component.formGroupMfe = form
- component.changeMode = 'EDIT'
-
- component.onSave()
-
- const expectedKey = 'VALIDATION.APP.UNIQUE_CONSTRAINT.REMOTE_MODULE'
- expect(msgServiceSpy.error).toHaveBeenCalledWith({
- summaryKey: 'ACTIONS.EDIT.APP.NOK',
- detailKey: expectedKey
+ mfeApiServiceSpy.updateMicrofrontend.and.returnValue(throwError(() => err))
+ component.appAbstract = appMfe
+ component.formGroupMfe = form
+ component.changeMode = 'EDIT'
+
+ component.onSave()
+
+ const expectedKey = 'VALIDATION.APP.UNIQUE_CONSTRAINT.REMOTE_MODULE'
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({
+ summaryKey: 'ACTIONS.EDIT.APP.NOK',
+ detailKey: expectedKey
+ })
})
- })
- it('should display save error in edit mode: other internal error', () => {
- const err = {
- error: {
- detail: 'error: microfrontend_remote_module',
- errorCode: 'other'
+ it('should display save error in edit mode: other internal error', () => {
+ const err = {
+ error: {
+ detail: 'error: microfrontend_remote_module',
+ errorCode: 'other'
+ }
}
- }
- mfeApiServiceSpy.updateMicrofrontend.and.returnValue(throwError(() => err))
- component.appAbstract = appMfe
- component.formGroupMfe = form
- component.changeMode = 'EDIT'
-
- component.onSave()
-
- const expectedKey = 'VALIDATION.ERRORS.INTERNAL_ERROR'
- expect(msgServiceSpy.error).toHaveBeenCalledWith({
- summaryKey: 'ACTIONS.EDIT.APP.NOK',
- detailKey: expectedKey
+ mfeApiServiceSpy.updateMicrofrontend.and.returnValue(throwError(() => err))
+ component.appAbstract = appMfe
+ component.formGroupMfe = form
+ component.changeMode = 'EDIT'
+
+ component.onSave()
+
+ const expectedKey = 'VALIDATION.ERRORS.INTERNAL_ERROR'
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({
+ summaryKey: 'ACTIONS.EDIT.APP.NOK',
+ detailKey: expectedKey
+ })
})
- })
- // ONSAVE TESTS FOR MSS
- it('should display error if form is invalid onSave', () => {
- component.appAbstract = appMs
- component.formGroupMs = new FormGroup({
- appId: new FormControl('i', Validators.minLength(2)),
- appName: new FormControl(''),
- appVersion: new FormControl(''),
- productName: new FormControl(''),
- description: new FormControl('')
+ // ONSAVE TESTS FOR MSS
+ it('should display error if form is invalid onSave', () => {
+ component.appAbstract = appMs
+ component.formGroupMs = new FormGroup({
+ appId: new FormControl('i', Validators.minLength(2)),
+ appName: new FormControl(''),
+ appVersion: new FormControl(''),
+ productName: new FormControl(''),
+ description: new FormControl('')
+ })
+ component.changeMode = 'CREATE'
+
+ component.onSave()
+
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({ summaryKey: 'VALIDATION.FORM_INVALID' })
})
- component.changeMode = 'CREATE'
-
- component.onSave()
-
- expect(msgServiceSpy.error).toHaveBeenCalledWith({ summaryKey: 'VALIDATION.FORM_INVALID' })
- })
- it('should call createApp onSave in create mode', () => {
- msApiServiceSpy.createMicroservice.and.returnValue(of({}))
- component.appAbstract = appMs
- component.formGroupMs = msForm
- component.changeMode = 'CREATE'
+ it('should call createApp onSave in create mode', () => {
+ msApiServiceSpy.createMicroservice.and.returnValue(of({}))
+ component.appAbstract = appMs
+ component.formGroupMs = msForm
+ component.changeMode = 'CREATE'
- component.onSave()
+ component.onSave()
- expect(component.formGroupMs.valid).toBeTrue()
- expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.CREATE.APP.OK' })
- })
+ expect(component.formGroupMs.valid).toBeTrue()
+ expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.CREATE.APP.OK' })
+ })
- it('should display save error in create mode', () => {
- const err = {
- error: {
- detail: 'Error',
- errorCode: 'PERSIST_ENTITY_FAILED'
+ it('should display save error in create mode', () => {
+ const err = {
+ error: {
+ detail: 'Error',
+ errorCode: 'PERSIST_ENTITY_FAILED'
+ }
}
- }
- msApiServiceSpy.createMicroservice.and.returnValue(throwError(() => err))
- component.appAbstract = appMs
- component.formGroupMs = msForm
- component.changeMode = 'CREATE'
-
- component.onSave()
-
- const expectedKey = ''
- expect(msgServiceSpy.error).toHaveBeenCalledWith({
- summaryKey: 'ACTIONS.CREATE.APP.NOK',
- detailKey: expectedKey
+ msApiServiceSpy.createMicroservice.and.returnValue(throwError(() => err))
+ component.appAbstract = appMs
+ component.formGroupMs = msForm
+ component.changeMode = 'CREATE'
+
+ component.onSave()
+
+ const expectedKey = ''
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({
+ summaryKey: 'ACTIONS.CREATE.APP.NOK',
+ detailKey: expectedKey
+ })
})
- })
- it('should call updateApp onSave in edit mode', () => {
- msApiServiceSpy.updateMicroservice.and.returnValue(of({}))
- component.appAbstract = appMs
- component.formGroupMs = msForm
- component.changeMode = 'EDIT'
+ it('should call updateApp onSave in edit mode', () => {
+ msApiServiceSpy.updateMicroservice.and.returnValue(of({}))
+ component.appAbstract = appMs
+ component.formGroupMs = msForm
+ component.changeMode = 'EDIT'
- component.onSave()
+ component.onSave()
- expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.EDIT.APP.OK' })
- })
+ expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.EDIT.APP.OK' })
+ })
- it('should display save error in edit mode: other internal error', () => {
- const err = {
- error: {
- detail: 'error: microservice_remote_module',
- errorCode: 'other'
+ it('should display save error in edit mode: other internal error', () => {
+ const err = {
+ error: {
+ detail: 'error: microservice_remote_module',
+ errorCode: 'other'
+ }
}
- }
- msApiServiceSpy.updateMicroservice.and.returnValue(throwError(() => err))
- component.appAbstract = appMs
- component.formGroupMs = msForm
- component.changeMode = 'EDIT'
+ msApiServiceSpy.updateMicroservice.and.returnValue(throwError(() => err))
+ component.appAbstract = appMs
+ component.formGroupMs = msForm
+ component.changeMode = 'EDIT'
+
+ component.onSave()
+
+ const expectedKey = 'VALIDATION.ERRORS.INTERNAL_ERROR'
+ expect(msgServiceSpy.error).toHaveBeenCalledWith({
+ summaryKey: 'ACTIONS.EDIT.APP.NOK',
+ detailKey: expectedKey
+ })
+ })
+ })
- component.onSave()
+ it('should update tabIndex onTabPanelChange', () => {
+ const mockEvent = { index: 3 }
- const expectedKey = 'VALIDATION.ERRORS.INTERNAL_ERROR'
- expect(msgServiceSpy.error).toHaveBeenCalledWith({
- summaryKey: 'ACTIONS.EDIT.APP.NOK',
- detailKey: expectedKey
- })
+ component.onTabPanelChange(mockEvent)
+
+ expect(component.tabIndex).toBe(mockEvent.index)
})
it('should call this.user.lang$ from the constructor and set this.dateFormat to the default format if user.lang$ is not de', () => {
diff --git a/src/app/product-store/app-detail/app-detail.component.ts b/src/app/product-store/app-detail/app-detail.component.ts
index 8c5c233..dc78487 100644
--- a/src/app/product-store/app-detail/app-detail.component.ts
+++ b/src/app/product-store/app-detail/app-detail.component.ts
@@ -1,8 +1,9 @@
-import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'
+import { Component, EventEmitter, Input, OnChanges, OnInit, Output, Renderer2, ViewChild } from '@angular/core'
import { FormControl, FormGroup, Validators } from '@angular/forms'
import { TranslateService } from '@ngx-translate/core'
import { finalize } from 'rxjs'
import { SelectItem } from 'primeng/api'
+import { TabView } from 'primeng/tabview'
import { PortalMessageService, UserService } from '@onecx/portal-integration-angular'
import { IconService } from 'src/app/shared/iconservice'
@@ -31,7 +32,9 @@ export interface MfeForm {
technology: FormControl
type: FormControl
remoteBaseUrl: FormControl
+ remoteName: FormControl
remoteEntry: FormControl
+ tagName: FormControl
classifications: FormControl
contact?: FormControl
iconName?: FormControl
@@ -51,28 +54,27 @@ export interface MsForm {
templateUrl: './app-detail.component.html',
styleUrls: ['./app-detail.component.scss']
})
-export class AppDetailComponent implements OnChanges {
+export class AppDetailComponent implements OnInit, OnChanges {
@Input() appAbstract: AppAbstract | undefined
@Input() dateFormat = 'medium'
@Input() changeMode: ChangeMode = 'VIEW'
@Input() displayDialog = false
@Output() appChanged = new EventEmitter()
+ @ViewChild('panelDetail') panelDetail: TabView | undefined
public mfe: Microfrontend | undefined
public ms: Microservice | undefined
public formGroupMfe: FormGroup
public formGroupMs: FormGroup
- public dialogTitelKey = ''
+ public tabIndex = 0
+ public dialogTitleKey = ''
public loading = false
public operator = false
public undeployed = false
public deprecated = false
public hasCreatePermission = false
public hasEditPermission = false
- public technologies: SelectItem[] = [
- { label: 'Angular', value: 'ANGULAR' },
- { label: 'WebComponent', value: 'WEBCOMPONENTMODULE' }
- ]
+ public technologies: SelectItem[] = []
public types: SelectItem[] = [
{ label: 'Module', value: 'MODULE' },
{ label: 'Component', value: 'COMPONENT' }
@@ -86,7 +88,8 @@ export class AppDetailComponent implements OnChanges {
private msApi: MicroservicesAPIService,
private mfeApi: MicrofrontendsAPIService,
private msgService: PortalMessageService,
- private translate: TranslateService
+ private translate: TranslateService,
+ private renderer: Renderer2
) {
this.hasCreatePermission = this.user.hasPermission('APP#CREATE')
this.hasEditPermission = this.user.hasPermission('APP#EDIT')
@@ -104,6 +107,8 @@ export class AppDetailComponent implements OnChanges {
type: new FormControl(null),
remoteBaseUrl: new FormControl(null, [Validators.maxLength(255)]),
remoteEntry: new FormControl(null, [Validators.maxLength(255)]),
+ remoteName: new FormControl(null, [Validators.maxLength(255)]),
+ tagName: new FormControl(null, [Validators.maxLength(255)]),
exposedModule: new FormControl(null, [Validators.maxLength(255)]),
classifications: new FormControl(null, [Validators.maxLength(255)]),
contact: new FormControl(null, [Validators.maxLength(255)]),
@@ -119,6 +124,10 @@ export class AppDetailComponent implements OnChanges {
})
}
+ ngOnInit() {
+ this.getDropdownTranslations()
+ }
+
ngOnChanges() {
this.enableForms()
if (this.changeMode === 'CREATE') {
@@ -174,7 +183,7 @@ export class AppDetailComponent implements OnChanges {
}
this.enableForms()
}
- this.dialogTitelKey = 'ACTIONS.' + this.changeMode + '.MFE.HEADER'
+ this.dialogTitleKey = 'ACTIONS.' + this.changeMode + '.MFE.HEADER'
}
})
}
@@ -200,7 +209,7 @@ export class AppDetailComponent implements OnChanges {
}
this.enableForms()
}
- this.dialogTitelKey = 'ACTIONS.' + this.changeMode + '.MS.HEADER'
+ this.dialogTitleKey = 'ACTIONS.' + this.changeMode + '.MS.HEADER'
}
})
}
@@ -216,6 +225,8 @@ export class AppDetailComponent implements OnChanges {
type: mfe['type'],
remoteBaseUrl: mfe['remoteBaseUrl'],
remoteEntry: mfe['remoteEntry'],
+ remoteName: mfe['remoteName'],
+ tagName: mfe['tagName'],
exposedModule: mfe['exposedModule'],
classifications: mfe['classifications'],
contact: mfe['contact'],
@@ -258,6 +269,9 @@ export class AppDetailComponent implements OnChanges {
}
}
+ public onTabPanelChange(e: any): void {
+ this.tabIndex = e.index
+ }
private createMfe() {
this.mfeApi.createMicrofrontend({ createMicrofrontendRequest: this.mfe as CreateMicrofrontendRequest }).subscribe({
next: () => {
@@ -330,4 +344,14 @@ export class AppDetailComponent implements OnChanges {
})
console.error('err', err)
}
+
+ private getDropdownTranslations() {
+ this.translate.get(['APP.WEBCOMPONENT.MODULE', 'APP.WEBCOMPONENT.SCRIPT']).subscribe((data) => {
+ this.technologies = [
+ { label: 'Angular', value: 'ANGULAR' },
+ { label: data['APP.WEBCOMPONENT.MODULE'], value: 'WEBCOMPONENTMODULE' },
+ { label: data['APP.WEBCOMPONENT.SCRIPT'], value: 'WEBCOMPONENTSCRIPT' }
+ ]
+ })
+ }
}
diff --git a/src/app/product-store/app-detail/app-intern/app-intern.component.html b/src/app/product-store/app-detail/app-intern/app-intern.component.html
new file mode 100644
index 0000000..d5b2460
--- /dev/null
+++ b/src/app/product-store/app-detail/app-intern/app-intern.component.html
@@ -0,0 +1,125 @@
+
diff --git a/src/app/product-store/app-detail/app-intern/app-intern.component.scss b/src/app/product-store/app-detail/app-intern/app-intern.component.scss
new file mode 100644
index 0000000..949c7c0
--- /dev/null
+++ b/src/app/product-store/app-detail/app-intern/app-intern.component.scss
@@ -0,0 +1,39 @@
+@import '/src/_mixins.scss';
+
+@include danger-action;
+
+/* limit deletion dialog */
+:host ::ng-deep {
+ // popup dialogues
+ @media (max-width: 991px) {
+ .p-dialog.p-dialog {
+ max-height: unset !important;
+ height: unset !important;
+ }
+ }
+
+ .p-dialog {
+ background: var(--panel-content-bg);
+ .p-dialog-content {
+ border-radius: unset !important;
+ padding-bottom: 0.5rem;
+ margin-bottom: 0.5rem;
+ }
+ .p-dialog-footer button {
+ margin: unset;
+ }
+ .p-dialog-header .p-dialog-header-icons {
+ display: none;
+ }
+ }
+ .p-fieldset {
+ &.p-fieldset-toggleable .p-fieldset-legend a,
+ .p-fieldset-legend {
+ background-color: transparent;
+ padding: 0.3rem 0.4rem;
+ }
+ .p-fieldset-content {
+ padding: 1rem 0.2rem 0rem;
+ }
+ }
+}
diff --git a/src/app/product-store/app-detail/app-intern/app-intern.component.spec.ts b/src/app/product-store/app-detail/app-intern/app-intern.component.spec.ts
new file mode 100644
index 0000000..8b4d242
--- /dev/null
+++ b/src/app/product-store/app-detail/app-intern/app-intern.component.spec.ts
@@ -0,0 +1,93 @@
+import { NO_ERRORS_SCHEMA } from '@angular/core'
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'
+import { HttpClientTestingModule } from '@angular/common/http/testing'
+import { RouterTestingModule } from '@angular/router/testing'
+import { TranslateTestingModule } from 'ngx-translate-testing'
+
+import { AppInternComponent } from './app-intern.component'
+import { Microfrontend, Microservice } from 'src/app/shared/generated'
+
+const appMfe: Microfrontend = {
+ operator: true,
+ deprecated: false,
+ undeployed: true
+} as Microfrontend
+
+const appMs: Microservice = {
+ operator: true,
+ undeployed: true
+}
+
+describe('AppInternComponent', () => {
+ let component: AppInternComponent
+ let fixture: ComponentFixture
+
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ declarations: [AppInternComponent],
+ imports: [
+ RouterTestingModule,
+ HttpClientTestingModule,
+ TranslateTestingModule.withTranslations({
+ de: require('src/assets/i18n/de.json'),
+ en: require('src/assets/i18n/en.json')
+ }).withDefaultLanguage('en')
+ ],
+ schemas: [NO_ERRORS_SCHEMA]
+ }).compileComponents()
+ }))
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AppInternComponent)
+ component = fixture.componentInstance
+ fixture.detectChanges()
+ })
+
+ it('should create', () => {
+ expect(component).toBeTruthy()
+ })
+
+ describe('ngOnChanges', () => {
+ it('should set relevant values correctly when viewed app is Microfrontend', () => {
+ component.app = appMfe
+
+ component.ngOnChanges()
+
+ expect(component.undeployed).toBe(true)
+ expect(component.operator).toBe(true)
+ expect(component.deprecated).toBe(false)
+ })
+
+ it('should set relevant values to false when viewed app is Microservice', () => {
+ component.app = appMs
+
+ component.ngOnChanges()
+
+ expect(component.undeployed).toBe(true)
+ expect(component.operator).toBe(true)
+ expect(component.deprecated).toBe(false)
+ })
+
+ it('should set all properties to false when app is undefined', () => {
+ component.app = undefined
+
+ component.ngOnChanges()
+
+ expect(component.undeployed).toBe(false)
+ expect(component.operator).toBe(false)
+ expect(component.deprecated).toBe(false)
+ })
+
+ it('should set deprecated to false if app is a Microfrontend and deprecated property is missing', () => {
+ const appMfeNoDeprecated: Partial = {
+ operator: true,
+ undeployed: true
+ }
+ component.app = appMfeNoDeprecated as Microfrontend
+
+ component.ngOnChanges()
+
+ expect(component.deprecated).toBe(false)
+ })
+ })
+})
diff --git a/src/app/product-store/app-detail/app-intern/app-intern.component.ts b/src/app/product-store/app-detail/app-intern/app-intern.component.ts
new file mode 100644
index 0000000..1766d3f
--- /dev/null
+++ b/src/app/product-store/app-detail/app-intern/app-intern.component.ts
@@ -0,0 +1,33 @@
+import { Component, Input, OnChanges } from '@angular/core'
+import { TranslateService } from '@ngx-translate/core'
+
+import { Microfrontend, Microservice } from 'src/app/shared/generated'
+
+@Component({
+ selector: 'app-app-intern',
+ templateUrl: './app-intern.component.html'
+})
+export class AppInternComponent implements OnChanges {
+ @Input() app: (Microfrontend | Microservice) | undefined
+ @Input() dateFormat = 'medium'
+
+ public undeployed = false
+ public operator = false
+ public deprecated = false
+
+ constructor(private translate: TranslateService) {}
+
+ public ngOnChanges(): void {
+ this.undeployed = this.app?.undeployed ?? false
+ this.operator = this.app?.operator ?? false
+ if (this.isMicrofrontend(this.app)) {
+ this.deprecated = this.app.deprecated ?? false
+ } else {
+ this.deprecated = false
+ }
+ }
+
+ private isMicrofrontend(app: Microfrontend | Microservice | undefined): app is Microfrontend {
+ return (app as Microfrontend)?.deprecated !== undefined
+ }
+}
diff --git a/src/app/product-store/app-search/app-search.component.html b/src/app/product-store/app-search/app-search.component.html
index 75fc9ea..cd90077 100644
--- a/src/app/product-store/app-search/app-search.component.html
+++ b/src/app/product-store/app-search/app-search.component.html
@@ -152,8 +152,9 @@
-
@@ -248,7 +249,7 @@
{{ limitText(app.productName, 25) }}
-
+
diff --git a/src/app/product-store/app-search/app-search.component.spec.ts b/src/app/product-store/app-search/app-search.component.spec.ts
index d0d3ac2..b3817b1 100644
--- a/src/app/product-store/app-search/app-search.component.spec.ts
+++ b/src/app/product-store/app-search/app-search.component.spec.ts
@@ -193,48 +193,6 @@ describe('AppSearchComponent', () => {
}
})
- it('should update viewMode onLayoutChange', () => {
- component.onLayoutChange('list')
-
- expect(component.viewMode).toBe('list')
- })
-
- it('should update filter and call dv.filter onFilterChange', () => {
- const filter = 'testFilter'
-
- component.onFilterChange(filter)
-
- expect(component.filter).toBe(filter)
- })
-
- it('should update filterBy and filterValue onQuickFilterChange: ALL', () => {
- component.onQuickFilterChange({ value: 'ALL' })
-
- expect(component.filterBy).toBe(component.filterValueDefault)
- expect(component.filterValue).toBe('')
- })
-
- it('should update filterBy and filterValue onQuickFilterChange: other', () => {
- component.onQuickFilterChange({ value: 'other' })
-
- expect(component.filterValue).toBe('other')
- expect(component.filterBy).toBe('appType')
- })
-
- it('should update sortField onSortChange', () => {
- component.onSortChange('field')
-
- expect(component.sortField).toBe('field')
- })
-
- it('should update sortOrder based on asc boolean onSortDirChange', () => {
- component.onSortDirChange(true)
- expect(component.sortOrder).toBe(-1)
-
- component.onSortDirChange(false)
- expect(component.sortOrder).toBe(1)
- })
-
it('should call searchApps onSearch', () => {
spyOn(component, 'searchApps')
@@ -363,13 +321,85 @@ describe('AppSearchComponent', () => {
})
})
- it('should reset appSearchCriteriaGroup onSearchReset is called', () => {
- component.appSearchCriteriaGroup = form
- spyOn(form, 'reset').and.callThrough()
+ /*
+ * UI ACTIONS
+ */
+ it('should update viewMode onLayoutChange', () => {
+ component.onLayoutChange('list')
- component.onSearchReset()
+ expect(component.viewMode).toBe('list')
+ })
- expect(component.appSearchCriteriaGroup.reset).toHaveBeenCalled()
+ it('should update filter and call dv.filter onFilterChange', () => {
+ const filter = 'testFilter'
+
+ component.onFilterChange(filter)
+
+ expect(component.filter).toBe(filter)
+ })
+
+ describe('onAppTypeFilterChange', () => {
+ it('should set appTypeFilterValue when ev.value is provided', () => {
+ const event = { value: 'testValue' }
+ component.onAppTypeFilterChange(event)
+ expect(component.appTypeFilterValue).toBe('testValue')
+ })
+
+ it('should not change appTypeFilterValue when ev.value is not provided', () => {
+ component.appTypeFilterValue = 'initialValue'
+ const event = { value: null }
+ component.onAppTypeFilterChange(event)
+ expect(component.appTypeFilterValue).toBe('initialValue')
+ })
+ })
+
+ describe('onQuickFilterChange', () => {
+ it('should update filterBy and filterValue onQuickFilterChange: ALL', () => {
+ component.onQuickFilterChange({ value: 'ALL' })
+
+ expect(component.filterBy).toBe(component.filterValueDefault)
+ expect(component.filterValue).toBe('')
+ })
+
+ it('should update filterBy and filterValue onQuickFilterChange: other', () => {
+ component.onQuickFilterChange({ value: 'other' })
+
+ expect(component.filterValue).toBe('other')
+ expect(component.filterBy).toBe('appType')
+ })
+
+ it('should set to quickFulterVaule to the original one if there is no current value', () => {
+ component.quickFilterValueOld = 'old'
+
+ component.onQuickFilterChange({})
+
+ expect(component.quickFilterValue).toBe('old')
+ })
+ })
+
+ it('should update sortField onSortChange', () => {
+ component.onSortChange('field')
+
+ expect(component.sortField).toBe('field')
+ })
+
+ describe('onSortDirChange', () => {
+ it('should update sortOrder based on asc boolean onSortDirChange', () => {
+ component.onSortDirChange(true)
+ expect(component.sortOrder).toBe(-1)
+
+ component.onSortDirChange(false)
+ expect(component.sortOrder).toBe(1)
+ })
+
+ it('should reset appSearchCriteriaGroup onSearchReset is called', () => {
+ component.appSearchCriteriaGroup = form
+ spyOn(form, 'reset').and.callThrough()
+
+ component.onSearchReset()
+
+ expect(component.appSearchCriteriaGroup.reset).toHaveBeenCalled()
+ })
})
it('should navigate back onBack', () => {
@@ -431,6 +461,9 @@ describe('AppSearchComponent', () => {
expect(component.app).toBe(msApp)
})
+ /**
+ * MODAL Dialog feedback
+ */
it('should call searchApps if app changed', () => {
spyOn(component, 'searchApps')
diff --git a/src/app/product-store/product-detail/product-apps/product-apps.component.spec.ts b/src/app/product-store/product-detail/product-apps/product-apps.component.spec.ts
index 73fbbe2..e20d14d 100644
--- a/src/app/product-store/product-detail/product-apps/product-apps.component.spec.ts
+++ b/src/app/product-store/product-detail/product-apps/product-apps.component.spec.ts
@@ -1,6 +1,4 @@
-/*
import { NO_ERRORS_SCHEMA } from '@angular/core'
-//import { ComponentFixture, TestBed, fakeAsync, waitForAsync } from '@angular/core/testing'
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'
import { HttpClientTestingModule } from '@angular/common/http/testing'
import { RouterTestingModule } from '@angular/router/testing'
@@ -8,15 +6,17 @@ import { of, throwError } from 'rxjs'
import { TranslateTestingModule } from 'ngx-translate-testing'
import { PortalMessageService } from '@onecx/portal-integration-angular'
-import { ProductAppsComponent } from './product-apps.component'
+import { AppType, ProductAppsComponent } from './product-apps.component'
import {
MicrofrontendAbstract,
- MicrofrontendsAPIService,
MicrofrontendPageResult,
+ MicrofrontendType,
Microservice,
- MicroservicesAPIService,
- MicroservicePageResult,
- Product
+ Product,
+ ProductDetails,
+ ProductsAPIService,
+ Slot,
+ SlotPageItem
} from 'src/app/shared/generated'
import { AppAbstract } from '../../app-search/app-search.component'
@@ -52,11 +52,8 @@ describe('ProductAppsComponent', () => {
const ms: Microservice = { id: 'id', appId: 'appId', appName: 'microservice', productName: 'prodName' }
const msgServiceSpy = jasmine.createSpyObj('PortalMessageService', ['success', 'error', 'info'])
- const apiMfeServiceSpy = {
- searchMicrofrontends: jasmine.createSpy('searchMicrofrontends').and.returnValue(of({}))
- }
- const apiMsServiceSpy = {
- searchMicroservice: jasmine.createSpy('searchMicroservice').and.returnValue(of({}))
+ const productServiceSpy = {
+ getProductDetailsByCriteria: jasmine.createSpy('getProductDetailsByCriteria').and.returnValue(of({}))
}
beforeEach(waitForAsync(() => {
@@ -71,8 +68,7 @@ describe('ProductAppsComponent', () => {
}).withDefaultLanguage('en')
],
providers: [
- { provide: MicrofrontendsAPIService, useValue: apiMfeServiceSpy },
- { provide: MicroservicesAPIService, useValue: apiMsServiceSpy },
+ { provide: ProductsAPIService, useValue: productServiceSpy },
{ provide: PortalMessageService, useValue: msgServiceSpy }
],
schemas: [NO_ERRORS_SCHEMA]
@@ -83,15 +79,13 @@ describe('ProductAppsComponent', () => {
fixture = TestBed.createComponent(ProductAppsComponent)
component = fixture.componentInstance
fixture.detectChanges()
- apiMfeServiceSpy.searchMicrofrontends.and.returnValue(of({} as MicrofrontendPageResult))
- apiMsServiceSpy.searchMicroservice.and.returnValue(of({} as MicroservicePageResult))
+ productServiceSpy.getProductDetailsByCriteria.and.returnValue(of({} as MicrofrontendPageResult))
component.product = product
component.exceptionKey = ''
})
afterEach(() => {
- apiMfeServiceSpy.searchMicrofrontends.calls.reset()
- apiMsServiceSpy.searchMicroservice.calls.reset()
+ productServiceSpy.getProductDetailsByCriteria.calls.reset()
msgServiceSpy.success.calls.reset()
msgServiceSpy.error.calls.reset()
msgServiceSpy.info.calls.reset()
@@ -103,202 +97,159 @@ describe('ProductAppsComponent', () => {
it('should call searchApps onChanges if product exists', () => {
component.product = product
- spyOn(component, 'searchApps')
+ spyOn(component, 'searchProducts')
component.ngOnChanges()
- expect(component.searchApps).toHaveBeenCalled()
- })
-
- it('should search microfrontends and microservices on searchApps', (done) => {
- component.product = product
- apiMfeServiceSpy.searchMicrofrontends.and.returnValue(of({ stream: [mfe] } as MicrofrontendPageResult))
- apiMsServiceSpy.searchMicroservice.and.returnValue(of({ stream: [ms] } as MicroservicePageResult))
-
- component.searchApps()
-
- component.apps$.subscribe({
- next: (result) => {
- expect(result.length).toBe(2)
- result.forEach((result, i) => {
- if (i === 0) expect(result.appType).toEqual('MFE')
- if (i === 1) expect(result.appType).toEqual('MS')
- })
- done()
- },
- error: done.fail
- })
- })
-
- it('should search microfrontends only on searchApps', (done) => {
- component.product = product
- apiMfeServiceSpy.searchMicrofrontends.and.returnValue(of({ stream: [mfe] } as MicrofrontendPageResult))
-
- component.searchApps()
-
- component.apps$.subscribe({
- next: (result) => {
- expect(result.length).toBe(1)
- result.forEach((result, i) => {
- if (i === 0) expect(result.appType).toEqual('MFE')
- })
- done()
- },
- error: done.fail
- })
+ expect(component.searchProducts).toHaveBeenCalled()
})
- it('should search microservices only on searchApps', (done) => {
- component.product = product
- apiMsServiceSpy.searchMicroservice.and.returnValue(of({ stream: [ms] } as MicroservicePageResult))
-
- component.searchApps()
-
- component.apps$.subscribe({
- next: (result) => {
- expect(result.length).toBe(1)
- result.forEach((result, i) => {
- if (i === 0) expect(result.appType).toEqual('MS')
- })
- done()
- },
- error: done.fail
+ /**
+ * SEARCH
+ */
+ describe('searchProducts', () => {
+ it('should search microfrontends and microservices', (done) => {
+ component.product = product
+ productServiceSpy.getProductDetailsByCriteria.and.returnValue(
+ of({ microfrontends: [mfe], microservices: [ms] } as ProductDetails)
+ )
+
+ component.searchProducts()
+
+ component.productDetails$.subscribe({
+ next: (result) => {
+ expect(result.microfrontends?.length).toBe(1)
+ expect(result.microservices?.length).toBe(1)
+ done()
+ },
+ error: done.fail
+ })
})
- })
- it('should catch error on searchApps: mfes', (done) => {
- const err = { status: 404 }
- apiMfeServiceSpy.searchMicrofrontends.and.returnValue(throwError(() => err))
+ it('should catch error on searchProducts', (done) => {
+ const err = { status: 404 }
+ productServiceSpy.getProductDetailsByCriteria.and.returnValue(throwError(() => err))
- component.searchApps()
+ component.searchProducts()
- component.apps$.subscribe({
- next: (result) => {
- expect(result.length).toBe(0)
- expect(component.exceptionKey).toEqual('EXCEPTIONS.HTTP_STATUS_404.APPS')
- done()
- },
- error: done.fail
+ component.productDetails$.subscribe({
+ next: (result) => {
+ expect(component.exceptionKey).toEqual('EXCEPTIONS.HTTP_STATUS_404.APPS')
+ done()
+ },
+ error: done.fail
+ })
})
})
- it('should catch error on searchApps: ms', (done) => {
- const err = { status: 404 }
- apiMsServiceSpy.searchMicroservice.and.returnValue(throwError(() => err))
-
- component.searchApps()
-
- component.apps$.subscribe({
- next: (result) => {
- expect(result.length).toBe(0)
- expect(component.exceptionKey).toEqual('EXCEPTIONS.HTTP_STATUS_404.APPS')
- done()
- },
- error: done.fail
+ describe('sortMfesByTypeAndExposedModule', () => {
+ it('should sort by type and then by exposedModule', () => {
+ const mfeA: MicrofrontendAbstract = {
+ type: MicrofrontendType.Component,
+ exposedModule: 'moduleA'
+ } as MicrofrontendAbstract
+ const mfeB: MicrofrontendAbstract = {
+ type: MicrofrontendType.Component,
+ exposedModule: 'moduleB'
+ } as MicrofrontendAbstract
+ const mfeC: MicrofrontendAbstract = {
+ type: MicrofrontendType.Module,
+ exposedModule: 'moduleC'
+ } as MicrofrontendAbstract
+
+ expect(component.sortMfesByTypeAndExposedModule(mfeA, mfeB)).toBeLessThan(0)
+ expect(component.sortMfesByTypeAndExposedModule(mfeB, mfeA)).toBeGreaterThan(0)
+ expect(component.sortMfesByTypeAndExposedModule(mfeA, mfeC)).toBeLessThan(0)
+ expect(component.sortMfesByTypeAndExposedModule(mfeC, mfeA)).toBeGreaterThan(0)
+ expect(component.sortMfesByTypeAndExposedModule(mfeA, mfeA)).toBe(0)
})
- })
- it('should search microfrontends and microservices on searchApps with ms error', (done) => {
- const err = { status: 404 }
- apiMfeServiceSpy.searchMicrofrontends.and.returnValue(of({ stream: [mfe] } as MicrofrontendPageResult))
- apiMsServiceSpy.searchMicroservice.and.returnValue(of(throwError(() => err)))
-
- component.searchApps()
-
- component.apps$.subscribe({
- next: (result) => {
- expect(result.length).toBe(1)
- result.forEach((result, i) => {
- if (i === 0) expect(result.appType).toEqual('MFE')
- })
- done()
- },
- error: done.fail
- })
- })
+ it('should handle undefined or empty values', () => {
+ const mfeA: MicrofrontendAbstract = { type: MicrofrontendType.Component } as MicrofrontendAbstract
+ const mfeB: MicrofrontendAbstract = { exposedModule: 'moduleB' } as MicrofrontendAbstract
- it('should search microfrontends and microservices on searchApps with mfe and ms error', (done) => {
- component.product = product
- const err = { status: 404 }
- apiMfeServiceSpy.searchMicrofrontends.and.returnValue(of(throwError(() => err)))
- apiMsServiceSpy.searchMicroservice.and.returnValue(of(throwError(() => err)))
-
- component.searchApps()
-
- component.apps$.subscribe({
- next: (result) => {
- expect(result.length).toBe(0)
- done()
- },
- error: done.fail
+ expect(component.sortMfesByTypeAndExposedModule(mfeA, mfeB)).toBeGreaterThan(0)
})
})
- it('should set correct value onLayoutChange', () => {
- const viewMode = 'EDIT'
-
- component.onLayoutChange(viewMode)
+ describe('sortMssByAppId', () => {
+ it('should sort by appId', () => {
+ const msA: Microservice = { appId: 'a' } as Microservice
+ const msB: Microservice = { appId: 'b' } as Microservice
+ const msC: Microservice = { appId: 'a' } as Microservice
- expect(component.viewMode).toEqual('EDIT')
- })
-
- it('should set correct values onFilterChange', () => {
- const filter = 'filter'
+ expect(component.sortMssByAppId(msA, msB)).toBeLessThan(0)
+ expect(component.sortMssByAppId(msB, msA)).toBeGreaterThan(0)
+ expect(component.sortMssByAppId(msA, msC)).toBe(0)
+ })
- component.onFilterChange(filter)
+ it('should handle undefined or empty values', () => {
+ const msA: Microservice = { appId: 'a' } as Microservice
+ const msB: Microservice = {} as Microservice
+ const msC: Microservice = { appId: '' } as Microservice
- expect(component.filter).toEqual(filter)
+ expect(component.sortMssByAppId(msA, msB)).toBeGreaterThan(0)
+ expect(component.sortMssByAppId(msB, msA)).toBeLessThan(0)
+ expect(component.sortMssByAppId(msB, msC)).toBe(0)
+ })
})
- it('should set correct value onSortChange', () => {
- const sortField = 'field'
-
- component.onSortChange(sortField)
+ describe('sortSlotsByName', () => {
+ it('should sort by name', () => {
+ const slotA: SlotPageItem = { name: 'a' } as SlotPageItem
+ const slotB: SlotPageItem = { name: 'b' } as SlotPageItem
+ const slotC: SlotPageItem = { name: 'a' } as SlotPageItem
- expect(component.sortField).toEqual(sortField)
- })
+ expect(component.sortSlotsByName(slotA, slotB)).toBeLessThan(0)
+ expect(component.sortSlotsByName(slotB, slotA)).toBeGreaterThan(0)
+ expect(component.sortSlotsByName(slotA, slotC)).toBe(0)
+ })
- it('should set correct value onSortDirChange', () => {
- let asc = true
- component.onSortDirChange(asc)
- expect(component.sortOrder).toEqual(-1)
+ it('should handle undefined or empty values', () => {
+ const slotA: SlotPageItem = { name: 'a' } as SlotPageItem
+ const slotB: SlotPageItem = {} as SlotPageItem
+ const slotC: SlotPageItem = { name: '' } as SlotPageItem
- asc = false
- component.onSortDirChange(asc)
- expect(component.sortOrder).toEqual(1)
+ expect(component.sortSlotsByName(slotA, slotB)).toBeGreaterThan(0)
+ expect(component.sortSlotsByName(slotB, slotA)).toBeLessThan(0)
+ expect(component.sortSlotsByName(slotB, slotC)).toBe(0)
+ })
})
- it('should behave correctly onDetail for MFE', () => {
+ /**
+ * UI EVENTS
+ */
+ describe('onDetail', () => {
const mockEvent = { stopPropagation: jasmine.createSpy() }
- component.onDetail(mockEvent, mfeApp)
+ it('should display details of an mfe', () => {
+ component.onDetail(mockEvent, mfeApp, AppType.MFE)
- expect(component.app).toEqual(mfeApp)
- expect(component.changeMode).toEqual('EDIT')
- expect(component.displayDetailDialog).toBeTrue()
- })
-
- it('should behave correctly onDetail for MS', () => {
- const mockEvent = { stopPropagation: jasmine.createSpy() }
+ expect(component.app).toEqual(mfeApp)
+ expect(component.changeMode).toEqual('EDIT')
+ expect(component.displayDetailDialog).toBeTrue()
+ })
- component.onDetail(mockEvent, msApp)
+ it('should display details of an ms', () => {
+ component.onDetail(mockEvent, msApp, AppType.MS)
- expect(component.app).toEqual(msApp)
- expect(component.changeMode).toEqual('EDIT')
- expect(component.displayDetailDialog).toBeTrue()
+ expect(component.app).toEqual(msApp)
+ expect(component.changeMode).toEqual('EDIT')
+ expect(component.displayDetailDialog).toBeTrue()
+ })
})
- it('should behave correctly onCopy', () => {
+ it('should display details to copy', () => {
const mockEvent = { stopPropagation: jasmine.createSpy() }
- component.onCopy(mockEvent, mfeApp)
+ component.onCopy(mockEvent, mfeApp, AppType.MFE)
expect(component.app).toEqual(mfeApp)
expect(component.changeMode).toEqual('COPY')
expect(component.displayDetailDialog).toBeTrue()
})
- it('should should behave correctly onCreate', () => {
+ it('should should show create dialog', () => {
component.onCreate()
expect(component.changeMode).toEqual('CREATE')
@@ -306,32 +257,73 @@ describe('ProductAppsComponent', () => {
expect(component.displayDetailDialog).toBeTrue()
})
- it('should behave correctly onDelete', () => {
+ it('should display delete dialog', () => {
const mockEvent = { stopPropagation: jasmine.createSpy() }
- component.onDelete(mockEvent, mfeApp)
+ component.onDelete(mockEvent, mfeApp, AppType.MFE)
expect(component.app).toEqual(mfeApp)
expect(component.displayDeleteDialog).toBeTrue()
})
- it('should call searchApps if app changed', () => {
- spyOn(component, 'searchApps')
+ it('should call searchProducts if app changed', () => {
+ spyOn(component, 'searchProducts')
component.appChanged(true)
- expect(component.searchApps).toHaveBeenCalled()
+ expect(component.searchProducts).toHaveBeenCalled()
expect(component.displayDetailDialog).toBeFalse()
})
- it('should call searchApps if app deleted', () => {
- spyOn(component, 'searchApps')
+ it('should call searchProducts if app deleted', () => {
+ spyOn(component, 'searchProducts')
component.appDeleted(true)
- expect(component.searchApps).toHaveBeenCalled()
+ expect(component.searchProducts).toHaveBeenCalled()
expect(component.displayDetailDialog).toBeFalse()
})
-})
-*/
+ describe('onSlotDelete', () => {
+ it('should prepare slot deletion', () => {
+ const event = { stopPropagation: jasmine.createSpy('stopPropagation') }
+ const slot: Slot = { id: 'id', name: 'Test Slot' } as Slot
+
+ component.onSlotDelete(event, slot)
+
+ expect(event.stopPropagation).toHaveBeenCalled()
+ expect(component.slot).toEqual(slot)
+ expect(component.displaySlotDeleteDialog).toBe(true)
+ })
+ })
+
+ describe('slotDeleted', () => {
+ it('should set displaySlotDeleteDialog to false', () => {
+ component.displaySlotDeleteDialog = true
+
+ component.slotDeleted(false)
+
+ expect(component.displaySlotDeleteDialog).toBe(false)
+ })
+
+ it('should call searchProducts when slot has been deleted', () => {
+ spyOn(component, 'searchProducts')
+ component.displaySlotDeleteDialog = true
+
+ component.slotDeleted(true)
+
+ expect(component.displaySlotDeleteDialog).toBe(false)
+ expect(component.searchProducts).toHaveBeenCalled()
+ })
+
+ it('should not call searchProducts when slot has not been deleted', () => {
+ spyOn(component, 'searchProducts')
+ component.displaySlotDeleteDialog = true
+
+ component.slotDeleted(false)
+
+ expect(component.displaySlotDeleteDialog).toBe(false)
+ expect(component.searchProducts).not.toHaveBeenCalled()
+ })
+ })
+})
diff --git a/src/app/product-store/product-detail/product-apps/product-apps.component.ts b/src/app/product-store/product-detail/product-apps/product-apps.component.ts
index 6a18f89..33e70c1 100644
--- a/src/app/product-store/product-detail/product-apps/product-apps.component.ts
+++ b/src/app/product-store/product-detail/product-apps/product-apps.component.ts
@@ -17,7 +17,7 @@ import { IconService } from 'src/app/shared/iconservice'
import { AppAbstract, ChangeMode } from '../../app-search/app-search.component'
-enum AppType {
+export enum AppType {
MS = 'MS',
MFE = 'MFE'
}
diff --git a/src/app/product-store/product-detail/product-intern/product-intern.component.html b/src/app/product-store/product-detail/product-intern/product-intern.component.html
index 693af7a..f86f44c 100644
--- a/src/app/product-store/product-detail/product-intern/product-intern.component.html
+++ b/src/app/product-store/product-detail/product-intern/product-intern.component.html
@@ -9,7 +9,7 @@
inputId="product_detail_intern_field_operator"
[(ngModel)]="operator"
[binary]="true"
- [label]="'PRODUCT.OPERATOR' | translate"
+ [label]="'INTERNAL.OPERATOR' | translate"
[pTooltip]="'PRODUCT.TOOLTIPS.OPERATOR' | translate"
tooltipPosition="top"
tooltipEvent="hover"
diff --git a/src/app/product-store/product-detail/product-props/product-props.component.html b/src/app/product-store/product-detail/product-props/product-props.component.html
index a8e579b..7a65182 100644
--- a/src/app/product-store/product-detail/product-props/product-props.component.html
+++ b/src/app/product-store/product-detail/product-props/product-props.component.html
@@ -2,15 +2,17 @@
-
- >
-
+
+
diff --git a/src/app/product-store/product-store.module.ts b/src/app/product-store/product-store.module.ts
index 88352bf..3619331 100644
--- a/src/app/product-store/product-store.module.ts
+++ b/src/app/product-store/product-store.module.ts
@@ -15,6 +15,7 @@ import { SharedModule } from 'src/app/shared/shared.module'
import { AppSearchComponent } from './app-search/app-search.component'
import { AppDeleteComponent } from './app-delete/app-delete.component'
import { AppDetailComponent } from './app-detail/app-detail.component'
+import { AppInternComponent } from './app-detail/app-intern/app-intern.component'
import { ProductSearchComponent } from './product-search/product-search.component'
import { ProductDetailComponent } from './product-detail/product-detail.component'
import { ProductPropertyComponent } from './product-detail/product-props/product-props.component'
@@ -59,6 +60,7 @@ const routes: Routes = [
AppSearchComponent,
AppDeleteComponent,
AppDetailComponent,
+ AppInternComponent,
ProductSearchComponent,
ProductDetailComponent,
ProductPropertyComponent,
diff --git a/src/app/product-store/slot-search/slot-search.component.html b/src/app/product-store/slot-search/slot-search.component.html
index 4c6b8e8..313255e 100644
--- a/src/app/product-store/slot-search/slot-search.component.html
+++ b/src/app/product-store/slot-search/slot-search.component.html
@@ -95,7 +95,7 @@
tooltipPosition="top"
tooltipEvent="hover"
>
-
+ >