diff --git a/client/src/app/core/layout/layout.component.html b/client/src/app/core/layout/layout.component.html index 7b29ba9..e1d08fd 100644 --- a/client/src/app/core/layout/layout.component.html +++ b/client/src/app/core/layout/layout.component.html @@ -24,10 +24,7 @@ > - + -
-

{{redisStatus}}

+
+

{{ redisStatus }}

- - -
@@ -184,4 +185,3 @@ - diff --git a/client/src/app/features/merge/merge.component.html b/client/src/app/features/merge/merge.component.html index f844c27..51c8031 100644 --- a/client/src/app/features/merge/merge.component.html +++ b/client/src/app/features/merge/merge.component.html @@ -19,16 +19,50 @@ +
+ + + + + + -
+
-
+ + +
@@ -41,11 +75,92 @@ selectedCommit != '---' " > -
- {{ selectedCommit }} + +
+
+

Options

+
+
+ +

Replace selected values with master value

+
+
+ +

Replace selected values with machine value

+
+ + +
+ +

Remove it. Don't include this

+
+ + +
+ +

Switch state. On {{ "<-->" }} Off

+
+ + + +
+ +
+
+ +
+ + {{ selectedCommit }} + +
-
+
{{ pd }}
@@ -72,8 +190,7 @@ [productCode]="pd!" [noFetch]="false" [displayOnly]="true" - [diffChangeContext]="buildContext()" - (recipeListFormChange)="onRecipeListFormChange($event)" + [diffChangeContext]="buildContext('master', pd)" >
@@ -81,5 +198,30 @@
+ +
+
+
+
+ {{pd}} - {{anotherSelectedSource}} +
+ + + +
+
+
+
+
+ + + diff --git a/client/src/app/features/merge/merge.component.ts b/client/src/app/features/merge/merge.component.ts index 7871884..1217de7 100644 --- a/client/src/app/features/merge/merge.component.ts +++ b/client/src/app/features/merge/merge.component.ts @@ -33,6 +33,8 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { FormsModule } from '@angular/forms'; import { RecipeListComponent } from '../recipes/recipe-details/recipe-list/recipe-list.component'; import { ResizeEvent, ResizableModule } from 'angular-resizable-element'; +import { Debugger } from 'src/app/shared/helpers/debugger'; + @Component({ selector: 'app-merge', @@ -48,11 +50,26 @@ import { ResizeEvent, ResizableModule } from 'angular-resizable-element'; MatFormFieldModule, MatSelectModule, FormsModule, - ResizableModule + ResizableModule, ], }) 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() commit: Array | null | undefined = undefined; @@ -67,6 +84,8 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang targetRecipe: any = {}; // change map changeMap: any = {}; + // from another source + anotherTargetRecipe: any = {}; // -------------------- current selection @@ -84,6 +103,9 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang | undefined = undefined; selectedCommit: string = ''; + anotherSelectedSource: string = ''; + + ignoredMap: any = {}; // --------------------- Portal // deprecated~! @@ -100,6 +122,9 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang // ---------------------- Recipe from machine recipeFromMachine: any = {}; + // --- debug + mergeDebugger = new Debugger(); + constructor( private _recipeService: RecipeService ) @@ -135,6 +160,7 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang // store only await this.getMasterRecipeOfProductCode(productCode!); + // console.log("get master-commits recipe", this.mapProductCodeWithCommits); }); @@ -149,8 +175,6 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang async ngOnInit(): Promise { - - // fetch related product codes } @@ -239,17 +263,33 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang }; selectCommit = (commit: any) => { - console.log('select commit', commit.target.value); + // console.log('select commit', 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 { changeContext: undefined, 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 { 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 { // this do fetch recipelist @@ -319,70 +408,6 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang 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 async sendApply() { @@ -399,6 +424,11 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang to_send["appliedMachineRecipe"] = this.recipeFromMachine; } + // multi-target changes + // if(){ + + // } + console.log("sending upgrade", to_send); this._recipeService.upgradeRecipe( @@ -420,4 +450,10 @@ export class MergeComponent implements OnInit, AfterViewInit, OnDestroy, OnChang } }); } + + + + // --------------- + // attach debugger + eval = () => this.mergeDebugger.eval(this); } diff --git a/client/src/app/features/recipes/recipe-details/recipe-list/recipe-list.component.html b/client/src/app/features/recipes/recipe-details/recipe-list/recipe-list.component.html index c2984de..356935a 100644 --- a/client/src/app/features/recipes/recipe-details/recipe-list/recipe-list.component.html +++ b/client/src/app/features/recipes/recipe-details/recipe-list/recipe-list.component.html @@ -22,10 +22,9 @@ = 20 && !this.displayOnly) { // alert("Opening Recipe List Editor in detail") if ( @@ -1005,6 +1011,13 @@ export class RecipeListComponent implements OnInit, OnChanges { } else { 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); diff --git a/client/src/app/shared/helpers/debugger.ts b/client/src/app/shared/helpers/debugger.ts new file mode 100644 index 0000000..582d1f5 --- /dev/null +++ b/client/src/app/shared/helpers/debugger.ts @@ -0,0 +1,130 @@ +// + +//
+// +//
+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'); + } +} diff --git a/server/data/data.go b/server/data/data.go index 48375c8..fe90232 100644 --- a/server/data/data.go +++ b/server/data/data.go @@ -1079,78 +1079,17 @@ func (d *Data) MergeRecipe(country, filename, changeKey string) (string, error) } // get recipe + // var sourceRecipe models.Recipe 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 d.SetValuesToRecipe(sourceRecipe.Recipe01, patchValue) - // updating version - sourceRecipe.MachineSetting.ConfigNumber += 1 - newVersionStr := strconv.Itoa(sourceRecipe.MachineSetting.ConfigNumber) - // save to local and redis - - // 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 + return d.finalizedVersion(country, sourceRecipe) } 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 d.SetValuesToRecipe(sourceRecipe.Recipe01, updatedRecipe) + + return d.finalizedVersion(country, sourceRecipe) +} + +func (d *Data) finalizedVersion(country string, sourceRecipe *models.Recipe) (string, error) { // updating version sourceRecipe.MachineSetting.ConfigNumber += 1 newVersionStr := strconv.Itoa(sourceRecipe.MachineSetting.ConfigNumber) diff --git a/server/server.go b/server/server.go index d6dd6f1..049a99a 100644 --- a/server/server.go +++ b/server/server.go @@ -139,7 +139,7 @@ func (s *Server) createHandler() { ur := routers.NewUserRouter(s.taoLogger, userService) 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] 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 })