Skip to content

Commit

Permalink
feat(multi-row-editor): add a second special ID per row when necessary (
Browse files Browse the repository at this point in the history
  • Loading branch information
Helias authored Sep 11, 2024
1 parent 8a25e90 commit 9062e20
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Injectable } from '@angular/core';
import { CREATURE_ID, CREATURE_TEXT_TABLE, CreatureText, EXTRA_ID, TEXT_ID } from '@keira/shared/acore-world-model';
import { MultiRowEditorService } from '@keira/shared/base-abstract-classes';
import { CREATURE_ID, CREATURE_TEXT_TABLE, CreatureText, TEXT_ID } from '@keira/shared/acore-world-model';
import { CreatureHandlerService } from '../creature-handler.service';

@Injectable({
providedIn: 'root',
})
export class CreatureTextService extends MultiRowEditorService<CreatureText> {
constructor(protected override readonly handlerService: CreatureHandlerService) {
super(CreatureText, CREATURE_TEXT_TABLE, CREATURE_ID, TEXT_ID, handlerService);
super(CreatureText, CREATURE_TEXT_TABLE, CREATURE_ID, TEXT_ID, handlerService, EXTRA_ID);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { TableRow } from '@keira/shared/constants';
export const CREATURE_TEXT_TABLE = 'creature_text';
export const CREATURE_ID = 'CreatureID';
export const TEXT_ID = 'ID';
export const EXTRA_ID = 'GroupID';

export class CreatureText extends TableRow {
CreatureID: number = 0;
Expand Down
22 changes: 18 additions & 4 deletions libs/shared/base-abstract-classes/src/core.mock.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
/* istanbul ignore file */
import { Injectable } from '@angular/core';
import { TableRow } from '@keira/shared/constants';
import { HandlerService } from './service/handlers/handler.service';
import { MysqlQueryService } from '@keira/shared/db-layer';
import { Observable } from 'rxjs';
import { MultiRowComplexKeyEditorService } from './service/editors/multi-row-complex-key-editor.service';
import { MultiRowEditorService } from './service/editors/multi-row-editor.service';
import { MysqlQueryService } from '@keira/shared/db-layer';
import { MultiRowExternalEditorService } from './service/editors/multi-row-external-editor.service';
import { SingleRowComplexKeyEditorService } from './service/editors/single-row-complex-key-editor.service';
import { SingleRowEditorService } from './service/editors/single-row-editor.service';
import { HandlerService } from './service/handlers/handler.service';
import { SelectService } from './service/select/select.service';
import { MultiRowExternalEditorService } from './service/editors/multi-row-external-editor.service';
import { Observable } from 'rxjs';

export const MOCK_TABLE = 'mock_table';
export const MOCK_ID = 'id';
export const MOCK_ID_2 = 'guid';
export const MOCK_NAME = 'name';
export const MOCK_EXTRA_ID = 'extra_id';

export class MockEntity extends TableRow {
id: number = 0;
guid: number = 0;
name: string = '';
}

export class MockEntityExtra extends MockEntity {
extra_id?: any = 0;
}

@Injectable({
providedIn: 'root',
})
Expand Down Expand Up @@ -72,6 +77,15 @@ export class MockMultiRowEditorService extends MultiRowEditorService<MockEntity>
}
}

@Injectable({
providedIn: 'root',
})
export class MockMultiRowEditorExtraService extends MultiRowEditorService<MockEntityExtra> {
constructor(protected override handlerService: MockHandlerService) {
super(MockEntityExtra, MOCK_TABLE, MOCK_ID, MOCK_ID_2, handlerService, MOCK_EXTRA_ID);
}
}

@Injectable({
providedIn: 'root',
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { MysqlQueryService } from '@keira/shared/db-layer';
import { ToastrService } from 'ngx-toastr';
import { instance, mock } from 'ts-mockito';
import { MysqlQueryService } from '@keira/shared/db-layer';

import { MOCK_ID, MOCK_ID_2, MOCK_NAME, MockEntity, MockMultiRowEditorService } from '../../core.mock';
import {
MOCK_EXTRA_ID,
MOCK_ID,
MOCK_ID_2,
MOCK_NAME,
MockEntity,
MockEntityExtra,
MockMultiRowEditorExtraService,
MockMultiRowEditorService,
} from '../../core.mock';

describe('MultiRowEditorService', () => {
const queryResult = '-- Mock query result';
const rowId = 12345;
const extraRowId = 999;

beforeEach(() =>
TestBed.configureTestingModule({
Expand All @@ -20,16 +30,20 @@ describe('MultiRowEditorService', () => {
}),
);

function setup(config: { loadedEntityId?: number; nextRowId?: number; newRows?: MockEntity[] } = {}) {
const service = TestBed.inject(MockMultiRowEditorService);
function setup(
config: { loadedEntityId?: number; nextRowId?: number; newRows?: (MockEntity | MockEntityExtra)[]; extra?: boolean } = {},
) {
const service = config.extra ? TestBed.inject(MockMultiRowEditorExtraService) : TestBed.inject(MockMultiRowEditorService);

const updateDiffQuerySpy = spyOn<any>(service, 'updateDiffQuery');
const updateFullQuerySpy = spyOn<any>(service, 'updateFullQuery');
const formResetSpy = spyOn(service.form, 'reset').and.callThrough();
const formEnableSpy = spyOn(service.form, 'enable').and.callThrough();
const formDisableSpy = spyOn(service.form, 'disable').and.callThrough();

const selected = [{ [service['_entitySecondIdField']]: rowId } as MockEntity];
const selected = [
{ [service['_entitySecondIdField']]: rowId, [service['_entityExtraIdField'] as any]: extraRowId } as unknown as MockEntity,
];

if (config.loadedEntityId) {
service['_loadedEntityId'] = config.loadedEntityId;
Expand Down Expand Up @@ -355,4 +369,53 @@ describe('MultiRowEditorService', () => {
service.refreshDatatable();
expect(oldRows).not.toBe(service['_newRows']);
});

describe('extra row id', () => {
it('isRowSelected() should correctly work', () => {
const { service } = setup({ extra: true });
service['_selectedRowId'] = `${rowId}_${extraRowId}`;

expect(service.isRowSelected({ [MOCK_ID]: 1, [MOCK_ID_2]: rowId, [MOCK_NAME]: '', [MOCK_EXTRA_ID]: extraRowId })).toBe(true);
expect(service.isRowSelected({ [MOCK_ID]: 1, [MOCK_ID_2]: rowId, [MOCK_NAME]: '', [MOCK_EXTRA_ID]: 11111 })).toBe(false);
});

it('onRowSelection() should do nothing if the same row is already selected', () => {
const { service, formEnableSpy, formResetSpy, selected } = setup({ extra: true });
service['_selectedRowId'] = `${rowId}_${extraRowId}`;

service.onRowSelection({ selected });

expect(formResetSpy).toHaveBeenCalledTimes(0);
expect(formEnableSpy).toHaveBeenCalledTimes(0);
});

it('isFormIdUnique should return true when the form has a unique id', () => {
const newRows = [
{ [MOCK_ID]: 123, [MOCK_ID_2]: 1, [MOCK_NAME]: '', [MOCK_EXTRA_ID]: 1 },
{ [MOCK_ID]: 123, [MOCK_ID_2]: 2, [MOCK_NAME]: '', [MOCK_EXTRA_ID]: 2 },
{ [MOCK_ID]: 123, [MOCK_ID_2]: 3, [MOCK_NAME]: '', [MOCK_EXTRA_ID]: 3 },
];
const { service } = setup({ newRows, extra: true });

service.form.controls[MOCK_ID_2].setValue(4);
service.form?.controls[MOCK_EXTRA_ID]?.setValue(4);

expect(service.isFormIdUnique()).toBe(true);
});

it('getRowIndex(id) should correctly return the index', () => {
const newRows = [
{ [MOCK_ID]: 123, [MOCK_ID_2]: 3, [MOCK_NAME]: 'test', [MOCK_EXTRA_ID]: 1 },
{ [MOCK_ID]: 123, [MOCK_ID_2]: 5, [MOCK_NAME]: 'test', [MOCK_EXTRA_ID]: 2 },
{ [MOCK_ID]: 123, [MOCK_ID_2]: 9, [MOCK_NAME]: 'test', [MOCK_EXTRA_ID]: 3 },
];
const { service } = setup({ newRows, extra: true });

expect(service['getRowIndex']('3_1')).toEqual(0);
expect(service['getRowIndex']('5_2')).toEqual(1);
expect(service['getRowIndex']('9_3')).toEqual(2);

expect(service['getRowIndex']('3_9')).toEqual(0);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { FormGroup } from '@angular/forms';
import { Class, TableRow } from '@keira/shared/constants';
import { compareObjFn, ModelForm } from '@keira/shared/utils';
import { distinctUntilChanged } from 'rxjs';
import { HandlerService } from '../handlers/handler.service';
import { EditorService } from './editor.service';
import { compareObjFn } from '@keira/shared/utils';

export abstract class MultiRowEditorService<T extends TableRow> extends EditorService<T> {
protected FIRST_ROW_START_VALUE = 0;
Expand Down Expand Up @@ -37,19 +38,26 @@ export abstract class MultiRowEditorService<T extends TableRow> extends EditorSe
protected override readonly _entityIdField: string | undefined,
protected readonly _entitySecondIdField: string,
protected override readonly handlerService: HandlerService<T>,
protected readonly _entityExtraIdField: string | undefined = undefined,
) {
super(_entityClass, _entityTable, _entityIdField, handlerService);
this.initForm();
}

private getRowIndex(id: string | number): number {
for (let i = 0; i < this._newRows.length; i++) {
if (id === this._newRows[i][this._entitySecondIdField]) {
if (id === this.getNewRowId(this._newRows[i])) {
return i;
}
}

console.error(`getRowIndex() failed in finding row having ${this._entitySecondIdField} ${id}`);
if (this._entityExtraIdField) {
const [entitySecondIdField, extraIdField] = `${id}`.split('_');
console.error(`getRowIndex() failed in finding row having ${this._entitySecondIdField} ${entitySecondIdField} and ${extraIdField}`);
} else {
console.error(`getRowIndex() failed in finding row having ${this._entitySecondIdField} ${id}`);
}

return 0;
}

Expand All @@ -70,7 +78,7 @@ export abstract class MultiRowEditorService<T extends TableRow> extends EditorSe
if (this._form.dirty && this.isFormIdUnique()) {
this._newRows[this.getSelectedRowIndex()] = this._form.getRawValue() as T;
this._newRows = [...this._newRows];
this._selectedRowId = this.form.controls[this._entitySecondIdField].value;
this._selectedRowId = this.getNewRowIdForm(this._form.controls);
this.checkRowsCorrectness();
this.updateDiffQuery();
this.updateFullQuery();
Expand Down Expand Up @@ -136,7 +144,7 @@ export abstract class MultiRowEditorService<T extends TableRow> extends EditorSe
}

onRowSelection({ selected }: { selected: T[] }): void {
const newId = selected[0][this._entitySecondIdField];
const newId = this.getNewRowId(selected[0]);

if (newId === this._selectedRowId) {
return;
Expand Down Expand Up @@ -171,7 +179,7 @@ export abstract class MultiRowEditorService<T extends TableRow> extends EditorSe
protected onRowSelected(): void {}

isRowSelected(row: T): boolean {
return row[this._entitySecondIdField] === this._selectedRowId;
return this.getNewRowId(row) === this._selectedRowId;
}

deleteSelectedRow(): void {
Expand All @@ -194,6 +202,22 @@ export abstract class MultiRowEditorService<T extends TableRow> extends EditorSe
newRow[this._entityIdField as keyof T] = Number.parseInt(this.loadedEntityId, 10) as T[keyof T];
}

private getNewRowId(row: T): string | number {
if (this._entityExtraIdField) {
return `${row[this._entitySecondIdField]}_${row[this._entityExtraIdField]}`;
}

return row[this._entitySecondIdField];
}

private getNewRowIdForm(rowControls: FormGroup<ModelForm<T>>['controls']): string | number {
if (this._entityExtraIdField) {
return `${rowControls[this._entitySecondIdField].value}_${rowControls[this._entityExtraIdField].value}`;
}

return rowControls[this._entitySecondIdField].value;
}

addNewRow(copySelectedRow = false): void {
const newRow: T = copySelectedRow && this.hasSelectedRow() ? { ...this.getSelectedRow() } : new this._entityClass();
if (this._entityIdField) {
Expand All @@ -210,10 +234,7 @@ export abstract class MultiRowEditorService<T extends TableRow> extends EditorSe

isFormIdUnique(): boolean {
for (const row of this._newRows) {
if (
row[this._entitySecondIdField] !== this._selectedRowId &&
row[this._entitySecondIdField] === this._form.controls[this._entitySecondIdField].value
) {
if (this.getNewRowId(row) !== this._selectedRowId && this.getNewRowId(row) === this.getNewRowIdForm(this._form.controls)) {
return false;
}
}
Expand Down
10 changes: 5 additions & 5 deletions libs/shared/switch-language/src/switch-language.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { inject, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Injectable({
Expand All @@ -7,10 +7,10 @@ import { TranslateService } from '@ngx-translate/core';
export class SwitchLanguageService {
currentLanguage = 'en';

constructor(private readonly translateService: TranslateService) {}
private readonly translateService: TranslateService = inject(TranslateService);

setLanguage(event: any): void {
this.currentLanguage = event.target.value;
this.translateService.setDefaultLang(event.target.value);
setLanguage(event: Event): void {
this.currentLanguage = (event.target as HTMLSelectElement).value;
this.translateService.setDefaultLang((event.target as HTMLSelectElement).value);
}
}

0 comments on commit 9062e20

Please sign in to comment.