Skip to content

Commit

Permalink
Merge branch 'main' into options-options-columns
Browse files Browse the repository at this point in the history
  • Loading branch information
fdewas-aneo authored Jan 4, 2024
2 parents 6aa9701 + 05f4d4d commit 981fb6c
Show file tree
Hide file tree
Showing 12 changed files with 245 additions and 13 deletions.
17 changes: 16 additions & 1 deletion src/app/components/filters/filters-chips.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ describe('FiltersChipsComponent', () => {
field: 5,
type: 'unknownType',
for: 'root'
} as unknown as FilterDefinition<number, number>)
} as unknown as FilterDefinition<number, number>),
{
field: 1,
type: 'duration',
for: 'options'
}
];

beforeEach(async () => {
Expand Down Expand Up @@ -150,4 +155,14 @@ describe('FiltersChipsComponent', () => {

expect(component.trackByFilter(0, filter)).toEqual('');
});

it('should show a duration appropriately', () => {
const filter: Filter<number, number> = {
field: 1,
for: 'options',
operator: 1,
value: 94350
};
expect(component.content(filter)).toEqual('other Not Equal 26h 12m 30s');
});
});
20 changes: 20 additions & 0 deletions src/app/components/filters/filters-chips.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,30 @@ export class FiltersChipsComponent<T extends number, U extends number | null = n
else if (type === 'date') {
return `${label} ${operator} ${new Date(Number(filter.value) * 1000).toUTCString()}`;
}
else if (type === 'duration') {
return `${label} ${operator} ${this.durationToString(Number(filter.value))}`;
}

return `${label} ${operator} ${filter.value}`;
}

durationToString(value: number): string {
let resultString = '';
const hours = Math.floor(Number(value)/3600);
const minutes = Math.floor((Number(value)%3600)/60);
const seconds = Math.floor(((Number(value))%3600)%60);
if (hours > 0) {
resultString += `${hours}h `;
}
if (minutes > 0) {
resultString += `${minutes}m `;
}
if (seconds > 0) {
resultString += `${seconds}s`;
}
return resultString;
}

trackByFilter(_: number, filter: Filter<T, U>): string {
return filter.field?.toString() ?? '';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,17 @@ describe('FiltersDialogFilterFieldComponent', () => {
field: 5,
type: 'unknownType',
for: 'root'
} as unknown as FilterDefinition<number, number>)
} as unknown as FilterDefinition<number, number>),
{
field: 6,
type: 'duration',
for: 'options'
},
{
field: 7,
type: 'date',
for: 'root'
}
];

beforeEach(async () => {
Expand Down Expand Up @@ -132,6 +142,24 @@ describe('FiltersDialogFilterFieldComponent', () => {
component.onInputChange(inputEvent);
expect(component.filter.value).toBeNull();
});

it('should change the filter value to date if one is passed', () => {
const inputEvent = {
type: 'date',
value: 95603
} as unknown as FilterInputOutput;
component.onInputChange(inputEvent);
expect(component.filter.value).toEqual(95603);
});

it('should change the filter value to a duration if one is passed', () => {
const inputEvent = {
type: 'duration',
value: 94350
} as unknown as FilterInputOutput;
component.onInputChange(inputEvent);
expect(component.filter.value).toEqual(94350);
});
});

describe('findInput', () => {
Expand Down Expand Up @@ -274,6 +302,62 @@ describe('FiltersDialogFilterFieldComponent', () => {
'Unknown type unknownType'
);
});

describe('input filter of type date', () => {
it('should return a date', () => {
const dateFilter: Filter<number, number> = {
for: 'root',
field: 7,
operator: 1,
value: 1703085190
};
expect(component.findInput(dateFilter)).toEqual({
type: 'date',
value: new Date(1703085190000)
});
});

it('should return null if there is no date', () => {
const dateFilter: Filter<number, number> = {
for: 'root',
field: 7,
operator: 1,
value: null
};
expect(component.findInput(dateFilter)).toEqual({
type: 'date',
value: null
});
});
});

describe('input filter of type duration', () => {
it('should return a filterinput with a duration in seconds', () => {
const durationFilter: Filter<number, number> = {
field: 6,
for: 'options',
operator: 1,
value: 94350
};
expect(component.findInput(durationFilter)).toEqual({
type: 'duration',
value: 94350
});
});
});

it('should return a null filterInput if the duration is not existing', () => {
const durationFilter: Filter<number, number> = {
field: 6,
for: 'options',
operator: 1,
value: null
};
expect(component.findInput(durationFilter)).toEqual({
type: 'duration',
value: null
});
});
});

describe('findType', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
import { DATA_FILTERS_SERVICE } from '@app/tokens/filters.token';
import { FilterDefinition, FilterFor } from '@app/types/filter-definition';
import { Filter, FilterInput, FilterInputOutput, FilterInputType, FilterInputValueString, FilterValueOptions } from '@app/types/filters';
import { Filter, FilterInput, FilterInputOutput, FilterInputType, FilterInputValueDuration, FilterInputValueString, FilterValueOptions } from '@app/types/filters';
import { FiltersService } from '@services/filters.service';
import { FiltersDialogInputComponent } from './filters-dialog-input.component';

Expand Down Expand Up @@ -97,6 +97,8 @@ export class FiltersDialogFilterFieldComponent<T extends number, U extends numbe
case 'date':
this.filter.value = event.value;
break;
case 'duration':
this.filter.value = Number(event.value) || null;
}
}

Expand Down Expand Up @@ -132,6 +134,11 @@ export class FiltersDialogFilterFieldComponent<T extends number, U extends numbe
type: 'date',
value: filter.value ? new Date(Number(filter.value) * 1000) : null
};
case 'duration':
return {
type: 'duration',
value: filter.value as FilterInputValueDuration
};
default:
throw new Error(`Unknown type ${type}`);
}
Expand Down
30 changes: 30 additions & 0 deletions src/app/components/filters/filters-dialog-input.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,34 @@ describe('FiltersDialogInputComponent', () => {
};
expect(component.trackBySelect(0, item)).toBe(item.value);
});

it('should emit a duration in second', () => {
const inputEvent = {
target: {
value: '35'
}
} as unknown as Event;
component.onDurationChange(inputEvent, 0);
expect(valueChangeSpy).toHaveBeenCalledWith({type: 'duration', value: 126000});
(inputEvent.target as HTMLInputElement).value = '39';
component.onDurationChange(inputEvent, 1);
expect(valueChangeSpy).toHaveBeenLastCalledWith({type: 'duration', value: 128340});
component.onDurationChange(inputEvent, 2);
expect(valueChangeSpy).toHaveBeenLastCalledWith({type: 'duration', value: 128379});
});

describe('getDurationInputValue', () => {
beforeEach(() => {
component.input.value = 94350;
});
it('should get the hours from a duration in seconds', () => {
expect(component.getDurationInputValue('hours')).toEqual(26);
});
it('should get the minutes from a duration in seconds', () => {
expect(component.getDurationInputValue('minutes')).toEqual(12);
});
it('should get the seconds from a duration in seconds', () => {
expect(component.getDurationInputValue('seconds')).toEqual(30);
});
});
});
35 changes: 35 additions & 0 deletions src/app/components/filters/filters-dialog-input.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ import { FilterInput, FilterInputOutput, FilterInputType } from '@app/types/filt
<mat-option *ngFor="let option of input.statuses; trackBy: trackBySelect" [value]="option.key">{{ option.value }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field style="" id="durationForm" appearance="outline" subscriptSizing="dynamic" *ngIf="input.type === 'duration'">
<input matInput style="width: 25%; margin-right: 5px;" type="number" min="0" [value]="getDurationInputValue('hours')" (change)="onDurationChange($event, 0)" placeholder="hh">:
<input matInput style="width: 30%; margin-right: 5px;" type="number" min="0" [value]="getDurationInputValue('minutes')" (change)="onDurationChange($event, 1)" placeholder="mm">:
<input matInput style="width: 25%;" type="number" min="0" [value]="getDurationInputValue('seconds')" (change)="onDurationChange($event, 2)" placeholder="ss">
</mat-form-field>
`,
styles: [`
mat-form-field {
Expand All @@ -67,6 +73,7 @@ export class FiltersDialogInputComponent {
// Créer des types en fonction du type de champ
@Output() valueChange: EventEmitter<FilterInputOutput> = new EventEmitter<FilterInputOutput>();
actualDate = new Date();
duration: {[key: number]: string} = {};

onStringChange(event: Event): void {
this.valueChange.emit({
Expand Down Expand Up @@ -98,6 +105,21 @@ export class FiltersDialogInputComponent {
});
}

onDurationChange(event: Event, index: number) {
this.duration[index] = (event.target as HTMLInputElement).value;
const getHours = !isNaN(Number(this.duration[0])) ? Number(this.duration[0]) : this.getDurationInputValue('hours');
const getMinutes = !isNaN(Number(this.duration[1])) ? Number(this.duration[1]) : this.getDurationInputValue('minutes');
const getSeconds = !isNaN(Number(this.duration[2])) ? Number(this.duration[2]) : this.getDurationInputValue('seconds');

const durationSeconds = (getHours ?? 0) * 3600
+ (getMinutes ?? 0) * 60
+ (getSeconds ?? 0);
this.valueChange.emit({
type: 'duration',
value: durationSeconds
});
}

getInputType(): FilterInputType {
switch (this.input.type) {
case 'string':
Expand All @@ -115,6 +137,19 @@ export class FiltersDialogInputComponent {
}
}

getDurationInputValue(searchItem: string): number | undefined {
switch (searchItem) {
case 'hours':
return !isNaN(Number(this.input.value)) ? Math.floor(Number(this.input.value)/3600) : undefined;
case 'minutes':
return !isNaN(Number(this.input.value)) ? Math.floor((Number(this.input.value)%3600)/60) : undefined;
case 'seconds':
return !isNaN(Number(this.input.value)) ? Math.floor(((Number(this.input.value))%3600)%60) : undefined;
default:
return undefined;
}
}

trackBySelect(_: number, item: { value: string }): string {
return item.value;
}
Expand Down
11 changes: 10 additions & 1 deletion src/app/services/filter.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FilterArrayOperator, FilterBooleanOperator, FilterDateOperator, FilterNumberOperator, FilterStatusOperator, FilterStringOperator } from '@aneoconsultingfr/armonik.api.angular';
import { FilterArrayOperator, FilterBooleanOperator, FilterDateOperator, FilterDurationOperator, FilterNumberOperator, FilterStatusOperator, FilterStringOperator } from '@aneoconsultingfr/armonik.api.angular';
import { FiltersService } from './filters.service';

describe('FiltersService', () => {
Expand Down Expand Up @@ -28,6 +28,10 @@ describe('FiltersService', () => {
it('should return the filterBooleanOperators when "boolean" is provided', () => {
expect(service.findOperators('boolean')).toBe(service.filterBooleanOperators);
});

it('should return the filterDurationOperators when "duration" is provided', () => {
expect(service.findOperators('duration')).toBe(service.filterDurationOperators);
});
});

describe('createQueryParamsKey', () => {
Expand Down Expand Up @@ -70,5 +74,10 @@ describe('FiltersService', () => {
expect(service.createQueryParamsKey(1, 'my_string', FilterBooleanOperator.FILTER_BOOLEAN_OPERATOR_IS, 1))
.toEqual('1-my_string-1-0');
});

it('should return the correct string if a duration filter operator is provied', () => {
expect(service.createQueryParamsKey(1, 'my_string', FilterDurationOperator.FILTER_DURATION_OPERATOR_EQUAL, 7))
.toEqual('1-my_string-7-0');
});
});
});
12 changes: 11 additions & 1 deletion src/app/services/filters.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FilterArrayOperator, FilterBooleanOperator, FilterDateOperator, FilterNumberOperator, FilterStatusOperator, FilterStringOperator } from '@aneoconsultingfr/armonik.api.angular';
import { FilterArrayOperator, FilterBooleanOperator, FilterDateOperator, FilterDurationOperator, FilterNumberOperator, FilterStatusOperator, FilterStringOperator } from '@aneoconsultingfr/armonik.api.angular';
import { Injectable } from '@angular/core';
import { FilterOperators, FilterType } from '@app/types/filters';

Expand Down Expand Up @@ -45,13 +45,23 @@ export class FiltersService {
[FilterStatusOperator.FILTER_STATUS_OPERATOR_NOT_EQUAL]: $localize`Not Equal`,
};

readonly filterDurationOperators: Record<FilterDurationOperator, string> = {
[FilterDurationOperator.FILTER_DURATION_OPERATOR_EQUAL]: $localize`Equal`,
[FilterDurationOperator.FILTER_DURATION_OPERATOR_NOT_EQUAL]: $localize`Not Equal`,
[FilterDurationOperator.FILTER_DURATION_OPERATOR_SHORTER_THAN]: $localize`Shorter Than`,
[FilterDurationOperator.FILTER_DURATION_OPERATOR_SHORTER_THAN_OR_EQUAL]: $localize`Shorter or Equal`,
[FilterDurationOperator.FILTER_DURATION_OPERATOR_LONGER_THAN]: $localize`Longer Than`,
[FilterDurationOperator.FILTER_DURATION_OPERATOR_LONGER_THAN_OR_EQUAL]: $localize`Longer or Equal`
};

readonly filterOperators: Record<FilterType, Record<number, string>> = {
'string': this.filterStringOperators,
'number': this.filterNumberOperators,
'date': this.filterDateOperators,
'array': this.filterArrayOperators,
'status': this.filterStatusOperators,
'boolean': this.filterBooleanOperators,
'duration': this.filterDurationOperators,
};

findOperators(type: FilterType) {
Expand Down
2 changes: 1 addition & 1 deletion src/app/tasks/services/tasks-filters.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export class TasksFiltersService {
for: 'options',
field: TaskOptionEnumField.TASK_OPTION_ENUM_FIELD_MAX_RETRIES,
type: 'number'
},
}
];

readonly #defaultFilters: TaskSummaryFiltersOr = this.#defaultConfigService.defaultTasks.filters;
Expand Down
6 changes: 5 additions & 1 deletion src/app/tasks/services/tasks-index.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@ export class TasksIndexService {
}

isNotSortableColumn(column: TaskSummaryColumnKey): boolean {
return this.isActionsColumn(column) || this.isObjectColumn(column) || this.isSelectColumn(column);
return this.isActionsColumn(column) || this.isObjectColumn(column) || this.isSelectColumn(column) || this.isSpecifiedNotSortableColumn(column);
}

isSpecifiedNotSortableColumn(column: TaskSummaryColumnKey): boolean {
return column === 'countDataDependencies' || column === 'countParentTaskIds' || column === 'countExpectedOutputIds' || column === 'countRetryOfIds' || column === 'statusMessage';
}

isGenericColumn(column: TaskSummaryColumnKey): boolean {
Expand Down
8 changes: 7 additions & 1 deletion src/app/types/filter-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,16 @@ type FilterDefinitionTaskOptionNumber<T extends number | null> = {
type: 'number';
};

type FilterDefinitionTaskOptionDuration<T extends number | null> = {
for: 'options';
field: T;
type: 'duration'
};


type FilterDefinitionRoot<T extends number> = FilterDefinitionRootString<T> | FilterDefinitionRootNumber<T> | FilterDefinitionRootArray<T> | FilterDefinitionRootStatus<T> | FilterDefinitionRootDate<T>;

export type FilterDefinitionTaskOption<T extends number | null> = FilterDefinitionTaskOptionString<T> | FilterDefinitionTaskOptionNumber<T>;
export type FilterDefinitionTaskOption<T extends number | null> = FilterDefinitionTaskOptionString<T> | FilterDefinitionTaskOptionNumber<T> | FilterDefinitionTaskOptionDuration<T>;

export type FilterDefinition<T extends number, U extends number | null = null> = FilterDefinitionRoot<T> | FilterDefinitionTaskOption<U>;

Expand Down
Loading

0 comments on commit 981fb6c

Please sign in to comment.