Skip to content

Commit

Permalink
feat: copy app
Browse files Browse the repository at this point in the history
  • Loading branch information
HenryT-CG committed Feb 2, 2024
1 parent 6a725f9 commit bdf0b60
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 93 deletions.
27 changes: 27 additions & 0 deletions src/_mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,30 @@
}
}
}

@mixin card-badges {
:host ::ng-deep {
.card-badge-right {
display: inline-block;
position: absolute;
right: 2px;
&.badge-1 {
top: 3px;
}
&.badge-2 {
top: 30px;
}
}
.card-badge-left {
display: inline-block;
position: absolute;
left: 2px;
&.badge-1 {
top: 3px;
}
&.badge-2 {
top: 30px;
}
}
}
}
51 changes: 22 additions & 29 deletions src/app/product-store/app-detail/app-detail.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ export class AppDetailComponent implements OnChanges {
}

ngOnChanges() {
console.log('app detail ngOnChanges() ' + this.changeMode, this.appAbstract)
if (this.appAbstract && this.displayDetailDialog) {
if (this.changeMode !== 'CREATE') {
this.getApp()
Expand All @@ -102,9 +101,12 @@ export class AppDetailComponent implements OnChanges {
if (data) {
this.app = data
this.viewForm(this.app)
console.info('get app: ', data)
if (this.changeMode === 'COPY') {
if (this.app && this.app.id) this.app.id = undefined
if (this.app && this.app.id) {
this.app.id = undefined
this.app.creationDate = undefined
this.app.modificationDate = undefined
}
this.changeMode = 'CREATE'
} else this.changeMode = 'EDIT'
}
Expand Down Expand Up @@ -148,31 +150,18 @@ export class AppDetailComponent implements OnChanges {
}

private createApp() {
console.log('app detail createApp() ')
this.appApi.createMicrofrontend({ createMicrofrontendRequest: this.app as CreateMicrofrontendRequest }).subscribe({
next: () => {
this.msgService.success({ summaryKey: 'ACTIONS.CREATE.APP.OK' })
this.displayDetailDialogChange.emit(false)
},
error: (err) => {
this.msgService.error({
summaryKey: 'ACTIONS.CREATE.APP.NOK',
detailKey:
err?.error?.errorCode && err?.error?.errorCode === 'PERSIST_ENTITY_FAILED'
? err?.error?.detail.indexOf('microfrontend_app_id') > 0
? 'VALIDATION.APP.UNIQUE_CONSTRAINT.APP_ID'
: err?.error?.detail.indexOf('microfrontend_remote_module') > 0
? 'VALIDATION.APP.UNIQUE_CONSTRAINT.REMOTE_MODULE'
: 'VALIDATION.ERRORS.INTERNAL_ERROR'
: ''
})
console.error('err', err)
this.displaySaveError(err)
}
})
}

private updateApp() {
console.log('app detail updateApp() ' + this.app?.id)
this.appApi
.updateMicrofrontend({
id: this.app?.id ?? '',
Expand All @@ -184,19 +173,23 @@ export class AppDetailComponent implements OnChanges {
this.displayDetailDialogChange.emit(false)
},
error: (err) => {
this.msgService.error({
summaryKey: 'ACTIONS.EDIT.APP.NOK',
detailKey:
err?.error?.errorCode && err?.error?.errorCode === 'PERSIST_ENTITY_FAILED'
? err?.error?.detail.indexOf('microfrontend_app_id') > 0
? 'VALIDATION.APP.UNIQUE_CONSTRAINT.APP_ID'
: err?.error?.detail.indexOf('microfrontend_remote_module') > 0
? 'VALIDATION.APP.UNIQUE_CONSTRAINT.REMOTE_MODULE'
: 'VALIDATION.ERRORS.INTERNAL_ERROR'
: ''
})
console.error('err', err)
this.displaySaveError(err)
}
})
}

private displaySaveError(err: any): void {
this.msgService.error({
summaryKey: 'ACTIONS.' + this.changeMode + '.APP.NOK',
detailKey:
err?.error?.errorCode && err?.error?.errorCode === 'PERSIST_ENTITY_FAILED'
? err?.error?.detail.indexOf('microfrontend_app_id') > 0
? 'VALIDATION.APP.UNIQUE_CONSTRAINT.APP_ID'
: err?.error?.detail.indexOf('microfrontend_remote_module') > 0
? 'VALIDATION.APP.UNIQUE_CONSTRAINT.REMOTE_MODULE'
: 'VALIDATION.ERRORS.INTERNAL_ERROR'
: ''
})
console.error('err', err)
}
}
27 changes: 4 additions & 23 deletions src/app/product-store/app-search/app-search.component.scss
Original file line number Diff line number Diff line change
@@ -1,27 +1,8 @@
:host ::ng-deep {
.card-badge-right {
display: inline-block;
position: absolute;
right: 2px;
&.badge-1 {
top: 3px;
}
&.badge-2 {
top: 30px;
}
}
.card-badge-left {
display: inline-block;
position: absolute;
left: 2px;
&.badge-1 {
top: 3px;
}
&.badge-2 {
top: 30px;
}
}
@import '/src/_mixins.scss';

@include card-badges;

:host ::ng-deep {
.danger-action-text {
color: var(--danger-button-bg);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<ocx-data-view-controls
[enableFiltering]="true"
[enableSorting]="true"
[supportedViews]="['list']"
[supportedViews]="['grid']"
[initialViewMode]="viewMode"
[sortingOptions]="[{ label: 'MFE.APP_NAME' | translate, value: 'app_name' }]"
[defaultSortOption]="sortField"
Expand All @@ -35,7 +35,7 @@
>
</ocx-data-view-controls
></ng-template>
<ng-template let-app pTemplate="listItem">
<ng-template let-app pTemplate="gridItem">
<!--
<div
class="col-12 grid grid-nogutter align-items-center row-gap-1 listview-row p-1 hover:bg-gray-200 cursor-pointer"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,9 @@
@include make-disabled-form-readable-input;
@include make-disabled-form-readable-dropdown;
@include prepare-inputgroup;
@include card-badges;

:host ::ng-deep {
.card-badge-right {
display: inline-block;
position: absolute;
right: 2px;
&.badge-1 {
top: 3px;
}
&.badge-2 {
top: 30px;
}
}
.card-badge-left {
display: inline-block;
position: absolute;
left: 2px;
&.badge-1 {
top: 3px;
}
&.badge-2 {
top: 30px;
}
}

.danger-action-text {
color: var(--danger-button-bg);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class ProductAppsComponent implements OnChanges {
public app: MicrofrontendAbstract | undefined
public iconItems: SelectItem[] = [{ label: '', value: null }]
public filter: string | undefined
public viewMode = 'list'
public viewMode = 'grid'
public sortField = 'name'
public sortOrder = 1
public searchInProgress = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<ocx-page-header
[loading]="loading"
[header]="product?.displayName"
[subheader]="'DIALOG.DETAIL.SUBHEADER' | translate"
[subheader]="('DIALOG.DETAIL.SUBHEADER' | translate) + ': ' + ('ACTIONS.' + changeMode + '.LABEL' | translate)"
[actions]="(actions$ | async) ?? []"
[figureImage]="headerImageUrl"
[figureBackground]="!product?.imageUrl"
Expand Down
23 changes: 19 additions & 4 deletions src/app/product-store/product-detail/product-detail.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Product, ProductsAPIService } from 'src/app/shared/generated'
import { prepareUrl } from 'src/app/shared/utils'
import { ProductPropertyComponent } from './product-props/product-props.component'

type ChangeMode = 'VIEW' | 'CREATE' | 'EDIT'
export type ChangeMode = 'VIEW' | 'CREATE' | 'EDIT' | 'COPY'

@Component({
templateUrl: './product-detail.component.html',
Expand Down Expand Up @@ -78,6 +78,8 @@ export class ProductDetailComponent implements OnInit {
private prepareActionButtons(): void {
this.actions$ = this.translate
.get([
'ACTIONS.COPY.LABEL',
'ACTIONS.COPY.PRODUCT.HEADER',
'ACTIONS.DELETE.LABEL',
'ACTIONS.DELETE.PRODUCT.TOOLTIP',
'ACTIONS.DELETE.MESSAGE',
Expand Down Expand Up @@ -112,6 +114,16 @@ export class ProductDetailComponent implements OnInit {
showCondition: this.changeMode === 'VIEW' && this.product !== undefined,
permission: 'PRODUCT#EDIT'
},
{
label: data['ACTIONS.COPY.LABEL'],
title: data['ACTIONS.COPY.PRODUCT.HEADER'],
actionCallback: () => this.onCopy(),
icon: 'pi pi-copy',
show: 'always',
conditional: true,
showCondition: this.changeMode === 'VIEW' && this.product !== undefined,
permission: 'PRODUCT#CREATE'
},
{
label: data['ACTIONS.CANCEL'],
title: data['ACTIONS.TOOLTIPS.CANCEL'],
Expand Down Expand Up @@ -156,6 +168,10 @@ export class ProductDetailComponent implements OnInit {
this.close()
}

public onCopy(): void {
this.changeMode = 'COPY'
this.prepareActionButtons()
}
public onEdit() {
this.changeMode = 'EDIT'
this.getProduct()
Expand All @@ -165,9 +181,8 @@ export class ProductDetailComponent implements OnInit {
this.changeMode = 'VIEW'
this.getProduct()
}
if (this.changeMode === 'CREATE') {
this.close()
}
if (this.changeMode === 'COPY') this.close()
if (this.changeMode === 'CREATE') this.close()
}
public onSave() {
this.productPropsComponent.onSubmit()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { PortalMessageService } from '@onecx/portal-integration-angular'
import { CreateProductRequest, Product, ProductsAPIService, UpdateProductRequest } from 'src/app/shared/generated'
import { IconService } from 'src/app/shared/iconservice'
import { dropDownSortItemsByLabel } from 'src/app/shared/utils'
import { ChangeMode } from '../product-detail.component'

export interface ProductDetailForm {
id: FormControl<string | null>
Expand Down Expand Up @@ -36,9 +37,10 @@ export function productNameValidator(): ValidatorFn {
export class ProductPropertyComponent implements OnChanges {
@Input() product: Product | undefined
@Input() dateFormat = 'medium'
@Input() changeMode = 'VIEW'
@Input() changeMode: ChangeMode = 'VIEW'
@Output() productCreated = new EventEmitter<Product>()
@Output() productChanged = new EventEmitter<boolean>()
@Output() changeModeChange = new EventEmitter<ChangeMode>()
public formGroup: FormGroup<ProductDetailForm>
public productId: string | undefined
public productName: string | null | undefined
Expand Down Expand Up @@ -78,19 +80,21 @@ export class ProductPropertyComponent implements OnChanges {
this.formGroup.patchValue({
...this.product
})
this.productId = this.product.id
this.productId = this.changeMode !== 'COPY' ? this.product.id : undefined
this.productName = this.product.name // business key => manage the change!
} else {
this.formGroup.reset()
}
this.changeMode !== 'VIEW' ? this.formGroup.enable() : this.formGroup.disable()
this.changeMode = this.changeMode === 'COPY' ? 'CREATE' : this.changeMode
this.changeModeChange.emit(this.changeMode)
}

/** CREATE/UPDATE product
*/
public onSubmit() {
if (this.formGroup.valid) {
this.changeMode === 'CREATE' ? this.createProduct() : this.updateProduct()
this.changeMode === 'EDIT' ? this.updateProduct() : this.createProduct()
} else {
this.msgService.error({ summaryKey: 'VALIDATION.FORM_INVALID' })
// set focus to first invalid field
Expand Down Expand Up @@ -147,7 +151,7 @@ export class ProductPropertyComponent implements OnChanges {
}

private displaySaveError(err: any) {
if (err.error?.errorCode === 'MERGE_ENTITY_FAILED') {
if (err.error?.errorCode === 'PERSIST_ENTITY_FAILED') {
this.msgService.error({
summaryKey: 'ACTIONS.' + this.changeMode + '.PRODUCT.NOK',
detailKey: 'VALIDATION.PRODUCT.UNIQUE_CONSTRAINT'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ describe('ProductDetailComponent', () => {
let fixture: ComponentFixture<ProductDetailComponent>

const apiServiceSpy = {
searchProducts: jasmine.createSpy('searchProducts').and.returnValue(of({})),
getProductByName: jasmine.createSpy('getProductByName').and.returnValue(of({}))
}
const msgServiceSpy = jasmine.createSpyObj<PortalMessageService>('PortalMessageService', ['success', 'error', 'info'])
Expand Down Expand Up @@ -48,7 +47,6 @@ describe('ProductDetailComponent', () => {
msgServiceSpy.success.calls.reset()
msgServiceSpy.error.calls.reset()
msgServiceSpy.info.calls.reset()
apiServiceSpy.searchProducts.calls.reset()
apiServiceSpy.getProductByName.calls.reset()
})

Expand All @@ -74,7 +72,7 @@ describe('ProductDetailComponent', () => {

expect(component.product?.id).toEqual(p.id)
})

/*
it('should prepare action buttons callbacks on init: close', () => {
spyOn(component, 'close')
Expand Down Expand Up @@ -118,7 +116,7 @@ describe('ProductDetailComponent', () => {
expect(component.onSave).toHaveBeenCalled()
})

*/
it('should call close() onClose', () => {
spyOn(component, 'close')

Expand All @@ -138,14 +136,12 @@ describe('ProductDetailComponent', () => {

it('should behave correctly onCancel in edit mode', () => {
spyOn(component, 'getProduct')
spyOn(component, 'prepareTranslations')
component.changeMode = 'EDIT'

component.onCancel()

expect(component.changeMode).toEqual('VIEW')
expect(component.getProduct).toHaveBeenCalled()
expect(component.prepareTranslations).toHaveBeenCalled()
})

it('should behave correctly onCancel in new mode', () => {
Expand Down
1 change: 1 addition & 0 deletions src/assets/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
}
},
"VIEW": {
"LABEL": "Ansehen",
"APP": {
"HEADER": "App Details"
},
Expand Down
1 change: 1 addition & 0 deletions src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
}
},
"VIEW": {
"LABEL": "View",
"APP": {
"HEADER": "App Details"
},
Expand Down

0 comments on commit bdf0b60

Please sign in to comment.