feat(merge_component): ✨ Add third souce for diff
Add third source (only from recipe, WIP commit) and attach debugger for checking functions
This commit is contained in:
parent
860dc05cde
commit
1b96e298ee
8 changed files with 439 additions and 175 deletions
|
|
@ -24,10 +24,7 @@
|
||||||
></path>
|
></path>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<a
|
<a routerLink="/departments" class="flex ml-14 max-sm:hidden">
|
||||||
routerLink="/departments"
|
|
||||||
class="flex ml-14 max-sm:hidden"
|
|
||||||
>
|
|
||||||
<img
|
<img
|
||||||
src="assets/logo.svg"
|
src="assets/logo.svg"
|
||||||
class="h-10 md:h-20 px-4"
|
class="h-10 md:h-20 px-4"
|
||||||
|
|
@ -35,32 +32,36 @@
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
<!-- Redis Status -->
|
<!-- Redis Status -->
|
||||||
<div class="p-2 rounded-lg border border-double border-black" [ngStyle]="redisStatus == 'Online'?{'background-color':'greenyellow'}:{'background-color':'tomato'}">
|
<div
|
||||||
<p class="text-center font-bold">{{redisStatus}}</p>
|
class="p-2 rounded-lg border border-double border-black"
|
||||||
|
[ngStyle]="
|
||||||
|
redisStatus == 'Online'
|
||||||
|
? { 'background-color': 'greenyellow' }
|
||||||
|
: { 'background-color': 'tomato' }
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<p class="text-center font-bold">{{ redisStatus }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- File Change Status -->
|
<!-- File Change Status -->
|
||||||
<div *ngIf="isCommitLoaded | async">
|
<div *ngIf="isCommitLoaded | async">
|
||||||
<button onclick="patch_merge_modal.showModal()" >
|
<button onclick="patch_merge_modal.showModal()">
|
||||||
|
<h1
|
||||||
<h1 class="text-center font-extrabold text-2xl text-red-500 animate-pulse">Detect Changes! Click</h1>
|
class="text-center font-extrabold text-2xl text-red-500 animate-pulse"
|
||||||
|
>
|
||||||
|
Detect Changes! Click
|
||||||
|
</h1>
|
||||||
</button>
|
</button>
|
||||||
<dialog id="patch_merge_modal" class="modal">
|
<dialog id="patch_merge_modal" class="modal">
|
||||||
|
<div class="modal-action">
|
||||||
<div class="modal-box max-w-screen-2xl">
|
|
||||||
<app-merge
|
|
||||||
[commit]="changesCommit"
|
|
||||||
></app-merge>
|
|
||||||
<div class="modal-action sticky bottom-0 right-0">
|
|
||||||
<form method="dialog">
|
<form method="dialog">
|
||||||
<button class="btn btn-warning">Close</button>
|
<button class="text-3xl">✕</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="modal-box max-w-screen-2xl">
|
||||||
|
<app-merge [commit]="changesCommit"></app-merge>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</dialog>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -184,4 +185,3 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,50 @@
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<!-- third source selector / from machine -->
|
||||||
|
<label for="anotherKeys">Select another source : </label>
|
||||||
|
<select class="select select-sm select-primary" name="anotherKeys" (change)="selectAnotherSource($event)">
|
||||||
|
<option>--- Commit ---</option>
|
||||||
|
<option
|
||||||
|
*ngFor="let commit of getPatchMapKeys()"
|
||||||
|
[value]="commit"
|
||||||
|
id="source3_{{ commit }}"
|
||||||
|
>
|
||||||
|
[{{ getCommitAttr(commit, "Created_at") }}] [{{
|
||||||
|
getCommitAttr(commit, "Editor")
|
||||||
|
}}] | {{ getCommitAttr(commit, "Msg") }}
|
||||||
|
</option>
|
||||||
|
<option>--- Machine ---</option>
|
||||||
|
<option>--- Recipe ---</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<input type="text" placeholder="version number only..." *ngIf="this.anotherSelectedSource == '--- Recipe ---'" (mouseout)="changeAnotherSource($event)">
|
||||||
|
|
||||||
<!-- enable from console -->
|
<!-- enable from console -->
|
||||||
<button class="hidden" (click)="testLoadCheck()">Test load</button>
|
<button class="hidden" (click)="testLoadCheck()">Test load</button>
|
||||||
|
|
||||||
<!-- This do send to server that the shown commit id will 1be applied to main recipe -->
|
<!-- This do send to server that the shown commit id will 1be applied to main recipe -->
|
||||||
|
|
||||||
<div class="m-2 space-x-2" *ngIf="selectedCommit != '' && selectedCommit != '---'">
|
<div
|
||||||
|
class="m-2 space-x-2"
|
||||||
|
*ngIf="selectedCommit != '' && !isNotSelectable()"
|
||||||
|
>
|
||||||
<button class="btn btn-primary" (click)="sendApply()">Apply</button>
|
<button class="btn btn-primary" (click)="sendApply()">Apply</button>
|
||||||
<button class="btn btn-error">Reject</button>
|
<button class="btn btn-error">Reject</button>
|
||||||
</div>
|
<!-- Queue -->
|
||||||
|
<div
|
||||||
|
class="hidden tooltip m-2 p-2 bg-lime-200 w-48 shadow"
|
||||||
|
data-tip="All added commits/changes will be applied to this version"
|
||||||
|
>
|
||||||
|
<p class="text-center font-semibold justify-center">Merge List</p>
|
||||||
|
|
||||||
|
<div class="space-x-2">
|
||||||
|
<button mat-raised-button>Add</button>
|
||||||
|
<button mat-raised-button>Remove</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 3 columns with master at center -->
|
<!-- 3 columns with master at center -->
|
||||||
|
|
@ -41,11 +75,92 @@
|
||||||
selectedCommit != '---'
|
selectedCommit != '---'
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<details class="collapse collapse-arrow">
|
<!-- option if has ignored in list -->
|
||||||
<summary class="collapse-title bg-red-200">{{ selectedCommit }}</summary>
|
|
||||||
<div
|
<div
|
||||||
class="collapse-content"
|
class="m-2 p-2 !rounded-md bg-gray-400"
|
||||||
|
*ngIf="!isIgnoreListEmpty() && isCommitHasIgnored()"
|
||||||
>
|
>
|
||||||
|
<div class="flex p-2">
|
||||||
|
<p class="font-semibold text-md">Options</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex flex-row p-2 bg-gray-200 space-x-2"
|
||||||
|
id="ignore-replace-with-base-{{ selectedCommit }}"
|
||||||
|
>
|
||||||
|
<input type="checkbox" id="replace-{{ selectedCommit }}-with-base" />
|
||||||
|
<p>Replace selected values with master value</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex flex-row p-2 bg-gray-200 space-x-2"
|
||||||
|
id="ignore-replace-with-machine-{{ selectedCommit }}"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="replace-{{ selectedCommit }}-with-machine"
|
||||||
|
/>
|
||||||
|
<p>Replace selected values with machine value</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- remove -->
|
||||||
|
<div
|
||||||
|
class="flex flex-row p-2 bg-gray-200 space-x-2"
|
||||||
|
id="remove-{{ selectedCommit }}"
|
||||||
|
>
|
||||||
|
<input type="checkbox" id="remove-{{ selectedCommit }}" />
|
||||||
|
<p>Remove it. Don't include this</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- change state -->
|
||||||
|
<div
|
||||||
|
class="flex flex-row p-2 bg-gray-200 space-x-2"
|
||||||
|
id="toggle-state-{{ selectedCommit }}"
|
||||||
|
>
|
||||||
|
<input type="checkbox" id="toggle-state-{{ selectedCommit }}" />
|
||||||
|
<p>Switch state. On {{ "<-->" }} Off</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- other -->
|
||||||
|
<div class="hidden p-2 bg-gray-200 space-x-2" id="command">
|
||||||
|
<div class="flex flex-row p-2 space-x-2">
|
||||||
|
<input type="checkbox" id="command-enable" />
|
||||||
|
<p>Command</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <input class="w-56" type="text"> -->
|
||||||
|
<div class="flex flex-row gap-2">
|
||||||
|
<code class="">
|
||||||
|
<textarea
|
||||||
|
class="p-2 resize-none bg-black text-white"
|
||||||
|
id="command-code"
|
||||||
|
cols="30"
|
||||||
|
rows="10"
|
||||||
|
>
|
||||||
|
//Evaluate</textarea
|
||||||
|
>
|
||||||
|
</code>
|
||||||
|
<code class="">
|
||||||
|
<textarea
|
||||||
|
class="p-2 resize bg-black text-green-600"
|
||||||
|
id="command-output"
|
||||||
|
cols="30"
|
||||||
|
rows="10"
|
||||||
|
></textarea>
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<button class="m-2 btn btn-warning right-2" (click)="eval()">
|
||||||
|
OK
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<details class="collapse collapse-arrow">
|
||||||
|
<summary class="collapse-title bg-red-200">
|
||||||
|
{{ selectedCommit }}
|
||||||
|
</summary>
|
||||||
|
<div class="collapse-content">
|
||||||
<app-recipe-list
|
<app-recipe-list
|
||||||
[productCode]="
|
[productCode]="
|
||||||
getCommitAttr(selectedCommit, 'contents').productCode
|
getCommitAttr(selectedCommit, 'contents').productCode
|
||||||
|
|
@ -64,7 +179,10 @@
|
||||||
<!-- display zone -->
|
<!-- display zone -->
|
||||||
|
|
||||||
<div *ngFor="let pd of getProductCodesOfCommits()">
|
<div *ngFor="let pd of getProductCodesOfCommits()">
|
||||||
<div class="container" *ngIf="pd == getCommitAttr(selectedCommit, 'contents').productCode">
|
<div
|
||||||
|
class="container"
|
||||||
|
*ngIf="pd == getCommitAttr(selectedCommit, 'contents').productCode"
|
||||||
|
>
|
||||||
<details class="collapse collapse-arrow">
|
<details class="collapse collapse-arrow">
|
||||||
<summary class="collapse-title">{{ pd }}</summary>
|
<summary class="collapse-title">{{ pd }}</summary>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -72,8 +190,7 @@
|
||||||
[productCode]="pd!"
|
[productCode]="pd!"
|
||||||
[noFetch]="false"
|
[noFetch]="false"
|
||||||
[displayOnly]="true"
|
[displayOnly]="true"
|
||||||
[diffChangeContext]="buildContext()"
|
[diffChangeContext]="buildContext('master', pd)"
|
||||||
(recipeListFormChange)="onRecipeListFormChange($event)"
|
|
||||||
></app-recipe-list>
|
></app-recipe-list>
|
||||||
</div>
|
</div>
|
||||||
<!-- collapse -->
|
<!-- collapse -->
|
||||||
|
|
@ -81,5 +198,30 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="another-source" *ngIf="hasProductCodeOfCommits() && anotherSelectedSource != ''">
|
||||||
|
<div *ngFor="let pd of getProductCodesOfCommits()">
|
||||||
|
<div *ngIf="pd == getCommitAttr(selectedCommit, 'contents').productCode && anotherTargetRecipe[pd] != undefined">
|
||||||
|
<details class="collapse collapse-arrow">
|
||||||
|
<summary class="collapse-title">{{pd}} - {{anotherSelectedSource}}</summary>
|
||||||
|
<div>
|
||||||
|
<app-recipe-list
|
||||||
|
[productCode]="pd!"
|
||||||
|
[noFetch]="true"
|
||||||
|
[recipeList]="anotherTargetRecipe[pd].recipes"
|
||||||
|
[displayOnly]="true"
|
||||||
|
[diffChangeContext]="buildContext('right', pd)"
|
||||||
|
(recipeListFormChange)="onSourceListFormChange($event)"
|
||||||
|
>
|
||||||
|
|
||||||
|
</app-recipe-list>
|
||||||
</div>
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- another source -->
|
||||||
|
<!-- prep for machine recipe-->
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { RecipeListComponent } from '../recipes/recipe-details/recipe-list/recipe-list.component';
|
import { RecipeListComponent } from '../recipes/recipe-details/recipe-list/recipe-list.component';
|
||||||
import { ResizeEvent, ResizableModule } from 'angular-resizable-element';
|
import { ResizeEvent, ResizableModule } from 'angular-resizable-element';
|
||||||
|
import { Debugger } from 'src/app/shared/helpers/debugger';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-merge',
|
selector: 'app-merge',
|
||||||
|
|
@ -48,11 +50,26 @@ import { ResizeEvent, ResizableModule } from 'angular-resizable-element';
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ResizableModule
|
ResizableModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges {
|
export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges {
|
||||||
onRecipeListFormChange($event: any) {}
|
// from web client
|
||||||
|
onRecipeListFormChange($event: any) {
|
||||||
|
console.log("left side change: ", $event)
|
||||||
|
|
||||||
|
// check if event[1] is an array of 30 elements or more
|
||||||
|
if (!Array.isArray($event[0])) {
|
||||||
|
// event contains index of selection
|
||||||
|
this.ignoredMap[this.selectedCommit] = $event;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// from another source
|
||||||
|
onSourceListFormChange($event: any) {
|
||||||
|
console.log("right side change: ", $event)
|
||||||
|
}
|
||||||
|
|
||||||
// input from layout::getSavedTmp
|
// input from layout::getSavedTmp
|
||||||
@Input() commit: Array<any> | null | undefined = undefined;
|
@Input() commit: Array<any> | null | undefined = undefined;
|
||||||
|
|
@ -67,6 +84,8 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang
|
||||||
targetRecipe: any = {};
|
targetRecipe: any = {};
|
||||||
// change map
|
// change map
|
||||||
changeMap: any = {};
|
changeMap: any = {};
|
||||||
|
// from another source
|
||||||
|
anotherTargetRecipe: any = {};
|
||||||
|
|
||||||
// -------------------- current selection
|
// -------------------- current selection
|
||||||
|
|
||||||
|
|
@ -84,6 +103,9 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang
|
||||||
| undefined = undefined;
|
| undefined = undefined;
|
||||||
|
|
||||||
selectedCommit: string = '';
|
selectedCommit: string = '';
|
||||||
|
anotherSelectedSource: string = '';
|
||||||
|
|
||||||
|
ignoredMap: any = {};
|
||||||
|
|
||||||
// --------------------- Portal
|
// --------------------- Portal
|
||||||
// deprecated~!
|
// deprecated~!
|
||||||
|
|
@ -100,6 +122,9 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang
|
||||||
// ---------------------- Recipe from machine
|
// ---------------------- Recipe from machine
|
||||||
recipeFromMachine: any = {};
|
recipeFromMachine: any = {};
|
||||||
|
|
||||||
|
// --- debug
|
||||||
|
mergeDebugger = new Debugger();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _recipeService: RecipeService
|
private _recipeService: RecipeService
|
||||||
)
|
)
|
||||||
|
|
@ -135,6 +160,7 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang
|
||||||
// store only
|
// store only
|
||||||
await this.getMasterRecipeOfProductCode(productCode!);
|
await this.getMasterRecipeOfProductCode(productCode!);
|
||||||
|
|
||||||
|
|
||||||
// console.log("get master-commits recipe", this.mapProductCodeWithCommits);
|
// console.log("get master-commits recipe", this.mapProductCodeWithCommits);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -149,8 +175,6 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang
|
||||||
|
|
||||||
|
|
||||||
async ngOnInit(): Promise<void> {
|
async ngOnInit(): Promise<void> {
|
||||||
|
|
||||||
|
|
||||||
// fetch related product codes
|
// fetch related product codes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,17 +263,33 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang
|
||||||
};
|
};
|
||||||
|
|
||||||
selectCommit = (commit: any) => {
|
selectCommit = (commit: any) => {
|
||||||
console.log('select commit', commit.target.value);
|
// console.log('select commit', commit.target.value);
|
||||||
this.selectedCommit = commit.target.value;
|
this.selectedCommit = commit.target.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
selectAnotherSource = (sourceType: string) => {
|
selectAnotherSource = (source: any) => {
|
||||||
|
this.anotherSelectedSource = source.target.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildContext = () => {
|
changeAnotherSource = async (source: any) => {
|
||||||
|
this.anotherSelectedSource = "coffeethai02_" + source.target.value+".json";
|
||||||
|
console.log("another source: target version -> ", this.anotherSelectedSource);
|
||||||
|
// activate fetch
|
||||||
|
for(let pd of this.getProductCodesOfCommits()){
|
||||||
|
await this.getAnotherRecipeOfProductCode(pd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(this.selectedCommit == "" || this.selectedCommit == undefined || this.selectedCommit == '---'){
|
// get recipe from machine
|
||||||
|
|
||||||
|
// -- check ignore
|
||||||
|
isIgnoreListEmpty = () => Object.keys(this.ignoredMap).length === 0;
|
||||||
|
isCommitHasIgnored = () => this.ignoredMap[this.selectedCommit] != undefined && this.ignoredMap[this.selectedCommit].length > 0;
|
||||||
|
isNotSelectable = () => this.selectedCommit.startsWith('---');
|
||||||
|
|
||||||
|
buildContext = (ctxType?:string, pd?: string) => {
|
||||||
|
|
||||||
|
if(this.selectedCommit == "" || this.selectedCommit == undefined || this.selectedCommit.startsWith('---')){
|
||||||
return {
|
return {
|
||||||
changeContext: undefined,
|
changeContext: undefined,
|
||||||
skipZeroes: true,
|
skipZeroes: true,
|
||||||
|
|
@ -265,6 +305,23 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang
|
||||||
|
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
if(ctxType != undefined){
|
||||||
|
switch(ctxType){
|
||||||
|
case "master":
|
||||||
|
return {
|
||||||
|
changeContext: undefined,
|
||||||
|
skipZeroes: true,
|
||||||
|
toppingData: this.targetRecipe[pd!].ToppingSet,
|
||||||
|
};
|
||||||
|
case "right":
|
||||||
|
return {
|
||||||
|
changeContext: undefined,
|
||||||
|
skipZeroes: true,
|
||||||
|
toppingData: this.anotherTargetRecipe[pd!].ToppingSet,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
changeContext: undefined,
|
changeContext: undefined,
|
||||||
|
|
@ -307,6 +364,38 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getAnotherRecipeOfProductCode = async (productCode: string) => {
|
||||||
|
(
|
||||||
|
await this._recipeService.getRawRecipeOfProductCode(
|
||||||
|
await this._recipeService.getCurrentCountry(),
|
||||||
|
this.anotherSelectedSource,
|
||||||
|
productCode
|
||||||
|
)
|
||||||
|
).subscribe({
|
||||||
|
next: (data: any) => {
|
||||||
|
this.anotherTargetRecipe[productCode] = data;
|
||||||
|
// console.log("get master recipe", this.targetRecipe);
|
||||||
|
|
||||||
|
// for each patch, get diff master <---> patch
|
||||||
|
// test compare
|
||||||
|
this.getPatchMapKeys().forEach((patchId) => {
|
||||||
|
// compare with master
|
||||||
|
let cmp = compare(
|
||||||
|
this.anotherTargetRecipe[productCode!],
|
||||||
|
this.fullPatches[patchId].contents,
|
||||||
|
['LastChange']
|
||||||
|
);
|
||||||
|
// save only what changes
|
||||||
|
this.changeMap[patchId+"_"+this.anotherSelectedSource] = {
|
||||||
|
changes: cmp,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('change map', this.changeMap);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
generateMasterRecipeList(productCode: string): any {
|
generateMasterRecipeList(productCode: string): any {
|
||||||
// this do fetch recipelist
|
// this do fetch recipelist
|
||||||
|
|
||||||
|
|
@ -319,70 +408,6 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang
|
||||||
return this.targetRecipe[productCode].recipes;
|
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;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// use with 'apply' button
|
// use with 'apply' button
|
||||||
async sendApply() {
|
async sendApply() {
|
||||||
|
|
||||||
|
|
@ -399,6 +424,11 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang
|
||||||
to_send["appliedMachineRecipe"] = this.recipeFromMachine;
|
to_send["appliedMachineRecipe"] = this.recipeFromMachine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// multi-target changes
|
||||||
|
// if(){
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
console.log("sending upgrade", to_send);
|
console.log("sending upgrade", to_send);
|
||||||
|
|
||||||
this._recipeService.upgradeRecipe(
|
this._recipeService.upgradeRecipe(
|
||||||
|
|
@ -420,4 +450,10 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------
|
||||||
|
// attach debugger
|
||||||
|
eval = () => this.mergeDebugger.eval(this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,9 @@
|
||||||
<tr
|
<tr
|
||||||
class="bg-white border-b max-h-4"
|
class="bg-white border-b max-h-4"
|
||||||
[ngClass]="{
|
[ngClass]="{
|
||||||
'bg-red-400': selectedRecipeList.includes(i)
|
'!bg-red-400': selectedRecipeList.includes(i)
|
||||||
}"
|
}"
|
||||||
formGroupName="{{ i }}"
|
formGroupName="{{ i }}"
|
||||||
(click)="addToSelection(i)"
|
|
||||||
(mousedown)="initHoldEvent()"
|
(mousedown)="initHoldEvent()"
|
||||||
(mouseup)="openRecipeListEditor(i)"
|
(mouseup)="openRecipeListEditor(i)"
|
||||||
*ngIf="invokeZeroMaterialChecker(i)"
|
*ngIf="invokeZeroMaterialChecker(i)"
|
||||||
|
|
|
||||||
|
|
@ -762,6 +762,11 @@ export class RecipeListComponent implements OnInit, OnChanges {
|
||||||
}
|
}
|
||||||
this.selectedRecipeList.push(i);
|
this.selectedRecipeList.push(i);
|
||||||
console.log('selected recipe list', this.selectedRecipeList);
|
console.log('selected recipe list', this.selectedRecipeList);
|
||||||
|
|
||||||
|
if(this.displayOnly){
|
||||||
|
// ignore list
|
||||||
|
this.recipeListFormChange.emit(this.selectedRecipeList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get recipeListData(): FormArray {
|
get recipeListData(): FormArray {
|
||||||
|
|
@ -996,6 +1001,7 @@ export class RecipeListComponent implements OnInit, OnChanges {
|
||||||
async openRecipeListEditor(i: number) {
|
async openRecipeListEditor(i: number) {
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
if (this.timeoutHandler) {
|
if (this.timeoutHandler) {
|
||||||
|
console.log("timeout", this.timeout, "display only: ", this.displayOnly);
|
||||||
if (this.timeout >= 20 && !this.displayOnly) {
|
if (this.timeout >= 20 && !this.displayOnly) {
|
||||||
// alert("Opening Recipe List Editor in detail")
|
// alert("Opening Recipe List Editor in detail")
|
||||||
if (
|
if (
|
||||||
|
|
@ -1005,6 +1011,13 @@ export class RecipeListComponent implements OnInit, OnChanges {
|
||||||
} else {
|
} else {
|
||||||
this.showDetailRecipeList = false;
|
this.showDetailRecipeList = false;
|
||||||
}
|
}
|
||||||
|
} else if (this.timeout >= 0 && this.displayOnly){
|
||||||
|
console.log("Activate add to selection",i)
|
||||||
|
this.addToSelection(i);
|
||||||
|
} else if (this.timeout < 10 && !this.displayOnly){
|
||||||
|
// hayaina! taimu a-uto
|
||||||
|
console.log("早お腹(very fast)!タイムアウト(timeout)=", i);
|
||||||
|
this.addToSelection(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearInterval(this.timeoutHandler);
|
clearInterval(this.timeoutHandler);
|
||||||
|
|
|
||||||
130
client/src/app/shared/helpers/debugger.ts
Normal file
130
client/src/app/shared/helpers/debugger.ts
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
// <div class="hidden p-2 bg-gray-200 space-x-2" id="command">
|
||||||
|
// <div class="flex flex-row p-2 space-x-2">
|
||||||
|
// <input type="checkbox" id="command-enable">
|
||||||
|
// <p>Command</p>
|
||||||
|
// </div>
|
||||||
|
|
||||||
|
// <!-- <input class="w-56" type="text"> -->
|
||||||
|
// <div class="flex flex-row gap-2">
|
||||||
|
// <code class="">
|
||||||
|
// <textarea class="p-2 resize-none bg-black text-white" id="command-code" cols="30" rows="10">//Evaluate</textarea>
|
||||||
|
// </code>
|
||||||
|
// <code class="">
|
||||||
|
// <textarea class="p-2 resize bg-black text-green-600" id="command-output" cols="30" rows="10"></textarea>
|
||||||
|
// </code>
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
|
||||||
|
// <div class="flex justify-end">
|
||||||
|
// <button class="m-2 btn btn-warning right-2" (click)="eval()">OK</button>
|
||||||
|
// </div>
|
||||||
|
export class Debugger {
|
||||||
|
public output: any[] = [];
|
||||||
|
// evaluate
|
||||||
|
eval(comp: any) {
|
||||||
|
let enableCommand = document.getElementById('command-enable') as any;
|
||||||
|
this.clear();
|
||||||
|
if(enableCommand.checked){
|
||||||
|
let command = document.getElementById('command-code') as any;
|
||||||
|
console.log(">eval=",command.value);
|
||||||
|
let holdon:any = {};
|
||||||
|
// split line
|
||||||
|
let lines = command.value.split('\n');
|
||||||
|
lines.forEach((line: string, index: number) => {
|
||||||
|
// this.output.push(line);
|
||||||
|
|
||||||
|
// escape line, exec function of class
|
||||||
|
if(line.startsWith("!tb")){
|
||||||
|
let cmd = line.substring(3).trim();
|
||||||
|
switch(cmd){
|
||||||
|
case "proto":
|
||||||
|
this.output.push(Object.keys(comp));
|
||||||
|
break;
|
||||||
|
case "clear":
|
||||||
|
this.clear();
|
||||||
|
break;
|
||||||
|
case "store":
|
||||||
|
let varname = (lines[index -1] as string).split("=")[0].trim();
|
||||||
|
if(varname.includes("let") || varname.includes('var')){
|
||||||
|
varname = varname.split(" ")[1];
|
||||||
|
}
|
||||||
|
holdon[varname] = this.output[this.output.length - 1];
|
||||||
|
this.output.push("OK");
|
||||||
|
break;
|
||||||
|
case "vars":
|
||||||
|
this.output.push(JSON.stringify(holdon));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
if(cmd.startsWith("fn::")){
|
||||||
|
let execFn = cmd.substring(4);
|
||||||
|
|
||||||
|
// get some args
|
||||||
|
let args = execFn.split(' ');
|
||||||
|
execFn = args[0];
|
||||||
|
if(args[1].includes("Var::") || args[1].includes("var::")){
|
||||||
|
args[1] = holdon[args[1].split("::")[1]]
|
||||||
|
}
|
||||||
|
if(args[1].includes(',')){
|
||||||
|
args = args[1].split(',');
|
||||||
|
} else {
|
||||||
|
args = [args[1]];
|
||||||
|
}
|
||||||
|
console.log("args>", args);
|
||||||
|
|
||||||
|
// try exec class function
|
||||||
|
try{
|
||||||
|
|
||||||
|
let res = (comp as any)[execFn].apply("", args);
|
||||||
|
console.log("res>",res);
|
||||||
|
this.output.push(res);
|
||||||
|
} catch (e) {
|
||||||
|
this.output.push(e);
|
||||||
|
}
|
||||||
|
} else if(cmd.startsWith("get::")){
|
||||||
|
let getter = cmd.substring(5);
|
||||||
|
this.output.push(JSON.stringify(comp[getter]));
|
||||||
|
} else if(cmd.startsWith("var::")){
|
||||||
|
let varname = cmd.substring(5);
|
||||||
|
this.output.push(JSON.stringify(holdon[varname]));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (!line.startsWith("//")){
|
||||||
|
|
||||||
|
if(!line.startsWith("window") && !line.startsWith("let") && !line.startsWith("var")){
|
||||||
|
line = "window."+line;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
// is non-comment, exec js
|
||||||
|
let evalResult = eval(line);
|
||||||
|
// if(evalResult == undefined){
|
||||||
|
// evalResult = "see the console";
|
||||||
|
// }
|
||||||
|
this.output.push(evalResult);
|
||||||
|
} catch (error) {
|
||||||
|
this.output.push(error+" or scoped not global. Help: each line's scope is end within its line, you may want to drop `let` or `var` to let it live longer ~. Otherwise, write in the same line.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.print();
|
||||||
|
} else {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
console.log("output", this.output);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(){
|
||||||
|
this.output = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
print(){
|
||||||
|
let output = document.getElementById('command-output') as any;
|
||||||
|
output.value = this.output.join('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1079,78 +1079,17 @@ func (d *Data) MergeRecipe(country, filename, changeKey string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get recipe
|
// get recipe
|
||||||
|
// var sourceRecipe models.Recipe
|
||||||
sourceRecipe := d.GetRecipe(country, filename)
|
sourceRecipe := d.GetRecipe(country, filename)
|
||||||
|
// copy(d.GetRecipe(country, filename), &sourceRecipe)
|
||||||
|
|
||||||
|
// check address
|
||||||
|
fmt.Println("[Source] source === recipe? ", sourceRecipe == d.GetRecipe(country, filename))
|
||||||
|
|
||||||
// apply value to its source
|
// apply value to its source
|
||||||
d.SetValuesToRecipe(sourceRecipe.Recipe01, patchValue)
|
d.SetValuesToRecipe(sourceRecipe.Recipe01, patchValue)
|
||||||
// updating version
|
|
||||||
sourceRecipe.MachineSetting.ConfigNumber += 1
|
|
||||||
newVersionStr := strconv.Itoa(sourceRecipe.MachineSetting.ConfigNumber)
|
|
||||||
|
|
||||||
// save to local and redis
|
return d.finalizedVersion(country, sourceRecipe)
|
||||||
|
|
||||||
// create new file name
|
|
||||||
updatedFilename := ""
|
|
||||||
prefixLocalFile := "coffeethai02_"
|
|
||||||
if country != "tha" {
|
|
||||||
updatedFilename = prefixLocalFile + newVersionStr + "_" + country + ".json"
|
|
||||||
} else {
|
|
||||||
updatedFilename = prefixLocalFile + newVersionStr + ".json"
|
|
||||||
}
|
|
||||||
|
|
||||||
fullUpdatedFilename := path.Join("./cofffeemachineConfig", country, updatedFilename)
|
|
||||||
|
|
||||||
// create new file
|
|
||||||
|
|
||||||
// handle case if file already exists, add version by 1 then search new filename in loop
|
|
||||||
// list all files in dir
|
|
||||||
directory := path.Join("./cofffeemachineConfig", country)
|
|
||||||
files, err := os.ReadDir(directory)
|
|
||||||
if err != nil {
|
|
||||||
d.taoLogger.Log.Error("MergeRecipe: Error when read dir", zap.Error(err))
|
|
||||||
return "ReadDirError", fmt.Errorf("error when read dir: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, file := range files {
|
|
||||||
if file.Name() == updatedFilename {
|
|
||||||
// add version by 1
|
|
||||||
sourceRecipe.MachineSetting.ConfigNumber += 1
|
|
||||||
newVersionStr = strconv.Itoa(sourceRecipe.MachineSetting.ConfigNumber)
|
|
||||||
|
|
||||||
if country != "tha" {
|
|
||||||
updatedFilename = prefixLocalFile + newVersionStr + "_" + country + ".json"
|
|
||||||
} else {
|
|
||||||
updatedFilename = prefixLocalFile + newVersionStr + ".json"
|
|
||||||
}
|
|
||||||
|
|
||||||
fullUpdatedFilename = path.Join("./cofffeemachineConfig", country, updatedFilename)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Create(fullUpdatedFilename)
|
|
||||||
if err != nil {
|
|
||||||
d.taoLogger.Log.Error("MergeRecipe: Error when create new file", zap.Error(err))
|
|
||||||
return "CreateFileError", fmt.Errorf("error when create new file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// write file
|
|
||||||
encoder := json.NewEncoder(file)
|
|
||||||
encoder.SetIndent("", " ")
|
|
||||||
err = encoder.Encode(sourceRecipe)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
d.taoLogger.Log.Error("MergeRecipe: Error when write file", zap.Error(err))
|
|
||||||
return "WriteFileError", fmt.Errorf("error when write file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// set cache
|
|
||||||
err = d.redisClient.SetToKey(updatedFilename, sourceRecipe)
|
|
||||||
if err != nil {
|
|
||||||
d.taoLogger.Log.Error("MergeRecipe: Error when set cache", zap.Error(err))
|
|
||||||
return "SetCacheError", fmt.Errorf("error when set cache: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return updatedFilename, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Data) MergeRecipeNoCache(country string, filename string, updatedRecipe models.Recipe01) (string, error) {
|
func (d *Data) MergeRecipeNoCache(country string, filename string, updatedRecipe models.Recipe01) (string, error) {
|
||||||
|
|
@ -1159,6 +1098,11 @@ func (d *Data) MergeRecipeNoCache(country string, filename string, updatedRecipe
|
||||||
|
|
||||||
// apply value to its source
|
// apply value to its source
|
||||||
d.SetValuesToRecipe(sourceRecipe.Recipe01, updatedRecipe)
|
d.SetValuesToRecipe(sourceRecipe.Recipe01, updatedRecipe)
|
||||||
|
|
||||||
|
return d.finalizedVersion(country, sourceRecipe)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Data) finalizedVersion(country string, sourceRecipe *models.Recipe) (string, error) {
|
||||||
// updating version
|
// updating version
|
||||||
sourceRecipe.MachineSetting.ConfigNumber += 1
|
sourceRecipe.MachineSetting.ConfigNumber += 1
|
||||||
newVersionStr := strconv.Itoa(sourceRecipe.MachineSetting.ConfigNumber)
|
newVersionStr := strconv.Itoa(sourceRecipe.MachineSetting.ConfigNumber)
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ func (s *Server) createHandler() {
|
||||||
ur := routers.NewUserRouter(s.taoLogger, userService)
|
ur := routers.NewUserRouter(s.taoLogger, userService)
|
||||||
ur.Route(r)
|
ur.Route(r)
|
||||||
|
|
||||||
// fmt.Println("routers", r.Routes())
|
// //fmt.Println("routers", r.Routes())
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -169,7 +169,7 @@ func (s *Server) createHandler() {
|
||||||
|
|
||||||
// display all routes [DEBUG]
|
// display all routes [DEBUG]
|
||||||
chi.Walk(r, func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
|
chi.Walk(r, func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
|
||||||
fmt.Println(method, " ---> ", route)
|
//fmt.Println(method, " ---> ", route)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue