add deepCompare for merge, WIP merge

This commit is contained in:
pakintada@gmail.com 2024-02-23 16:50:21 +07:00
parent ed7810cded
commit cf5b11b267
6 changed files with 234 additions and 19 deletions

View file

@ -41,11 +41,26 @@
</div>
<!-- File Change Status -->
<button *ngIf="showDetectChanges">
<button onclick="patch_merge_modal.showModal()" *ngIf="showDetectChanges">
<h1 class="text-center font-extrabold text-2xl text-red-500 animate-pulse">Detect Changes! Click</h1>
</button>
<dialog id="patch_merge_modal" class="modal">
<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">
<button class="btn btn-warning">Close</button>
</form>
</div>
</div>
</dialog>
<div class="flex items-center">
<div class="flex items-center ml-3">
@ -168,4 +183,3 @@
</div>
</div>
<!--Modal-->

View file

@ -60,6 +60,7 @@ export class LayoutComponent implements OnInit, OnDestroy {
redisStatus:string = "Offline";
showDetectChanges: boolean = false;
changesCommit: any = undefined;
constructor(
private _userService: UserService,
@ -94,9 +95,11 @@ export class LayoutComponent implements OnInit, OnDestroy {
next: async (data: any) => {
if(data != undefined && typeof data === 'object'){
// check if attr exists
if(data.files != null){
if(data.files != null && data.files != undefined){
this.showDetectChanges = true;
await AsyncStorage.setItem("detectChanges", "true");
this.changesCommit = data.files;
console.log("get commits", this.changesCommit);
} else {
this.showDetectChanges = false;
await AsyncStorage.setItem("detectChanges", "false");

View file

@ -1 +1,40 @@
<p>merge works!</p>
<!-- 3 columns with master at center -->
<div class="grid grid-cols-3">
<!-- from patch -->
<div>
<div class="m-2" *ngFor="let patchKey of getPatchMapKeys()">
<mat-card class="!bg-amber-300 !rounded-xl p-2">
<mat-card-title>
{{getCommitAttr(patchKey, 'Msg')}}
</mat-card-title>
<mat-card-content>
<div>
<p>date: {{getCommitAttr(patchKey, 'Created_at') }}</p>
<p>editor: {{getCommitAttr(patchKey, 'Editor') }}</p>
<p>ref: {{patchKey}}</p>
<p class="hidden">full ref: {{getCommitAttr(patchKey, 'Change_file')}}</p>
<button mat-raised-button class="!bg-white" (click)="copyRef(getCommitAttr(patchKey, 'Change_file'))">Copy full ref</button>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
<!-- from master -->
<div>
<p>master</p>
</div>
<!-- from machine -->
<div>
<p>machine</p>
</div>
</div>

View file

@ -1,31 +1,117 @@
import { Component, OnInit } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RecipeService } from 'src/app/core/services/recipe.service';
import { MatCardModule } from '@angular/material/card';
import { MatButtonModule } from '@angular/material/button';
import { copy } from 'src/app/shared/helpers/copy';
import { compare } from 'src/app/shared/helpers/compare';
import { AsyncStorage } from 'src/app/shared/helpers/asyncStorage';
@Component({
selector: 'app-merge',
standalone: true,
imports: [CommonModule],
imports: [CommonModule, MatCardModule, MatButtonModule],
templateUrl: './merge.component.html',
})
export class MergeComponent implements OnInit {
@Input() commit: Array<any> | undefined = undefined;
patchMap: any = {}
patchMap: any = {};
fullPatches: any = {};
conflictList: string[] = [];
constructor(
private _recipeService: RecipeService
) { }
//map productCode:commits
mapProductCodeWithCommits: any = {};
// master recipes for product code given by commits
targetRecipe: any = {}
// change map
changeMap: any = {};
constructor(private _recipeService: RecipeService) {}
async ngOnInit(): Promise<void> {
(await this._recipeService.getPatchListOfCurrentFile(
await this._recipeService.getCurrentCountry(),
this._recipeService.getCurrentFile()
)).subscribe({
(
await this._recipeService.getPatchListOfCurrentFile(
await this._recipeService.getCurrentCountry(),
this._recipeService.getCurrentFile()
)
).subscribe({
next: (data: any) => {
this.patchMap = data;
console.log("patches",this.patchMap);
}
// console.log("patches",this.patchMap);
// console.log("commits", this.commit!);
this.getPatchMapKeys().forEach(async (key) => {
this.fullPatches[key] = {
contents: this.patchMap[key],
...this.commit!.find((commit: any) => commit.Id === key),
};
// find product code from commits
let productCode = this.patchMap[key].productCode;
if (productCode) {
// check if exist in map
if (!this.mapProductCodeWithCommits[productCode]) {
this.mapProductCodeWithCommits[productCode] = [ key ];
} else {
this.mapProductCodeWithCommits[productCode].push(key);
}
}
// store only
await this.getMasterRecipeOfProductCode(productCode!);
// console.log("get master-commits recipe", this.mapProductCodeWithCommits);
});
console.log('full patch', this.fullPatches);
// console.log('change map', this.changeMap);
},
});
// fetch related product codes
}
// funcitons
// get patch map keys
getPatchMapKeys = () => Object.keys(this.patchMap);
// get commit message by commit id
getCommitAttr = (id: string, attr: string) => this.fullPatches[id][attr];
// copy to clipboard
copyRef = async (ref: string) => await copy(ref);
// ----------------------------- Master Functions ---------------------------
getMasterRecipeOfProductCode = async (productCode: string) => {
(await this._recipeService.getRawRecipeOfProductCode(
await this._recipeService.getCurrentCountry(),
this._recipeService.getCurrentFile(),
productCode
)).subscribe({
next: (data: any) => {
this.targetRecipe[productCode] = data;
// console.log("get master recipe", this.targetRecipe);
// for each patch, get diff master <---> patch
// test compare
this.getPatchMapKeys().forEach((patchId) => {
// compare with master
let cmp = compare(
this.targetRecipe[productCode!],
this.fullPatches[patchId].contents,
['LastChange']
);
// save only what changes
this.changeMap[patchId] = {
changes: cmp
};
});
console.log("change map", this.changeMap);
}
});
};
}

View file

@ -209,7 +209,7 @@ export class RecipeListComponent implements OnInit {
],
stirTime: [
{
value: recipeDetailMat.stirTime / 10,
value: recipeDetailMat.stirTime,
disabled: !this.isEditable(),
},
],
@ -325,7 +325,7 @@ export class RecipeListComponent implements OnInit {
],
stirTime: [
{
value: recipeDetailMat.stirTime / 10,
value: recipeDetailMat.stirTime,
disabled: !this.isEditable(),
},
],
@ -402,7 +402,7 @@ export class RecipeListComponent implements OnInit {
);
// revert stirTime
recipeDetailMat.stirTime = recipeDetailMat.stirTime! * 10;
recipeDetailMat.stirTime = recipeDetailMat.stirTime!;
emitted_res.push(recipeDetailMat);
});
@ -633,7 +633,7 @@ export class RecipeListComponent implements OnInit {
isMixOrder = (index: number) => {
let mixOrder = this.recipeListData.at(index).get('MixOrder')?.value;
console.log("get::MixOrder", mixOrder, "test get::mixOrder", this.recipeListData.at(index).get('mixOrder'));
// console.log("get::MixOrder", mixOrder, "test get::mixOrder", this.recipeListData.at(index).get('mixOrder'));
// retry if not exist
// if (!mixOrder) {
// mixOrder = this.recipeListData.at(index).get('mixOrder')!.value;

View file

@ -0,0 +1,73 @@
export function compare(
base: any,
updated: any,
ignore?: string[],
pathInit = '',
sep = '.'
): any[] {
// recursive loop
let compare_results = [];
// check if array
if (Array.isArray(base) && Array.isArray(updated)) {
for (let i = 0; i < base.length; i++) {
compare_results.push(
...compare(
base[i],
updated[i],
ignore,
pathInit + sep + i.toString(),
sep
)
);
}
} else {
if(updated == null || updated == undefined || base == null || base == undefined){
return [];
}
//
let base_keys = Object.keys(base);
let updated_keys = Object.keys(updated);
for (let key of base_keys) {
if (ignore != undefined && ignore != null) {
if (ignore.includes(key)) {
continue;
}
}
const base_value = base[key];
const updated_value = updated[key];
let isObj =
base_value != undefined &&
base_value != null &&
typeof base_value === 'object' &&
updated_value != undefined &&
updated_value != null &&
typeof updated_value === 'object';
if (isObj) {
compare_results.push(
...compare(
base_value,
updated_value,
ignore,
pathInit + sep + key,
sep
)
);
} else if (base_value != updated_value) {
compare_results.push({
key: pathInit + sep + key,
value: base_value,
change_to: updated_value,
});
}
}
}
return compare_results;
}