diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts index 47bb4d4..52f280c 100644 --- a/client/src/app/app-routing.module.ts +++ b/client/src/app/app-routing.module.ts @@ -93,13 +93,13 @@ const routes: Routes = [ ).then((m) => m.RecipeDetailsComponent), canActivate: [authGuard], }, - { - path: 'log', - loadComponent: () => - import('./features/changelog/changelog.component').then( - (m) => m.ChangelogComponent - ), - }, + // { + // path: 'log', + // loadComponent: () => + // import('./features/changelog/changelog.component').then( + // (m) => m.ChangelogComponent + // ), + // }, { path: '**', redirectTo: 'recipes', diff --git a/client/src/app/core/services/recipe.service.ts b/client/src/app/core/services/recipe.service.ts index 46fe787..010ae79 100644 --- a/client/src/app/core/services/recipe.service.ts +++ b/client/src/app/core/services/recipe.service.ts @@ -80,4 +80,20 @@ export class RecipeService { { withCredentials: true, responseType: 'json' } ); } + + editChanges(version: string, change: any){ + console.log("target version = ", version); + console.log("change in edit: ",change.value) + return this._httpClient.post<{ + status: string + }>( + environment.api + ('/recipes/edit/'+version), + change.value, + { withCredentials: true, responseType: 'json', } + ).subscribe({ + next(value) { + console.log(value, change.value) + }, + }); + } } diff --git a/client/src/app/features/changelog/changelog.component.html b/client/src/app/features/changelog/changelog.component.html index b797975..c1e855d 100644 --- a/client/src/app/features/changelog/changelog.component.html +++ b/client/src/app/features/changelog/changelog.component.html @@ -94,4 +94,16 @@ +
+

Diff

+ +
+

Select Version

+
+ + +
+
+ +
diff --git a/client/src/app/features/changelog/changelog.component.ts b/client/src/app/features/changelog/changelog.component.ts index b774390..73f4a79 100644 --- a/client/src/app/features/changelog/changelog.component.ts +++ b/client/src/app/features/changelog/changelog.component.ts @@ -150,5 +150,12 @@ export class ChangelogComponent { -} + } + + + // Add version button + addVersion(){ + let dvs = document.getElementById("diff_version_select"); + dvs!.innerHTML += ``; + } } diff --git a/client/src/app/features/recipes/recipe-details/recipe-details.component.ts b/client/src/app/features/recipes/recipe-details/recipe-details.component.ts index ad1f039..87b5fa0 100644 --- a/client/src/app/features/recipes/recipe-details/recipe-details.component.ts +++ b/client/src/app/features/recipes/recipe-details/recipe-details.component.ts @@ -182,6 +182,14 @@ export class RecipeDetailsComponent implements OnInit { message: 'Do you want to save changes?', confirmCallBack: () => { console.log('confirm save'); + // TODO: update value in targeted recipe + this._recipeService.editChanges( + this._recipeService.getCurrentVersion(), + { + ...this.recipeDetail + } + ); + console.log("Sending changes") this._router.navigate(['/recipes']); }, }; diff --git a/client/src/app/features/recipes/recipes.component.html b/client/src/app/features/recipes/recipes.component.html index 5318882..b47c5c4 100644 --- a/client/src/app/features/recipes/recipes.component.html +++ b/client/src/app/features/recipes/recipes.component.html @@ -191,4 +191,6 @@ + + diff --git a/client/src/app/features/recipes/recipes.component.ts b/client/src/app/features/recipes/recipes.component.ts index 1020980..e659783 100644 --- a/client/src/app/features/recipes/recipes.component.ts +++ b/client/src/app/features/recipes/recipes.component.ts @@ -43,7 +43,12 @@ export class DashboardComponent implements OnInit { private searchStr = ''; private oldSearchStr = ''; + tableCtx?: ElementRef; + @ViewChild('table', { static: false }) set content(table: ElementRef) { + // expose element ref for other fn + this.tableCtx = table; + table.nativeElement.addEventListener( 'scroll', () => { @@ -202,4 +207,8 @@ export class DashboardComponent implements OnInit { '_blank' ); } + + scrollToTop() { + this.tableCtx!.nativeElement.scroll; + } } diff --git a/server/data/data.go b/server/data/data.go index a461406..3681371 100644 --- a/server/data/data.go +++ b/server/data/data.go @@ -6,8 +6,15 @@ import ( "os" "path/filepath" "recipe-manager/models" + "recipe-manager/services/logger" "sort" "time" + + "go.uber.org/zap" +) + +var ( + Log = logger.GetInstance() ) func readFile(version string) *models.Recipe { @@ -131,6 +138,27 @@ func (d *Data) GetRecipe01() []models.Recipe01 { return d.currentRecipe.Recipe01 } +func (d *Data) GetRecipe01ByProductCode(code string) models.Recipe01 { + result := make([]models.Recipe01, 0) + + for _, v := range d.currentRecipe.Recipe01 { + if v.ProductCode == code { + result = append(result, v) + } + } + + return result[0] +} + +func (d *Data) SetValuesToRecipe(recipe models.Recipe01) { + for _, v := range d.currentRecipe.Recipe01 { + if v.ProductCode == recipe.ProductCode { + v = recipe + break + } + } +} + func (d *Data) GetMaterialSetting(version string) []models.MaterialSetting { result := make([]models.MaterialSetting, 0) @@ -225,3 +253,13 @@ func (d *Data) GetMaterialCode(ids []uint64, version string) []models.MaterialCo return resultFilter } + +func (d *Data) ExportToJSON() []byte { + b_recipe, err := json.Marshal(d.currentRecipe) + if err != nil { + Log.Error("Error when marshal recipe", zap.Error(err)) + return nil + } + + return b_recipe +} diff --git a/server/models/recipe.go b/server/models/recipe.go index a9c17db..df7a8ea 100644 --- a/server/models/recipe.go +++ b/server/models/recipe.go @@ -1,5 +1,7 @@ package models +import "encoding/json" + type Recipe struct { Timestamp string `json:"Timestamp"` MachineSetting MachineSetting `json:"MachineSetting"` @@ -82,6 +84,19 @@ type Recipe01 struct { Weight_float int `json:"weight_float"` } +func (r *Recipe01) ToMap() map[string]interface{} { + var m map[string]interface{} + recipeRecord, _ := json.Marshal(r) + json.Unmarshal(recipeRecord, &m) + return m +} + +func (r *Recipe01) FromMap(m map[string]interface{}) Recipe01 { + recipeRecord, _ := json.Marshal(m) + json.Unmarshal(recipeRecord, &r) + return *r +} + type MatRecipe struct { MixOrder int `json:"MixOrder"` FeedParameter int `json:"FeedParameter"` diff --git a/server/routers/recipe.go b/server/routers/recipe.go index 0ab7133..3a9fe07 100644 --- a/server/routers/recipe.go +++ b/server/routers/recipe.go @@ -2,15 +2,19 @@ package routers import ( "encoding/json" + "io/fs" "net/http" + "os" "recipe-manager/data" "recipe-manager/models" + "recipe-manager/services/logger" "recipe-manager/services/sheet" "sort" "strconv" "strings" "github.com/go-chi/chi/v5" + "go.uber.org/zap" ) type RecipeRouter struct { @@ -18,6 +22,10 @@ type RecipeRouter struct { sheetService sheet.SheetService } +var ( + Log = logger.GetInstance() +) + func NewRecipeRouter(data *data.Data, sheetService sheet.SheetService) *RecipeRouter { return &RecipeRouter{ data: data, @@ -143,5 +151,53 @@ func (rr *RecipeRouter) Route(r chi.Router) { } json.NewEncoder(w).Encode(mapResult) }) + + r.Post("/edit/{version}", func(w http.ResponseWriter, r *http.Request) { + Log.Debug("Edit: ", zap.String("path", r.RequestURI)) + version := chi.URLParam(r, "version") + target_recipe := rr.data.GetRecipe(version) + + Log.Debug("Target => ", zap.Any("target", target_recipe.MachineSetting.ConfigNumber)) + + // Body + var changes models.Recipe01 + err := json.NewDecoder(r.Body).Decode(&changes) + if err != nil { + Log.Error("Decode in request failed: ", zap.Error(err)) + } + + Log.Debug("Changes: ", zap.Any("changes", changes)) + // TODO: find the matched pd + target_menu := rr.data.GetRecipe01ByProductCode(changes.ProductCode) + + menu_map := target_menu.ToMap() + change_map := changes.ToMap() + + // Find changes + for key, val := range menu_map { + if val != change_map[key] { + menu_map[key] = change_map[key] + } + } + + // Apply changes + tempRecipe := models.Recipe01{} + tempRecipe = tempRecipe.FromMap(menu_map) + rr.data.SetValuesToRecipe(tempRecipe) + + finalData := rr.data.ExportToJSON() + temp_finalData, err := json.MarshalIndent(finalData, "", " ") + if err != nil { + Log.Error("Error when indent marshal recipe", zap.Error(err)) + return + } + + os.WriteFile("./cofffeemachineConfig/coffeethai02_"+version+".json", temp_finalData, fs.FileMode(0666)) + + w.Header().Add("Content-Type", "application/json") + json.NewEncoder(w).Encode(map[string]interface{}{ + "status": "OK", + }) + }) }) } diff --git a/server/server.go b/server/server.go index b02f0fa..f61729e 100644 --- a/server/server.go +++ b/server/server.go @@ -324,67 +324,8 @@ func (s *Server) createHandler() { }) - // r.Get("/mergelogList", func(w http.ResponseWriter, r *http.Request) { - // ch_dir, err := os.ReadDir("cofffeemachineConfig/changelog") - // if err != nil { - // Log.Error("Error while trying to read dir: ", zap.String("dir", "cofffeemachineConfig/changelog"), zap.Error(err)) - // http.Error(w, err.Error(), http.StatusInternalServerError) - // } - // displayable := make([]string, 0) - - // for _, file := range ch_dir { - // if strings.Contains(file.Name(), ".html") { - - // displayable = append(displayable, file.Name()[:len(file.Name())-len(filepath.Ext(file.Name()))]) - // } - // } - // w.Header().Set("Content-Type", "application/json") - // w.WriteHeader(http.StatusOK) - // json.NewEncoder(w).Encode(map[string][]string{"dirs": displayable}) - // }) - r.Get("/listFileInDir/*", func(w http.ResponseWriter, r *http.Request) { - // // socket - // socket, err := upgrader.Upgrade(w, r, nil) - - // if err != nil { - // Log.Error("Error while trying to upgrade socket: ", zap.Error(err)) - // return - // } - - // // TODO: Change to websocket for better performance - // for { - // msg_type, msg, err := socket.ReadMessage() - - // if err != nil { - // Log.Warn("Idle ", zap.Any("status", err)) - // return - // } - - // var msgPayload map[string]interface{} - - // err = json.Unmarshal(msg, &msgPayload) - // if err != nil { - // Log.Error("Error while trying to unmarshal message: ", zap.Error(err)) - // return - // } - - // // topic := msgPayload["topic"].(string) - - // Log.Info("Receive message: ", zap.Any("msg_type", msg_type), zap.Any("msg", msgPayload)) - - // response, err := json.Marshal(map[string]interface{}{ - // "message": "ok", - // }) - // if err != nil { - // Log.Error("Error at marshalling response: ", zap.Error(err)) - // return - // } - // // respons to client - // socket.WriteMessage(msg_type, response) - // } - //spl spl_path := strings.Split(r.RequestURI, "/") if len(spl_path) > 3 { @@ -437,6 +378,51 @@ func (s *Server) createHandler() { Log.Debug("Scan dir completed < ", zap.String("path", r.RequestURI)) }) + r.Get("/get_log_relation", func(w http.ResponseWriter, r *http.Request) { + + // Python looker + py_exec, err := exec.LookPath("python") + if err != nil { + Log.Error("Error while trying to find python: ", zap.Error(err)) + http.Error(w, err.Error(), http.StatusInternalServerError) + } + + merge_timeline, api_err := os.Open("./python_api/merge_timeline.py") + if api_err != nil { + Log.Error("Error while trying to open merge_timeline.json: ", zap.Error(api_err)) + http.Error(w, api_err.Error(), http.StatusInternalServerError) + } + defer merge_timeline.Close() + + cmd := exec.Command(py_exec, merge_timeline.Name(), "get_relate") + + Log.Debug("Command: ", zap.String("command", cmd.String())) + + out, err := cmd.CombinedOutput() + + Log.Debug("Output: ", zap.String("output", string(out))) + + if err != nil { + Log.Error("Error while trying to run python: ", zap.Error(err)) + http.Error(w, err.Error(), http.StatusInternalServerError) + } + + // clean up output + clean1 := strings.ReplaceAll(string(out), "\n", "") + clean2 := strings.ReplaceAll(clean1, "\r", "") + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string]interface{}{ + "message": clean2, + }) + }) + + r.Post("/diffpy/*", func(w http.ResponseWriter, r *http.Request) { + Log.Debug("Diffpy: ", zap.String("path", r.RequestURI)) + // TODO: add command exec `python_Exec` `merge_recipe.py` `diff` `master_version` `version-version-version` `debug?` `flatten={true|false}` `out={true|false}` + }) + sheetService, err := sheet.NewSheetService(context.Background(), s.cfg) if err != nil {