add changes diffing modal & silence some logs
This commit is contained in:
parent
148488e2c4
commit
da353cec84
22 changed files with 1770 additions and 120 deletions
|
|
@ -309,4 +309,19 @@ export class RecipeService {
|
|||
{ withCredentials: true, responseType: 'json' }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
async sortRecipe(
|
||||
country: string,
|
||||
filename: string,
|
||||
sortKey: string,
|
||||
): Promise<Observable<any>> {
|
||||
return this._httpClient.post<any>(
|
||||
environment.api + '/recipes/sort/' + country + '/' + filename ,
|
||||
JSON.stringify({
|
||||
"sortKey": sortKey
|
||||
}),
|
||||
{ withCredentials: true, responseType: 'json' }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
116
client/src/app/features/merge/changes/changes.component.ts
Normal file
116
client/src/app/features/merge/changes/changes.component.ts
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { compare } from 'src/app/shared/helpers/compare';
|
||||
import { RecipeListComponent } from '../../recipes/recipe-details/recipe-list/recipe-list.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-changes',
|
||||
standalone: true,
|
||||
templateUrl: './changes.component.html',
|
||||
imports: [CommonModule, MatCardModule, RecipeListComponent],
|
||||
})
|
||||
export class ChangesComponent implements OnInit {
|
||||
@Input() changePackage:
|
||||
| {
|
||||
// if is unchanged, do not show
|
||||
minimizeUnchanged: boolean;
|
||||
// do highlight when matched this data
|
||||
highlightChangeWhenMatched: {};
|
||||
// base product code
|
||||
targetProductCode: string;
|
||||
// full recipelist
|
||||
targetRecipe: any;
|
||||
// path
|
||||
path: string;
|
||||
// changes
|
||||
changes: any;
|
||||
}
|
||||
| undefined = undefined;
|
||||
|
||||
diffList: any[] = [];
|
||||
matchedIdx: number[] = [];
|
||||
|
||||
ngOnInit(): void {
|
||||
// this.createDiffList(this.changePackage?.targetRecipe, this.changePackage?.targetRecipe);
|
||||
|
||||
// iterate
|
||||
this.traverseByPath(
|
||||
this.changePackage?.path!,
|
||||
this.changePackage?.targetRecipe
|
||||
);
|
||||
}
|
||||
|
||||
createDiffList = (base: any, change: any) => {
|
||||
// console.log("base", base, "change", change);
|
||||
let compRes = compare(base, change);
|
||||
// if (!this.diffList.includes(compRes)) {
|
||||
|
||||
// }
|
||||
|
||||
// for(let c of compRes){
|
||||
// console.log("c", c, "diffList", this.diffList.indexOf(c));
|
||||
// if(this.diffList.indexOf(c) == -1){
|
||||
// this.diffList.push(c);
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
if(this.diffList.length == 0){
|
||||
this.diffList = compRes;
|
||||
}
|
||||
// else if(this.diffList.length > 0){
|
||||
|
||||
// let concatable = true;
|
||||
// // check if exist
|
||||
// for(let i = 0; i < this.diffList.length; i++){
|
||||
// for(let j = 0; j < compRes.length; j++){
|
||||
// if(this.diffList[i] == compRes[j]){
|
||||
// concatable = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if(concatable){
|
||||
// this.diffList = this.diffList.concat(compRes);
|
||||
// }
|
||||
// }
|
||||
|
||||
console.log("diff list", this.diffList);
|
||||
};
|
||||
|
||||
traverseByPath = (path: string, obj: any) => {
|
||||
let pathList = path.split('.');
|
||||
let data = obj;
|
||||
for (let pathKey of pathList) {
|
||||
if (pathKey != '') {
|
||||
if (!isNaN(parseInt(pathKey))) {
|
||||
let asIntKey = parseInt(pathKey);
|
||||
|
||||
data = data[asIntKey];
|
||||
if (!this.matchedIdx.includes(asIntKey)) {
|
||||
this.matchedIdx.push(parseInt(pathKey));
|
||||
}
|
||||
} else {
|
||||
data = data[pathKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
popLast = (keyString: string) => {
|
||||
let keyList = keyString.split('.');
|
||||
keyList.pop();
|
||||
return keyList.join('.');
|
||||
};
|
||||
|
||||
getChanges = () =>
|
||||
this.traverseByPath(
|
||||
this.popLast(this.changePackage!.path),
|
||||
this.changePackage!.changes
|
||||
);
|
||||
|
||||
removeDot = (s: string) => s.replace(".", "");
|
||||
}
|
||||
|
|
@ -1,40 +1,68 @@
|
|||
<p>merge works!</p>
|
||||
<!-- 3 columns with master at center -->
|
||||
<div class="grid grid-cols-3">
|
||||
<!-- from patch -->
|
||||
<div>
|
||||
<div class="m-2" *ngFor="let patchKey of getPatchMapKeys()">
|
||||
<div class="h-[80vh]">
|
||||
<!-- select a commit -->
|
||||
<div *ngIf="isPatchMapKeysLoaded()">
|
||||
<label for="patchKeys">Select a commit : </label>
|
||||
<select
|
||||
class="select select-sm select-primary"
|
||||
name="patchKeys"
|
||||
(change)="selectCommit($event)"
|
||||
>
|
||||
<option>---</option>
|
||||
<option *ngFor="let commit of getPatchMapKeys()" [value]="commit" id="commit_{{commit}}">
|
||||
[{{ getCommitAttr(commit, "Created_at") }}] [{{
|
||||
getCommitAttr(commit, "Editor")
|
||||
}}] | {{ getCommitAttr(commit, "Msg") }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<!-- enable from console -->
|
||||
<button class="hidden" (click)="testLoadCheck()">Test load</button>
|
||||
</div>
|
||||
|
||||
<!-- 3 columns with master at center -->
|
||||
<div class="flex flex-grow gap-4 p-4">
|
||||
<!-- from patch -->
|
||||
<div
|
||||
class="w-100 overflow-x-visible overflow-y-visible"
|
||||
*ngIf="hasProductCodeOfCommits() && selectedCommit != '' && selectedCommit != '---'"
|
||||
>
|
||||
<details class="collapse collapse-arrow">
|
||||
<summary class="collapse-title">{{ selectedCommit }}</summary>
|
||||
<div class="collapse-content">
|
||||
<app-recipe-list
|
||||
[productCode]="
|
||||
getCommitAttr(selectedCommit, 'contents').productCode
|
||||
"
|
||||
[noFetch]="true"
|
||||
[recipeList]="getCommitAttr(selectedCommit, 'contents').recipes"
|
||||
[displayOnly]="true"
|
||||
[diffChangeContext]="buildContext()"
|
||||
(recipeListFormChange)="onRecipeListFormChange($event)"
|
||||
></app-recipe-list>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<!-- from master -->
|
||||
<div *ngIf="hasProductCodeOfCommits()">
|
||||
<!-- display zone -->
|
||||
|
||||
<mat-card class="!bg-amber-300 !rounded-xl p-2">
|
||||
<mat-card-title>
|
||||
{{getCommitAttr(patchKey, 'Msg')}}
|
||||
</mat-card-title>
|
||||
<mat-card-content>
|
||||
<div>
|
||||
<p>date: {{getCommitAttr(patchKey, 'Created_at') }}</p>
|
||||
<p>editor: {{getCommitAttr(patchKey, 'Editor') }}</p>
|
||||
<p>ref: {{patchKey}}</p>
|
||||
|
||||
<p class="hidden">full ref: {{getCommitAttr(patchKey, 'Change_file')}}</p>
|
||||
|
||||
<button mat-raised-button class="!bg-white" (click)="copyRef(getCommitAttr(patchKey, 'Change_file'))">Copy full ref</button>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<div *ngFor="let pd of getProductCodesOfCommits()">
|
||||
<div class="container">
|
||||
<details class="collapse collapse-arrow">
|
||||
<summary class="collapse-title">{{ pd }}</summary>
|
||||
<div>
|
||||
<app-recipe-list
|
||||
[productCode]="pd!"
|
||||
[noFetch]="false"
|
||||
[displayOnly]="true"
|
||||
[diffChangeContext]="buildContext()"
|
||||
(recipeListFormChange)="onRecipeListFormChange($event)"
|
||||
></app-recipe-list>
|
||||
</div>
|
||||
<!-- collapse -->
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- from master -->
|
||||
<div>
|
||||
<p>master</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- from machine -->
|
||||
<div>
|
||||
<p>machine</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,16 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import {
|
||||
AfterViewInit,
|
||||
ApplicationRef,
|
||||
Component,
|
||||
ComponentFactoryResolver,
|
||||
Injector,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
TemplateRef,
|
||||
ViewChild,
|
||||
ViewContainerRef,
|
||||
} from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RecipeService } from 'src/app/core/services/recipe.service';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
|
|
@ -6,14 +18,38 @@ import { MatButtonModule } from '@angular/material/button';
|
|||
import { copy } from 'src/app/shared/helpers/copy';
|
||||
import { compare } from 'src/app/shared/helpers/compare';
|
||||
import { AsyncStorage } from 'src/app/shared/helpers/asyncStorage';
|
||||
import { ChangesComponent } from './changes/changes.component';
|
||||
import {
|
||||
CdkPortal,
|
||||
DomPortalOutlet,
|
||||
Portal,
|
||||
PortalModule,
|
||||
TemplatePortal,
|
||||
} from '@angular/cdk/portal';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { RecipeListComponent } from '../recipes/recipe-details/recipe-list/recipe-list.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-merge',
|
||||
standalone: true,
|
||||
imports: [CommonModule, MatCardModule, MatButtonModule],
|
||||
templateUrl: './merge.component.html',
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatCardModule,
|
||||
MatButtonModule,
|
||||
ChangesComponent,
|
||||
RecipeListComponent,
|
||||
PortalModule,
|
||||
MatFormFieldModule,
|
||||
MatSelectModule,
|
||||
FormsModule
|
||||
],
|
||||
})
|
||||
export class MergeComponent implements OnInit {
|
||||
export class MergeComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
onRecipeListFormChange($event: any) {}
|
||||
|
||||
@Input() commit: Array<any> | undefined = undefined;
|
||||
|
||||
patchMap: any = {};
|
||||
|
|
@ -23,11 +59,47 @@ export class MergeComponent implements OnInit {
|
|||
//map productCode:commits
|
||||
mapProductCodeWithCommits: any = {};
|
||||
// master recipes for product code given by commits
|
||||
targetRecipe: any = {}
|
||||
targetRecipe: any = {};
|
||||
// change map
|
||||
changeMap: any = {};
|
||||
|
||||
constructor(private _recipeService: RecipeService) {}
|
||||
// -------------------- current selection
|
||||
|
||||
currentTargetOfMaster: any = undefined;
|
||||
highlightChanges: any = {};
|
||||
selectedProductCode = '';
|
||||
|
||||
changePackage:
|
||||
| {
|
||||
minimizeUnchanged: boolean;
|
||||
highlightChangeWhenMatched: {};
|
||||
targetProductCode: string;
|
||||
targetRecipe: any;
|
||||
path: string;
|
||||
changes: any;
|
||||
}
|
||||
| undefined = undefined;
|
||||
|
||||
selectedCommit: string = '';
|
||||
|
||||
// --------------------- Portal
|
||||
// deprecated~!
|
||||
// @ViewChild(CdkPortal)
|
||||
// private portal: CdkPortal | undefined;
|
||||
// private host: DomPortalOutlet | undefined;
|
||||
|
||||
selectedPortal!: Portal<any>;
|
||||
templatePortal!: TemplatePortal<any>;
|
||||
// template
|
||||
@ViewChild('templateRecipeChangeContent')
|
||||
templateRecipeChangeContent!: TemplateRef<any>;
|
||||
|
||||
constructor(
|
||||
private _recipeService: RecipeService,
|
||||
private _containerRef: ViewContainerRef // private cfr: ComponentFactoryResolver,
|
||||
) // private appRef: ApplicationRef,
|
||||
// private injector: Injector
|
||||
{}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
(
|
||||
|
|
@ -51,7 +123,7 @@ export class MergeComponent implements OnInit {
|
|||
if (productCode) {
|
||||
// check if exist in map
|
||||
if (!this.mapProductCodeWithCommits[productCode]) {
|
||||
this.mapProductCodeWithCommits[productCode] = [ key ];
|
||||
this.mapProductCodeWithCommits[productCode] = [key];
|
||||
} else {
|
||||
this.mapProductCodeWithCommits[productCode].push(key);
|
||||
}
|
||||
|
|
@ -69,7 +141,29 @@ export class MergeComponent implements OnInit {
|
|||
});
|
||||
|
||||
// fetch related product codes
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
//Called after ngAfterContentInit when the component's view has been initialized. Applies to components only.
|
||||
//Add 'implements AfterViewInit' to the class.
|
||||
// this.host = new DomPortalOutlet(
|
||||
// document.querySelector('#view_change')!,
|
||||
// this.cfr,
|
||||
// this.appRef,
|
||||
// this.injec2tor
|
||||
// );
|
||||
|
||||
// this.host.attach(this.portal);
|
||||
// console.log("Portal attached!");
|
||||
|
||||
this.templatePortal = new TemplatePortal(
|
||||
this.templateRecipeChangeContent,
|
||||
this._containerRef
|
||||
);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
// this.host?.detach();
|
||||
}
|
||||
|
||||
// funcitons
|
||||
|
|
@ -77,20 +171,73 @@ export class MergeComponent implements OnInit {
|
|||
// get patch map keys
|
||||
getPatchMapKeys = () => Object.keys(this.patchMap);
|
||||
|
||||
// check if load patch keys
|
||||
isPatchMapKeysLoaded = () => this.getPatchMapKeys().length > 0;
|
||||
testLoadCheck = () => console.log('test load check', this.isPatchMapKeysLoaded());
|
||||
|
||||
// get product code targets
|
||||
getProductCodesOfCommits = () => Object.keys(this.mapProductCodeWithCommits);
|
||||
|
||||
// mapProductCodeWithCommits have data in it yet?
|
||||
hasProductCodeOfCommits = () =>
|
||||
Object.keys(this.mapProductCodeWithCommits).length > 0;
|
||||
|
||||
// get commit message by commit id
|
||||
getCommitAttr = (id: string, attr: string) => this.fullPatches[id][attr];
|
||||
|
||||
// copy to clipboard
|
||||
copyRef = async (ref: string) => await copy(ref);
|
||||
|
||||
// do show warning conflict if contains same path key in change map
|
||||
isThisCommitConflict = (patchId: string) => {
|
||||
// loop key of change map
|
||||
// find other patch if .changes array contains same path key
|
||||
// if yes, return true
|
||||
if (
|
||||
this.changeMap[patchId] == undefined ||
|
||||
this.changeMap[patchId] == null ||
|
||||
!Object.keys(this.changeMap[patchId]).includes('changes')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let commit = this.changeMap[patchId]['changes'] as Array<any>;
|
||||
for (let key in this.changeMap) {
|
||||
if (key !== patchId) {
|
||||
let testCondition = this.changeMap[key].changes.some(
|
||||
(change: any) =>
|
||||
commit.find((commit: any) => commit.path === change.path) !=
|
||||
undefined
|
||||
);
|
||||
return testCondition;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
selectCommit = (commit: any) => {
|
||||
console.log('select commit', commit.target.value);
|
||||
this.selectedCommit = commit.target.value;
|
||||
}
|
||||
|
||||
buildContext = () => {
|
||||
return {
|
||||
changeContext: undefined,
|
||||
skipZeroes: true,
|
||||
};
|
||||
};
|
||||
|
||||
// ----------------------------- Master Functions ---------------------------
|
||||
|
||||
getMasterRecipeOfProductCode = async (productCode: string) => {
|
||||
(await this._recipeService.getRawRecipeOfProductCode(
|
||||
await this._recipeService.getCurrentCountry(),
|
||||
this._recipeService.getCurrentFile(),
|
||||
productCode
|
||||
)).subscribe({
|
||||
(
|
||||
await this._recipeService.getRawRecipeOfProductCode(
|
||||
await this._recipeService.getCurrentCountry(),
|
||||
this._recipeService.getCurrentFile(),
|
||||
productCode
|
||||
)
|
||||
).subscribe({
|
||||
next: (data: any) => {
|
||||
this.targetRecipe[productCode] = data;
|
||||
// console.log("get master recipe", this.targetRecipe);
|
||||
|
|
@ -106,12 +253,88 @@ export class MergeComponent implements OnInit {
|
|||
);
|
||||
// save only what changes
|
||||
this.changeMap[patchId] = {
|
||||
changes: cmp
|
||||
changes: cmp,
|
||||
};
|
||||
});
|
||||
|
||||
console.log("change map", this.changeMap);
|
||||
}
|
||||
console.log('change map', this.changeMap);
|
||||
},
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
generateMasterRecipeList(productCode: string): any {
|
||||
// this do fetch recipelist
|
||||
|
||||
if (
|
||||
this.targetRecipe[productCode] != undefined ||
|
||||
this.targetRecipe[productCode] != null
|
||||
) {
|
||||
this.getMasterRecipeOfProductCode(productCode);
|
||||
}
|
||||
return this.targetRecipe[productCode].recipes;
|
||||
}
|
||||
|
||||
getRecipeFromSingleLayerPath = (
|
||||
productCode: string,
|
||||
path: string,
|
||||
ref_id: string,
|
||||
popLast?: boolean
|
||||
) => {
|
||||
console.log(
|
||||
'mapProductCodeWithCommits map = ',
|
||||
this.mapProductCodeWithCommits
|
||||
);
|
||||
// split path
|
||||
let pathList = path.split('.');
|
||||
|
||||
if (popLast) {
|
||||
// pop last pathlist
|
||||
pathList.pop();
|
||||
}
|
||||
|
||||
// get product code data
|
||||
let productCodeData = this.targetRecipe[productCode];
|
||||
let data = undefined;
|
||||
for (let pathKey of pathList) {
|
||||
if (data == undefined) {
|
||||
if (!isNaN(parseInt(pathKey))) {
|
||||
data = productCodeData[parseInt(pathKey)];
|
||||
} else {
|
||||
data = productCodeData[pathKey];
|
||||
}
|
||||
} else {
|
||||
if (!isNaN(parseInt(pathKey))) {
|
||||
data = data[parseInt(pathKey)];
|
||||
} else {
|
||||
data = data[pathKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('data from path', path,"=", data);
|
||||
|
||||
// setter
|
||||
this.selectedProductCode = productCode;
|
||||
this.currentTargetOfMaster = productCodeData.recipes;
|
||||
// configure for changes display
|
||||
// this.highlightChanges = data;
|
||||
// this.minimizeUnchanged = true;
|
||||
|
||||
// packing into one map; do update if selected
|
||||
let changeConfigure = {
|
||||
minimizeUnchanged: true,
|
||||
highlightChangeWhenMatched: data,
|
||||
targetProductCode: productCode,
|
||||
targetRecipe: productCodeData,
|
||||
path: path,
|
||||
changes: this.fullPatches[ref_id].contents,
|
||||
};
|
||||
|
||||
this.changePackage = changeConfigure;
|
||||
};
|
||||
|
||||
// revert search by using commit ref id to find productCode
|
||||
getProductCodeByCommitRef = (commitRef: string) => {
|
||||
return this.patchMap[commitRef].productCode;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="justify-center w-full flex flex-row sticky top-0 z-10">
|
||||
<div class="justify-center w-full flex flex-row sticky top-0 z-10" *ngIf="displayOnly == false">
|
||||
<button class="btn w-1/2" (click)="addRow()">Add</button>
|
||||
<button class="btn w-1/2" (click)="removeRow()">Remove</button>
|
||||
</div>
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
(click)="addToSelection(i)"
|
||||
(mousedown)="initHoldEvent()"
|
||||
(mouseup)="openRecipeListEditor(i)"
|
||||
*ngIf="invokeZeroMaterialChecker(i)"
|
||||
>
|
||||
<td class="font-medium text-gray-900 whitespace-nowrap sticky left-0">
|
||||
<input type="checkbox" class="toggle" formControlName="isUse" />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CommonModule, NgFor, NgIf } from '@angular/common';
|
||||
import { Component, EventEmitter, Input, OnInit, Output, ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR } from '@angular/core';
|
||||
import {
|
||||
FormArray,
|
||||
FormBuilder,
|
||||
|
|
@ -42,10 +42,15 @@ import Lang from 'src/app/shared/helpers/lang';
|
|||
standalone: true,
|
||||
imports: [CommonModule,NgIf, NgFor, ReactiveFormsModule, FormsModule, RecipeToppingComponent]
|
||||
})
|
||||
export class RecipeListComponent implements OnInit {
|
||||
export class RecipeListComponent implements OnInit, OnChanges {
|
||||
@Input({ required: true }) productCode!: string;
|
||||
@Input() noFetch: boolean = false;
|
||||
@Input() recipeList: any | undefined = undefined;
|
||||
@Input() displayOnly: boolean = false;
|
||||
@Input() diffChangeContext: {
|
||||
changeContext: any;
|
||||
skipZeroes: boolean;
|
||||
} | undefined = undefined;
|
||||
@Output() recipeListFormChange = new EventEmitter<unknown[]>();
|
||||
|
||||
materialList: MaterialCode[] = [];
|
||||
|
|
@ -267,6 +272,7 @@ export class RecipeListComponent implements OnInit {
|
|||
this.isMatLoaded = true;
|
||||
});
|
||||
} else if(this.recipeList != undefined){
|
||||
console.log("test recipelist", this.recipeList);
|
||||
this.recipeList.forEach( (recipeDetailMat: RecipeDetailMat, index: number) => {
|
||||
|
||||
// StringParam
|
||||
|
|
@ -297,7 +303,7 @@ export class RecipeListComponent implements OnInit {
|
|||
// --------------- mapping missing data ---------------
|
||||
|
||||
// map name
|
||||
console.log("use recipeList input; ", recipeDetailMat);
|
||||
// console.log("use recipeList input; ", recipeDetailMat);
|
||||
|
||||
this.recipeListData.push(
|
||||
this._formBuilder.group({
|
||||
|
|
@ -460,6 +466,216 @@ export class RecipeListComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
async ngOnChanges(changes: SimpleChanges): Promise<void> {
|
||||
|
||||
if(changes['recipeList']){
|
||||
let previousRecipeList = changes['recipeList'].previousValue;
|
||||
let newUpdatedRecipeList = changes['recipeList'].currentValue;
|
||||
let firstTime = changes['recipeList'].isFirstChange();
|
||||
|
||||
console.log("test on changes", changes);
|
||||
if(newUpdatedRecipeList != undefined && !firstTime){
|
||||
console.log("test updated input recipelist", newUpdatedRecipeList);
|
||||
|
||||
// reset
|
||||
this.stringParamData.clear();
|
||||
this.recipeListData.clear();
|
||||
|
||||
newUpdatedRecipeList.forEach( (recipeDetailMat: RecipeDetailMat, index: number) => {
|
||||
|
||||
// StringParam
|
||||
if (
|
||||
recipeDetailMat.StringParam != '' ||
|
||||
recipeDetailMat.StringParam != null
|
||||
) {
|
||||
let currStringParam = new StringParam(recipeDetailMat.StringParam);
|
||||
let stringParamList = currStringParam.extract().as_list();
|
||||
|
||||
let stringParamListTransform: any[] = [];
|
||||
for (let param of stringParamList) {
|
||||
// boolean transform
|
||||
if (param.pvalue == 'true') {
|
||||
param.pvalue = true;
|
||||
} else if (param.pvalue == 'false') {
|
||||
param.pvalue = false;
|
||||
}
|
||||
}
|
||||
|
||||
this.stringParamData.push(
|
||||
this._formBuilder.array(stringParamListTransform)
|
||||
)
|
||||
|
||||
this.stringParams[index] = stringParamList;
|
||||
}
|
||||
|
||||
// --------------- mapping missing data ---------------
|
||||
|
||||
// map name
|
||||
// console.log("use recipeList input; ", recipeDetailMat);
|
||||
|
||||
this.recipeListData.push(
|
||||
this._formBuilder.group({
|
||||
StringParam: [
|
||||
{
|
||||
value: recipeDetailMat.StringParam,
|
||||
disabled: !this.isEditable(),
|
||||
},
|
||||
],
|
||||
isUse: [
|
||||
{ value: recipeDetailMat.isUse, disabled: !this.isEditable() },
|
||||
],
|
||||
materialPathId: [
|
||||
{
|
||||
value: recipeDetailMat.materialPathId,
|
||||
disabled: !this.isEditable(),
|
||||
},
|
||||
],
|
||||
name: [{ value: recipeDetailMat.name, disabled: true }],
|
||||
MixOrder: [
|
||||
{
|
||||
value: recipeDetailMat.MixOrder,
|
||||
disabled: !this.isEditable(),
|
||||
},
|
||||
],
|
||||
stirTime: [
|
||||
{
|
||||
value: recipeDetailMat.stirTime,
|
||||
disabled: !this.isEditable(),
|
||||
},
|
||||
],
|
||||
powderGram: [
|
||||
{
|
||||
value: recipeDetailMat.powderGram,
|
||||
disabled: !this.isEditable(),
|
||||
},
|
||||
],
|
||||
powderTime: [
|
||||
{
|
||||
value: recipeDetailMat.powderTime,
|
||||
disabled: !this.isEditable(),
|
||||
},
|
||||
],
|
||||
syrupGram: [
|
||||
{
|
||||
value: recipeDetailMat.syrupGram,
|
||||
disabled: !this.isEditable(),
|
||||
},
|
||||
],
|
||||
syrupTime: [
|
||||
{
|
||||
value: recipeDetailMat.syrupTime,
|
||||
disabled: !this.isEditable(),
|
||||
},
|
||||
],
|
||||
waterCold: [
|
||||
{
|
||||
value: recipeDetailMat.waterCold,
|
||||
disabled: !this.isEditable(),
|
||||
},
|
||||
],
|
||||
waterYield: [
|
||||
{
|
||||
value: recipeDetailMat.waterYield,
|
||||
disabled: !this.isEditable(),
|
||||
},
|
||||
],
|
||||
feedPattern: [
|
||||
{
|
||||
value: recipeDetailMat.feedPattern,
|
||||
disabled: !this.isEditable(),
|
||||
}
|
||||
],
|
||||
feedParameter: [
|
||||
{
|
||||
value: recipeDetailMat.feedParameter,
|
||||
disabled: !this.isEditable(),
|
||||
}
|
||||
]
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// resub listener
|
||||
|
||||
this.recipeListForm.valueChanges.subscribe((value) => {
|
||||
// console.log(value.recipeListData);
|
||||
// console.log("original recipe detail",this._recipeListOriginalArray);
|
||||
if (
|
||||
!isEqual(
|
||||
sortBy(value, 'materialID'),
|
||||
sortBy(this._recipeListOriginalArray, 'materialID')
|
||||
)
|
||||
) {
|
||||
let emitted_res: any[] = [];
|
||||
|
||||
// force type change. temporary solution
|
||||
forEach(value.recipeListData!, (recipeDetailMat: any) => {
|
||||
recipeDetailMat.materialPathId = parseInt(
|
||||
recipeDetailMat.materialPathId!
|
||||
);
|
||||
|
||||
// revert stirTime
|
||||
recipeDetailMat.stirTime = recipeDetailMat.stirTime!;
|
||||
|
||||
emitted_res.push(recipeDetailMat);
|
||||
});
|
||||
|
||||
this.recipeListFormChange.emit([this.toppingList, emitted_res] as unknown[]);
|
||||
} else {
|
||||
this.recipeListFormChange.emit([]);
|
||||
}
|
||||
});
|
||||
|
||||
this.stringParamForm.valueChanges.subscribe((value) => {
|
||||
// value.stringParamData: Array
|
||||
// where this.stringParams: {[key: number] : {pkey: string, pvalue: any}}
|
||||
|
||||
// transform value to map
|
||||
let mapValue: { [key: number]: { pkey: string; pvalue: any }[] } = {};
|
||||
forEach(value.stringParamData, (param: any, index: number) => {
|
||||
mapValue[index] = param;
|
||||
});
|
||||
|
||||
let checkLen =
|
||||
Object.keys(mapValue).length ==
|
||||
Object.keys(this.stringParams as any).length;
|
||||
let baseLen =
|
||||
Object.keys(this.stringParams as any).length >=
|
||||
Object.keys(mapValue).length
|
||||
? Object.keys(this.stringParams as any).length
|
||||
: Object.keys(mapValue).length;
|
||||
|
||||
if (checkLen) {
|
||||
for (let i = 0; i < baseLen; i++) {
|
||||
if (!isEqual(this.stringParams[i], mapValue[i])) {
|
||||
// console.log('check', (this.stringParams as any)[i], mapValue[i]);
|
||||
|
||||
// transform back to string
|
||||
let initString = ',';
|
||||
for (let key of Object.keys(mapValue[i])) {
|
||||
initString += `${mapValue[i][parseInt(key)].pkey}=${
|
||||
mapValue[i][parseInt(key)].pvalue
|
||||
},`;
|
||||
}
|
||||
|
||||
if (initString.length > 1) {
|
||||
(this.recipeListData.at(i) as any).controls.StringParam.setValue(
|
||||
initString
|
||||
);
|
||||
// console.log('set', initString);
|
||||
}
|
||||
|
||||
// do last
|
||||
this.stringParams[i] = mapValue[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add new row
|
||||
addRow() {
|
||||
|
|
@ -521,6 +737,11 @@ export class RecipeListComponent implements OnInit {
|
|||
}
|
||||
|
||||
isEditable() {
|
||||
|
||||
if(this.displayOnly){
|
||||
return !this.displayOnly;
|
||||
}
|
||||
|
||||
return this._userService
|
||||
.getCurrentUser()!
|
||||
.permissions.includes(UserPermissions.EDITOR);
|
||||
|
|
@ -737,7 +958,7 @@ export class RecipeListComponent implements OnInit {
|
|||
await Promise.resolve();
|
||||
if (this.timeoutHandler) {
|
||||
|
||||
if (this.timeout >= 20) {
|
||||
if (this.timeout >= 20 && !this.displayOnly) {
|
||||
// alert("Opening Recipe List Editor in detail")
|
||||
if (confirm("Are you sure you want to open Recipe List Editor in detail?")) {
|
||||
this.showDetailRecipeList = true;
|
||||
|
|
@ -810,4 +1031,17 @@ export class RecipeListComponent implements OnInit {
|
|||
}
|
||||
|
||||
|
||||
// ----------------------------- Change/Diff -------------------------------
|
||||
|
||||
invokeZeroMaterialChecker = (index: number) => {
|
||||
if(this.diffChangeContext?.skipZeroes == true){
|
||||
// check if current index's material is 0
|
||||
let isZeroMaterial = this.recipeListData.at(index).get('materialPathId')?.value == "0";
|
||||
if(isZeroMaterial){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,21 +82,26 @@ export class RecipeToppingComponent implements OnInit {
|
|||
this._toppingSetOriginalArray = data;
|
||||
console.log('ToppingSet', data, this.index, data.length >= this.index!, data[0]);
|
||||
|
||||
this.listGroupId.push(data[this.index!].ListGroupID);
|
||||
|
||||
// check length of toppingList if in range with given index
|
||||
if (data.length >= this.index!) {
|
||||
this.toppingList.push(
|
||||
this._formBuilder.group({
|
||||
isUse: data[this.index!].isUse,
|
||||
groupID: data[this.index!].groupID,
|
||||
defaultIDSelect: data[this.index!].defaultIDSelect,
|
||||
ListGroupID: data[this.index!].ListGroupID,
|
||||
})
|
||||
);
|
||||
if(data[this.index!] != undefined && data[this.index!] != null){
|
||||
|
||||
this.listGroupId.push(data[this.index!].ListGroupID);
|
||||
|
||||
// check length of toppingList if in range with given index
|
||||
if (data.length >= this.index!) {
|
||||
this.toppingList.push(
|
||||
this._formBuilder.group({
|
||||
isUse: data[this.index!].isUse,
|
||||
groupID: data[this.index!].groupID,
|
||||
defaultIDSelect: data[this.index!].defaultIDSelect,
|
||||
ListGroupID: data[this.index!].ListGroupID,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
console.log('SubscribeToppingSet', this.toppingList, "list group id=", this.listGroupId);
|
||||
}
|
||||
|
||||
console.log('SubscribeToppingSet', this.toppingList, "list group id=", this.listGroupId);
|
||||
});
|
||||
|
||||
// get all topping
|
||||
|
|
|
|||
|
|
@ -305,7 +305,8 @@
|
|||
<th scope="col" class="px-6 py-3" *ngFor="let header of tableHeads">
|
||||
<div class="flex items-center uppercase">
|
||||
{{ header }}
|
||||
<a href="#"
|
||||
<!-- sorting -->
|
||||
<button (click)="sortByHeader(header)"
|
||||
><svg
|
||||
class="w-3 h-3 ml-1.5"
|
||||
aria-hidden="true"
|
||||
|
|
@ -317,7 +318,7 @@
|
|||
d="M8.574 11.024h6.852a2.075 2.075 0 0 0 1.847-1.086 1.9 1.9 0 0 0-.11-1.986L13.736 2.9a2.122 2.122 0 0 0-3.472 0L6.837 7.952a1.9 1.9 0 0 0-.11 1.986 2.074 2.074 0 0 0 1.847 1.086Zm6.852 1.952H8.574a2.072 2.072 0 0 0-1.847 1.087 1.9 1.9 0 0 0 .11 1.985l3.426 5.05a2.123 2.123 0 0 0 3.472 0l3.427-5.05a1.9 1.9 0 0 0 .11-1.985 2.074 2.074 0 0 0-1.846-1.087Z"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3"></th>
|
||||
|
|
|
|||
|
|
@ -166,7 +166,6 @@ export class RecipesComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||
// );
|
||||
|
||||
// // get default file that should be opened
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -626,4 +625,35 @@ export class RecipesComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||
console.log('copyToTsvErr', err);
|
||||
});
|
||||
}
|
||||
|
||||
// ------------------------------------ sorting ------------------------------------
|
||||
|
||||
async sortByHeader(header: string) {
|
||||
// productCode
|
||||
// name
|
||||
// otherName
|
||||
// description
|
||||
// otherDescription
|
||||
// LastUpdate
|
||||
|
||||
// activate sorting
|
||||
console.log('sortByHeader', header);
|
||||
//
|
||||
|
||||
// send to server [/recipe/sort]
|
||||
(
|
||||
await this._recipeService.sortRecipe(
|
||||
await this._recipeService.getCurrentCountry(),
|
||||
this._recipeService.getCurrentFile(),
|
||||
header
|
||||
)
|
||||
).subscribe({
|
||||
|
||||
next: (data: any) => {
|
||||
if(data.status == 'OK'){
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue