⚠️ WIP migrating tmp to patch
This commit is contained in:
parent
89ce1f361c
commit
fed315367a
13 changed files with 317 additions and 270 deletions
|
|
@ -34,7 +34,19 @@
|
||||||
alt="Tao Bin Logo"
|
alt="Tao Bin Logo"
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
|
<!-- Redis Status -->
|
||||||
|
<div 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>
|
||||||
|
|
||||||
|
<!-- File Change Status -->
|
||||||
|
<button *ngIf="showDetectChanges">
|
||||||
|
|
||||||
|
<h1 class="text-center font-extrabold text-2xl text-red-500 animate-pulse">Detect Changes! Click</h1>
|
||||||
|
|
||||||
|
</button>
|
||||||
|
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div class="flex items-center ml-3">
|
<div class="flex items-center ml-3">
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
|
|
@ -155,3 +167,5 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!--Modal-->
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, RouterModule } from '@angular/router';
|
import { ActivatedRoute, RouterModule } from '@angular/router';
|
||||||
import { DatePipe, NgFor, NgIf, NgOptimizedImage } from '@angular/common';
|
import { CommonModule, DatePipe, NgFor, NgIf, NgOptimizedImage } from '@angular/common';
|
||||||
import { GoogleButtonComponent } from 'src/app/shared/googleButton/googleButton.component';
|
import { GoogleButtonComponent } from 'src/app/shared/googleButton/googleButton.component';
|
||||||
import { UserService } from '../services/user.service';
|
import { UserService } from '../services/user.service';
|
||||||
import { User } from '../models/user.model';
|
import { User } from '../models/user.model';
|
||||||
import { Subject, Subscription, map, share, takeUntil, timer } from 'rxjs';
|
import { Subject, Subscription, map, share, takeUntil, timer } from 'rxjs';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { environment } from 'src/environments/environment';
|
||||||
|
import { RecipeService } from '../services/recipe.service';
|
||||||
|
import { AsyncStorage } from 'src/app/shared/helpers/asyncStorage';
|
||||||
|
import { MergeComponent } from "../../features/merge/merge.component";
|
||||||
|
|
||||||
interface MenuItem {
|
interface MenuItem {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -13,17 +18,19 @@ interface MenuItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-layout',
|
selector: 'app-layout',
|
||||||
templateUrl: './layout.component.html',
|
templateUrl: './layout.component.html',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule,
|
RouterModule,
|
||||||
NgFor,
|
NgFor,
|
||||||
NgIf,
|
NgIf,
|
||||||
GoogleButtonComponent,
|
GoogleButtonComponent,
|
||||||
DatePipe,
|
DatePipe,
|
||||||
NgOptimizedImage,
|
NgOptimizedImage,
|
||||||
],
|
CommonModule,
|
||||||
|
MergeComponent
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class LayoutComponent implements OnInit, OnDestroy {
|
export class LayoutComponent implements OnInit, OnDestroy {
|
||||||
current_department = this._router.snapshot.paramMap.get('department')!;
|
current_department = this._router.snapshot.paramMap.get('department')!;
|
||||||
|
|
@ -51,12 +58,17 @@ export class LayoutComponent implements OnInit, OnDestroy {
|
||||||
user: User | null = null;
|
user: User | null = null;
|
||||||
exit$ = new Subject<void>();
|
exit$ = new Subject<void>();
|
||||||
|
|
||||||
|
redisStatus:string = "Offline";
|
||||||
|
showDetectChanges: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _userService: UserService,
|
private _userService: UserService,
|
||||||
private _router: ActivatedRoute
|
private _router: ActivatedRoute,
|
||||||
|
private _httpClient: HttpClient,
|
||||||
|
private _recipeService: RecipeService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
async ngOnInit(): Promise<void> {
|
||||||
this._userService.currentUser
|
this._userService.currentUser
|
||||||
.pipe(takeUntil(this.exit$))
|
.pipe(takeUntil(this.exit$))
|
||||||
.subscribe((user) => (this.user = user));
|
.subscribe((user) => (this.user = user));
|
||||||
|
|
@ -69,6 +81,32 @@ export class LayoutComponent implements OnInit, OnDestroy {
|
||||||
.subscribe((time) => {
|
.subscribe((time) => {
|
||||||
this.date = time;
|
this.date = time;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._httpClient.get(environment.api + "/health/redis").subscribe((status) => {
|
||||||
|
this.redisStatus = (status as any)["status"];
|
||||||
|
});
|
||||||
|
|
||||||
|
// check if saves existed
|
||||||
|
this._recipeService.getSavedTmp(
|
||||||
|
await this._recipeService.getCurrentCountry(),
|
||||||
|
this._recipeService.getCurrentFile()
|
||||||
|
).subscribe({
|
||||||
|
next: async (data: any) => {
|
||||||
|
if(data != undefined && typeof data === 'object'){
|
||||||
|
// check if attr exists
|
||||||
|
if(data.files != null){
|
||||||
|
this.showDetectChanges = true;
|
||||||
|
await AsyncStorage.setItem("detectChanges", "true");
|
||||||
|
} else {
|
||||||
|
this.showDetectChanges = false;
|
||||||
|
await AsyncStorage.setItem("detectChanges", "false");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.showDetectChanges = false;
|
||||||
|
await AsyncStorage.setItem("detectChanges", "false");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,10 @@ export class RecipeService {
|
||||||
return this.tmp_files;
|
return this.tmp_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private _httpClient: HttpClient, private _route: ActivatedRoute) {}
|
constructor(
|
||||||
|
private _httpClient: HttpClient,
|
||||||
|
private _route: ActivatedRoute
|
||||||
|
) {}
|
||||||
|
|
||||||
getRecipesDashboard(
|
getRecipesDashboard(
|
||||||
params: any = {
|
params: any = {
|
||||||
|
|
@ -95,8 +98,9 @@ export class RecipeService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRecipeDetail(productCode: string): Promise<Observable<RecipeDetail>> {
|
async getRecipeDetail(
|
||||||
|
productCode: string
|
||||||
|
): Promise<Observable<RecipeDetail>> {
|
||||||
let asyncCountry = await this.getCurrentCountry(this.department!);
|
let asyncCountry = await this.getCurrentCountry(this.department!);
|
||||||
console.log('get detail by asyncCountry', asyncCountry);
|
console.log('get detail by asyncCountry', asyncCountry);
|
||||||
|
|
||||||
|
|
@ -115,8 +119,7 @@ export class RecipeService {
|
||||||
|
|
||||||
async getRecipeDetailMat(
|
async getRecipeDetailMat(
|
||||||
productCode: string
|
productCode: string
|
||||||
): Promise<Observable<{ result: RecipeDetailMat[]; }>> {
|
): Promise<Observable<{ result: RecipeDetailMat[] }>> {
|
||||||
|
|
||||||
let asyncCountry = await this.getCurrentCountry(this.department!);
|
let asyncCountry = await this.getCurrentCountry(this.department!);
|
||||||
|
|
||||||
return this._httpClient.get<{ result: RecipeDetailMat[] }>(
|
return this._httpClient.get<{ result: RecipeDetailMat[] }>(
|
||||||
|
|
@ -133,10 +136,8 @@ export class RecipeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentFile(): string {
|
getCurrentFile(): string {
|
||||||
|
|
||||||
// TODO: get default from server
|
// TODO: get default from server
|
||||||
|
|
||||||
|
|
||||||
const currentRecipeFile = localStorage.getItem('currentRecipeFile');
|
const currentRecipeFile = localStorage.getItem('currentRecipeFile');
|
||||||
if (currentRecipeFile) {
|
if (currentRecipeFile) {
|
||||||
return currentRecipeFile;
|
return currentRecipeFile;
|
||||||
|
|
@ -150,9 +151,7 @@ export class RecipeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCurrentCountry(department?: string): Promise<string> {
|
async getCurrentCountry(department?: string): Promise<string> {
|
||||||
|
if (department) {
|
||||||
if(department){
|
|
||||||
|
|
||||||
// translate back to full name
|
// translate back to full name
|
||||||
let fullname = getCountryMapSwitcher(department);
|
let fullname = getCountryMapSwitcher(department);
|
||||||
|
|
||||||
|
|
@ -167,7 +166,9 @@ export class RecipeService {
|
||||||
|
|
||||||
// const currentRecipeCountry = localStorage.getItem('currentRecipeCountry');
|
// const currentRecipeCountry = localStorage.getItem('currentRecipeCountry');
|
||||||
|
|
||||||
const currentRecipeCountry = await AsyncStorage.getItem<string>('currentRecipeCountry');
|
const currentRecipeCountry = await AsyncStorage.getItem<string>(
|
||||||
|
'currentRecipeCountry'
|
||||||
|
);
|
||||||
if (currentRecipeCountry) {
|
if (currentRecipeCountry) {
|
||||||
return currentRecipeCountry;
|
return currentRecipeCountry;
|
||||||
}
|
}
|
||||||
|
|
@ -275,13 +276,37 @@ export class RecipeService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRawRecipeOfProductCode(country: string, filename: string, productCode: string): Promise<Observable<{}>> {
|
async getRawRecipeOfProductCode(
|
||||||
|
country: string,
|
||||||
|
filename: string,
|
||||||
|
productCode: string
|
||||||
|
): Promise<Observable<{}>> {
|
||||||
return this._httpClient.get<{}>(
|
return this._httpClient.get<{}>(
|
||||||
environment.api + '/recipes/' + country + '/' + filename + '/' + productCode + '/raw_full',
|
environment.api +
|
||||||
|
'/recipes/' +
|
||||||
|
country +
|
||||||
|
'/' +
|
||||||
|
filename +
|
||||||
|
'/' +
|
||||||
|
productCode +
|
||||||
|
'/raw_full',
|
||||||
{
|
{
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
responseType: 'json',
|
responseType: 'json',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getPatchListOfCurrentFile(
|
||||||
|
country: string,
|
||||||
|
filename: string
|
||||||
|
): Promise<Observable<any>> {
|
||||||
|
|
||||||
|
console.log("try get patches", country, filename);
|
||||||
|
|
||||||
|
return this._httpClient.get<any>(
|
||||||
|
environment.api + '/recipes/patch/get/' + country + '/' + filename ,
|
||||||
|
{ withCredentials: true, responseType: 'json' }
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { MergeComponent } from '../merge/merge.component';
|
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { environment } from 'src/environments/environment.development';
|
import { environment } from 'src/environments/environment.development';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
@ -10,7 +10,7 @@ import { FetchLogService } from 'src/app/shared/services/fetch-log.service';
|
||||||
standalone: true,
|
standalone: true,
|
||||||
templateUrl: './changelog.component.html',
|
templateUrl: './changelog.component.html',
|
||||||
styleUrls: ['./changelog.component.css'],
|
styleUrls: ['./changelog.component.css'],
|
||||||
imports: [CommonModule, MergeComponent],
|
imports: [CommonModule],
|
||||||
})
|
})
|
||||||
export class ChangelogComponent {
|
export class ChangelogComponent {
|
||||||
public displayableLogs: string[] = [];
|
public displayableLogs: string[] = [];
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { MergeServiceService } from './merge-service.service';
|
|
||||||
|
|
||||||
describe('MergeServiceService', () => {
|
|
||||||
let service: MergeServiceService;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({});
|
|
||||||
service = TestBed.inject(MergeServiceService);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class MergeServiceService {
|
|
||||||
|
|
||||||
master_version: number = 0;
|
|
||||||
dev_version: number = 0;
|
|
||||||
output_path:string = "";
|
|
||||||
changelog_path:string = "";
|
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +1 @@
|
||||||
|
<p>merge works!</p>
|
||||||
<div class="flex-3 bg-stone-400 h-screen justify-centers items-center">
|
|
||||||
|
|
||||||
<h3 class="text-2xl text-center py-4 font-semibold">Merge 2 json</h3>
|
|
||||||
|
|
||||||
<div class="bg-stone-600 p-1 m-2 rounded-md">
|
|
||||||
<div class="bg-stone-500 m-2 rounded-md">
|
|
||||||
<p class="px-1 py-5 font-semibold">
|
|
||||||
❓ What does this function do?
|
|
||||||
</p>
|
|
||||||
<div class="bg-stone-300 rounded">
|
|
||||||
<p class="px-2 ">
|
|
||||||
Apply changes from the `dev` version
|
|
||||||
<br>into the `master` version
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="bg-stone-200 p-1 m-2 rounded-md">
|
|
||||||
<p class="px-2 py-4 text-md text-center font-bold">
|
|
||||||
❗Beware❗
|
|
||||||
<br>`master` = base version
|
|
||||||
<br>`dev` = your version
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<form class="space-y-6 p-3 bg-stone-500 rounded" [formGroup]="mergeForm" (ngSubmit)="fetchMerge()">
|
|
||||||
<div class="flex">
|
|
||||||
<label class="flex-1 text-red-700 font-bold bg-yellow-100 rounded text-center" for="master_version">Master</label>
|
|
||||||
<input class="flex-1 mx-1 bg-slate-300 hover:bg-blue-400 text-center border border-collapse rounded-md" id="master_version" formControlName="master_version" type="text" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex">
|
|
||||||
<label class="flex-1 bg-yellow-100 font-bold rounded text-center" for="dev_version">Dev</label>
|
|
||||||
<input class="flex-1 mx-1 bg-slate-300 hover:bg-blue-400 text-center border border-collapse rounded-md" id="dev_version" formControlName="dev_version" type="text" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Output path -->
|
|
||||||
<div class="flex">
|
|
||||||
<label class="flex-1 bg-yellow-100 font-bold rounded text-center" for="output_path">Output Path (.json)</label>
|
|
||||||
<input class="flex-1 mx-1 bg-slate-300 hover:bg-blue-400 text-center border border-collapse rounded-md" id="output_path" formControlName="output_path" type="text" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Changelog path -->
|
|
||||||
<div class="flex">
|
|
||||||
<label class="flex-1 bg-yellow-100 font-bold rounded text-center" for="changelog_path">Changelog Path (.json)</label>
|
|
||||||
<input class="flex-1 mx-1 bg-slate-300 hover:bg-blue-400 text-center border border-collapse rounded-md" id="changelog_path" formControlName="changelog_path" type="text" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button class="button font-semibold bg-red-300 p-4 border border-collapse rounded-md" type="submit">Begin Merge</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { MergeComponent } from './merge.component';
|
|
||||||
|
|
||||||
describe('MergeComponent', () => {
|
|
||||||
let component: MergeComponent;
|
|
||||||
let fixture: ComponentFixture<MergeComponent>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
imports: [MergeComponent]
|
|
||||||
});
|
|
||||||
fixture = TestBed.createComponent(MergeComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,90 +1,31 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { RecipeService } from 'src/app/core/services/recipe.service';
|
||||||
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { MergeServiceService } from './merge-service.service';
|
|
||||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
|
||||||
import { environment } from 'src/environments/environment.development';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { ChangelogComponent } from '../changelog/changelog.component';
|
|
||||||
import { FetchLogService } from 'src/app/shared/services/fetch-log.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-merge',
|
selector: 'app-merge',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, ReactiveFormsModule, ChangelogComponent],
|
imports: [CommonModule],
|
||||||
templateUrl: './merge.component.html',
|
templateUrl: './merge.component.html',
|
||||||
styleUrls: ['./merge.component.css']
|
|
||||||
})
|
})
|
||||||
export class MergeComponent<T> {
|
export class MergeComponent implements OnInit {
|
||||||
|
|
||||||
exceptionValues = [0, null, undefined]
|
patchMap: any = {}
|
||||||
|
|
||||||
mergeForm = this.formBuilder.group({
|
|
||||||
master_version: 0,
|
|
||||||
dev_version: 0,
|
|
||||||
output_path: "",
|
|
||||||
changelog_path: ""
|
|
||||||
});
|
|
||||||
|
|
||||||
default_output_path = "cofffeemachineConfig/merge/"
|
|
||||||
default_changelog_path = "cofffeemachineConfig/changelog/"
|
|
||||||
|
|
||||||
mergeLogs: Map<string, string> | void | undefined
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private targets: MergeServiceService,
|
private _recipeService: RecipeService
|
||||||
private formBuilder: FormBuilder,
|
) { }
|
||||||
private httpClient: HttpClient,
|
|
||||||
private chlog: ChangelogComponent
|
|
||||||
){
|
|
||||||
// Default fetching logs
|
|
||||||
|
|
||||||
// fetch html
|
async ngOnInit(): Promise<void> {
|
||||||
// this.fetchLogsToDisplay("", true, false);
|
(await this._recipeService.getPatchListOfCurrentFile(
|
||||||
// // fetch log file
|
await this._recipeService.getCurrentCountry(),
|
||||||
// this.fetchLogsToDisplay("", false, false);
|
this._recipeService.getCurrentFile()
|
||||||
// // fetch json
|
)).subscribe({
|
||||||
// this.mergeLogs = this.fetchLogsToDisplay("", false, true);
|
next: (data: any) => {
|
||||||
|
this.patchMap = data;
|
||||||
|
console.log("patches",this.patchMap);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private isException(value: any){
|
|
||||||
return this.exceptionValues.includes(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchMerge(){
|
|
||||||
if(this.isException(this.mergeForm.value.master_version) || this.isException(this.mergeForm.value.dev_version)){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.targets.master_version = this.mergeForm.value.master_version!;
|
|
||||||
this.targets.dev_version = this.mergeForm.value.dev_version!;
|
|
||||||
this.targets.output_path = this.default_output_path + this.mergeForm.value.output_path!;
|
|
||||||
this.targets.changelog_path = this.default_changelog_path + this.mergeForm.value.changelog_path!;
|
|
||||||
|
|
||||||
// TODO: Fetch merge. Modify this to websocket
|
|
||||||
this.httpClient.post<T>(environment.api+"/merge", {
|
|
||||||
master: this.targets.master_version,
|
|
||||||
dev: this.targets.dev_version,
|
|
||||||
output: this.targets.output_path,
|
|
||||||
changelog: this.targets.changelog_path
|
|
||||||
}, {
|
|
||||||
withCredentials: true
|
|
||||||
}).subscribe({
|
|
||||||
next: (value: T) => {
|
|
||||||
console.log(value)
|
|
||||||
if(typeof value === "object" && value !== null){
|
|
||||||
if("message" in value){
|
|
||||||
// fetch html
|
|
||||||
// this.fetchLogsToDisplay("", true, false);
|
|
||||||
// fetch log file
|
|
||||||
// this.fetchLogsToDisplay("", false, false);
|
|
||||||
// fetch json
|
|
||||||
this.mergeLogs = new FetchLogService(this.httpClient).fetchLogsToDisplay("", false, true,this.targets.changelog_path);
|
|
||||||
this.chlog.fetchLoglist();
|
|
||||||
this.chlog.translateLogDirToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ export class RecipesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
|
|
||||||
savedTmpfiles: any[] = [];
|
savedTmpfiles: any[] = [];
|
||||||
saveTab: boolean = false;
|
saveTab: boolean = false;
|
||||||
showSaveNoti: boolean = true;
|
showSaveNoti: boolean = false;
|
||||||
|
|
||||||
department: string = this.route.parent!.snapshot.params['department'];
|
department: string = this.route.parent!.snapshot.params['department'];
|
||||||
copyList: any[] = [];
|
copyList: any[] = [];
|
||||||
|
|
@ -197,7 +197,7 @@ export class RecipesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME: Lag assigned
|
// : Lag assigned
|
||||||
|
|
||||||
this.recipesDashboard$.subscribe(async (data) => {
|
this.recipesDashboard$.subscribe(async (data) => {
|
||||||
this.currentVersion = data.configNumber;
|
this.currentVersion = data.configNumber;
|
||||||
|
|
@ -241,37 +241,37 @@ export class RecipesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
|
|
||||||
// end of FIXME
|
// end of FIXME
|
||||||
|
|
||||||
this._recipeService
|
// this._recipeService
|
||||||
.getSavedTmp(
|
// .getSavedTmp(
|
||||||
await this._recipeService.getCurrentCountry(this.department),
|
// await this._recipeService.getCurrentCountry(this.department),
|
||||||
this._recipeService.getCurrentFile()
|
// this._recipeService.getCurrentFile()
|
||||||
)
|
// )
|
||||||
.subscribe({
|
// .subscribe({
|
||||||
next: (files: any) => {
|
// next: (files: any) => {
|
||||||
console.log('Obtain saves: ', typeof files, files);
|
// console.log('Obtain saves: ', typeof files, files);
|
||||||
this.showSaveNoti = false;
|
// this.showSaveNoti = false;
|
||||||
if (files != undefined && typeof files === 'object') {
|
// if (files != undefined && typeof files === 'object') {
|
||||||
if (files.files != null) {
|
// if (files.files != null) {
|
||||||
console.log(
|
// console.log(
|
||||||
'Obtain saves object: ',
|
// 'Obtain saves object: ',
|
||||||
files.files[0],
|
// files.files[0],
|
||||||
typeof files
|
// typeof files
|
||||||
);
|
// );
|
||||||
this.savedTmpfiles = files.files;
|
// this.savedTmpfiles = files.files;
|
||||||
} else {
|
// } else {
|
||||||
this.showSaveNoti = false;
|
// this.showSaveNoti = false;
|
||||||
this.savedTmpfiles = [];
|
// this.savedTmpfiles = [];
|
||||||
console.log(this.showSaveNoti, this.savedTmpfiles);
|
// console.log(this.showSaveNoti, this.savedTmpfiles);
|
||||||
}
|
// }
|
||||||
// let svf = (document.getElementById('select_savefile_modal') as HTMLInputElement)!.checked;
|
// // let svf = (document.getElementById('select_savefile_modal') as HTMLInputElement)!.checked;
|
||||||
// console.log("isSavedModalOpened",svf)
|
// // console.log("isSavedModalOpened",svf)
|
||||||
} else {
|
// } else {
|
||||||
this.showSaveNoti = false;
|
// this.showSaveNoti = false;
|
||||||
this.savedTmpfiles = [];
|
// this.savedTmpfiles = [];
|
||||||
console.log(this.showSaveNoti, this.savedTmpfiles);
|
// console.log(this.showSaveNoti, this.savedTmpfiles);
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
(await this._materialService.getMaterialCodes())
|
(await this._materialService.getMaterialCodes())
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
||||||
|
|
@ -135,3 +135,39 @@ func (r *RedisCli) SetKeyTimeout(key string, value interface{}, timeout int) err
|
||||||
fmt.Println("error on EXPIRE ", err)
|
fmt.Println("error on EXPIRE ", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *RedisCli) KeyList() ([]string, error) {
|
||||||
|
// if cannot pass healthcheck, return err
|
||||||
|
if err := r.HealthCheck(); err != nil {
|
||||||
|
fmt.Println("HS> KEYS error ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := r.Client.Keys(context.Background(), "*")
|
||||||
|
|
||||||
|
return keys.Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// list operations
|
||||||
|
|
||||||
|
func (r *RedisCli) GetList(key string) ([]string, error) {
|
||||||
|
// if cannot pass healthcheck, return err
|
||||||
|
if err := r.HealthCheck(); err != nil {
|
||||||
|
fmt.Println("HS> List.GET error ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Client.LRange(context.Background(), key, 0, -1).Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisCli) Add(key string, value interface{}) error {
|
||||||
|
// if cannot pass healthcheck, return err
|
||||||
|
if err := r.HealthCheck(); err != nil {
|
||||||
|
fmt.Println("HS> List.ADD error ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.Client.RPush(context.Background(), key, value)
|
||||||
|
|
||||||
|
return err.Err()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,8 @@ func (rr *RecipeRouter) Route(r chi.Router) {
|
||||||
|
|
||||||
r.Get("/saved/{country}/{filename_version_only}", rr.getSavedRecipes)
|
r.Get("/saved/{country}/{filename_version_only}", rr.getSavedRecipes)
|
||||||
|
|
||||||
|
r.Get("/patch/get/{country}/{filename}", rr.getSavedAsPatches)
|
||||||
|
|
||||||
r.Get("/departments", func(w http.ResponseWriter, r *http.Request) {
|
r.Get("/departments", func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
|
||||||
|
|
@ -447,6 +449,7 @@ func (rr *RecipeRouter) updateRecipe(w http.ResponseWriter, r *http.Request) {
|
||||||
tempRecipe := models.Recipe01{}
|
tempRecipe := models.Recipe01{}
|
||||||
tempRecipe = tempRecipe.FromMap(changeMap)
|
tempRecipe = tempRecipe.FromMap(changeMap)
|
||||||
rr.data.SetValuesToRecipe(targetRecipe.Recipe01, tempRecipe)
|
rr.data.SetValuesToRecipe(targetRecipe.Recipe01, tempRecipe)
|
||||||
|
|
||||||
rr.taoLogger.Log.Debug("ApplyChange", zap.Any("status", "passed"))
|
rr.taoLogger.Log.Debug("ApplyChange", zap.Any("status", "passed"))
|
||||||
|
|
||||||
// check if changed
|
// check if changed
|
||||||
|
|
@ -462,7 +465,7 @@ func (rr *RecipeRouter) updateRecipe(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// gen hash
|
// gen hash
|
||||||
commit_hash, err := data.HashCommit(8)
|
commit_hash, err := data.HashCommit(8)
|
||||||
rr.cache_db.SetToKey(commit_hash, targetRecipe)
|
// rr.cache_db.SetToKey(commit_hash, targetRecipe)
|
||||||
|
|
||||||
commit := data.CommitLog{
|
commit := data.CommitLog{
|
||||||
|
|
||||||
|
|
@ -474,31 +477,68 @@ func (rr *RecipeRouter) updateRecipe(w http.ResponseWriter, r *http.Request) {
|
||||||
Relation: filename,
|
Relation: filename,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------ SKIP THIS ------------------------
|
||||||
|
// TODO: save only changes.
|
||||||
|
|
||||||
|
// get new tempfile name if redis is connected;
|
||||||
|
|
||||||
|
productCodeNoSpl := strings.ReplaceAll(changes.ProductCode, "-", "")
|
||||||
|
patchName := "Recipe_" + productCodeNoSpl + "-" + commit_hash + "_" + filename + ".patch"
|
||||||
|
|
||||||
|
// if cache service online
|
||||||
|
if rr.cache_db.HealthCheck() == nil {
|
||||||
|
// do change mode
|
||||||
|
commit.Change_file = patchName
|
||||||
|
commit.Relation = commit.Relation + "/patch"
|
||||||
|
|
||||||
|
// add to patch list of that filename
|
||||||
|
// filename:patchlist
|
||||||
|
err := rr.cache_db.Add(countryID+"."+filename+":patchList", commit.Id)
|
||||||
|
|
||||||
|
// add failed
|
||||||
|
if err != nil {
|
||||||
|
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "Error when tried to add to patch list")))
|
||||||
|
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// this following codes do need users to pass update to each other
|
||||||
|
// otherwise, the changes will diverge
|
||||||
|
|
||||||
|
file, _ := os.Create(temp_file_name)
|
||||||
|
if err != nil {
|
||||||
|
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "Error when tried to create file")))
|
||||||
|
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// write to local if cannot connect
|
||||||
|
encoder := json.NewEncoder(file)
|
||||||
|
encoder.SetIndent("", " ")
|
||||||
|
// full
|
||||||
|
err = encoder.Encode(targetRecipe)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
|
||||||
|
// partial
|
||||||
|
// err = encoder.Encode(changes)
|
||||||
|
|
||||||
|
// put changes to redis
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "Error when write file")))
|
||||||
|
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to commit
|
||||||
err = data.Insert(&commit)
|
err = data.Insert(&commit)
|
||||||
|
|
||||||
file, _ := os.Create(temp_file_name)
|
err = rr.cache_db.SetToKey(patchName, changes)
|
||||||
if err != nil {
|
// TODO: ^----- change this to patch
|
||||||
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "Error when tried to create file")))
|
|
||||||
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder := json.NewEncoder(file)
|
|
||||||
encoder.SetIndent("", " ")
|
|
||||||
// full
|
|
||||||
err = encoder.Encode(targetRecipe)
|
|
||||||
|
|
||||||
// partial
|
|
||||||
// err = encoder.Encode(changes)
|
|
||||||
|
|
||||||
// put changes to redis
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "Error when write file")))
|
|
||||||
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = rr.cache_db.SetToKey(commit_hash+"_"+filename, changes)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipeCache", zap.Error(errors.WithMessage(err, "Error when write file")))
|
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipeCache", zap.Error(errors.WithMessage(err, "Error when write file")))
|
||||||
|
|
@ -567,6 +607,64 @@ func (rr *RecipeRouter) getSavedRecipes(w http.ResponseWriter, r *http.Request)
|
||||||
json.NewEncoder(w).Encode(map[string]interface{}{"files": commits})
|
json.NewEncoder(w).Encode(map[string]interface{}{"files": commits})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rr *RecipeRouter) getSavedAsPatches(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
filename := chi.URLParam(r, "filename")
|
||||||
|
country := chi.URLParam(r, "country")
|
||||||
|
|
||||||
|
countryID, err := rr.data.GetCountryIDByName(country)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("Country Name: %s not found!!!", country), http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
patchList, err := rr.cache_db.GetList(countryID + "." + filename + ":patchList")
|
||||||
|
if err != nil {
|
||||||
|
// silent return, no patch
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rr.taoLogger.Log.Debug("RecipeRouter.getSavedAsPatches", zap.Any("targetPatchOf", countryID+"."+filename+":patchList"), zap.Any("patchList", patchList))
|
||||||
|
|
||||||
|
// find patch content from patch list
|
||||||
|
keys, err := rr.cache_db.KeyList()
|
||||||
|
if err != nil {
|
||||||
|
// keys found nothing
|
||||||
|
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop through keys, if contain patch id
|
||||||
|
patchMap := map[string]models.Recipe01{}
|
||||||
|
for _, key := range keys {
|
||||||
|
if strings.Contains(key, filename) && strings.Contains(key, "patch") {
|
||||||
|
|
||||||
|
// check if legit saved file from patchList
|
||||||
|
for _, patchID := range patchList {
|
||||||
|
if strings.Contains(key, patchID) {
|
||||||
|
// get patch content
|
||||||
|
var recipePatch models.Recipe01
|
||||||
|
err := rr.cache_db.GetKeyTo(key, &recipePatch)
|
||||||
|
if err != nil {
|
||||||
|
// silent return, no patch
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// append to patch list
|
||||||
|
// patchContents = append(patchContents, recipePatch)
|
||||||
|
patchMap[patchID] = recipePatch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(patchMap)
|
||||||
|
|
||||||
|
rr.taoLogger.Log.Debug("RecipeRouter.getSavedAsPatches", zap.Any("patchMap", patchMap))
|
||||||
|
}
|
||||||
|
|
||||||
func (rr *RecipeRouter) getToppings(w http.ResponseWriter, r *http.Request) {
|
func (rr *RecipeRouter) getToppings(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
countryID := chi.URLParam(r, "country")
|
countryID := chi.URLParam(r, "country")
|
||||||
|
|
@ -626,7 +724,7 @@ func (rr *RecipeRouter) getRawRecipeOfProductCode(w http.ResponseWriter, r *http
|
||||||
productCode := chi.URLParam(r, "product_code")
|
productCode := chi.URLParam(r, "product_code")
|
||||||
|
|
||||||
// debug
|
// debug
|
||||||
rr.taoLogger.Log.Debug("RecipeRouter.getRawRecipeOfProductCode", zap.Any("countryID", countryID), zap.Any("filename", filename), zap.Any("productCode", productCode))
|
// rr.taoLogger.Log.Debug("RecipeRouter.getRawRecipeOfProductCode", zap.Any("countryID", countryID), zap.Any("filename", filename), zap.Any("productCode", productCode))
|
||||||
|
|
||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
|
||||||
|
|
@ -638,7 +736,7 @@ func (rr *RecipeRouter) getRawRecipeOfProductCode(w http.ResponseWriter, r *http
|
||||||
}
|
}
|
||||||
|
|
||||||
// return recipe
|
// return recipe
|
||||||
rr.taoLogger.Log.Debug("RecipeRouter.getRawRecipeOfProductCode", zap.Any("recipe", recipe))
|
// rr.taoLogger.Log.Debug("RecipeRouter.getRawRecipeOfProductCode", zap.Any("recipe", recipe))
|
||||||
|
|
||||||
json.NewEncoder(w).Encode(recipe)
|
json.NewEncoder(w).Encode(recipe)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue