Skip to content

Commit

Permalink
Add a filter by state in feed filter screen (#5817)
Browse files Browse the repository at this point in the history
Signed-off-by: Giovanni Ferrari <giovanni.ferrari@soft.it>
  • Loading branch information
quinarygio authored and vlo-rte committed Feb 6, 2024
1 parent 9341443 commit f059d8b
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 22 deletions.
2 changes: 2 additions & 0 deletions config/docker/ui-config/web-ui.json
Expand Up @@ -54,6 +54,8 @@
"display": "BUSINESS"
},
"hideResponseFilter": false,
"hideProcessFilter": false,
"hideStateFilter": false,
"hideApplyFiltersToTimeLineChoice": false,
"secondsBeforeLttdForClockDisplay": 3700,
"hideAckAllCardsFeature": false,
Expand Down
Expand Up @@ -80,6 +80,7 @@ For example adding `Keycloak` application, with `'Keycloak'` as `name`, `1` as `
|feed.card.hideApplyFiltersToTimeLineChoice|false|no|Control if you want to show or hide the option of applying filters or not to timeline in the feed page
|feed.card.hideResponseFilter|false|no|Control if you want to show or hide the response filter in the feed page
|feed.card.hideProcessFilter|false|no|Control if you want to show or hide the process filter in the feed page
|feed.card.hideStateFilter|false|no|Control if you want to show or hide the state filter in the feed page
|feed.card.maxNbOfCardsToDisplay|100|no| Max number of card visible in feed (This limit is used for performance reasons, setting the value too high can have consequences on browser response times)
|feed.card.secondsBeforeLttdForClockDisplay|180|no| Number of seconds before lttd when a clock is activated in cards on the feed
|feed.card.time.display|BUSINESS|no
Expand Down
7 changes: 4 additions & 3 deletions src/docs/asciidoc/resources/migration_guide_to_4.2.adoc
Expand Up @@ -96,6 +96,7 @@ migration documentation to opfab 4.0 to know which functions you have to use.
The card field `keepChildCards` is now deprecated, use the new `actions` field (string array) including "KEEP_CHILD_CARDS" action instead.


== Feed process filter
A new filter has been added to feed filters to allow filtering by card process.
It is possible to hide the process filter by setting `feed.card.hideProcessFilter` to `true` in `web-ui.json` config file
== Feed process and state filter
New filters have been added to feed filters to allow filtering by card process and state.
It is possible to hide the process filter by setting `feed.card.hideProcessFilter` to `true` in `web-ui.json` config file. When process filter is hidden than also state filter is hidden.
It is possible to hide just the the state filter by setting `feed.card.hideStateFilter` to `true` in `web-ui.json` config file
Expand Up @@ -12,6 +12,7 @@ import {TranslateService} from '@ngx-translate/core';
import {ProcessesService} from 'app/business/services/businessconfig/processes.service';
import {UserService} from 'app/business/services/users/user.service';
import {MultiSelectOption} from '@ofModel/multiselect.model';
import {Process} from '@ofModel/processes.model';

/** This class contains functions to get the list of process and states for filters in UI */

Expand All @@ -28,25 +29,38 @@ export class ProcessStatesMultiSelectOptionsService {
const statesMultiSelectOptionsPerProcess: Array<MultiSelectOption> = [];
ProcessesService.getAllProcesses().forEach((process) => {
const stateOptions = new MultiSelectOption(process.id, process.name);
stateOptions.options = [];
process.states.forEach((state, stateid) => {
if (
this.doesStateHaveToBeDisplayedInFilters(
hideChildStates,
state.isOnlyAChildState,
process.id,
stateid,
isAdminModeAndUserHasRightToSeeAllStates
)
) {
stateOptions.options.push(new MultiSelectOption(process.id + '.' + stateid, state.name));
}
});
stateOptions.options = this.getStatesMultiSelectOptionsPerSingleProcess(
process,
isAdminModeAndUserHasRightToSeeAllStates,
hideChildStates
);
if (stateOptions.options.length > 0) statesMultiSelectOptionsPerProcess.push(stateOptions);
});
return statesMultiSelectOptionsPerProcess;
}

getStatesMultiSelectOptionsPerSingleProcess(
process: Process,
isAdminModeAndUserHasRightToSeeAllStates: boolean,
hideChildStates: boolean
): any[] {
const stateOptions: Array<MultiSelectOption> = [];
process.states.forEach((state, stateid) => {
if (
this.doesStateHaveToBeDisplayedInFilters(
hideChildStates,
state.isOnlyAChildState,
process.id,
stateid,
isAdminModeAndUserHasRightToSeeAllStates
)
) {
stateOptions.push(new MultiSelectOption(process.id + '.' + stateid, state.name));
}
});
return stateOptions;
}

private doesStateHaveToBeDisplayedInFilters(
hideChildStates: boolean,
isOnlyAChildState: boolean,
Expand Down
Expand Up @@ -25,6 +25,7 @@ describe('NewFilterService ', () => {
cards = cards.concat(
getSeveralLightCards(1, {
process: 'process1',
state: 'first',
startDate: new Date().valueOf(),
endDate: null,
publishDate: new Date().valueOf(),
Expand All @@ -37,6 +38,7 @@ describe('NewFilterService ', () => {
cards = cards.concat(
getSeveralLightCards(1, {
process: 'process1',
state: 'second',
startDate: new Date().valueOf(),
endDate: new Date().valueOf() + ONE_HOUR,
publishDate: new Date().valueOf() - ONE_HOUR,
Expand All @@ -49,6 +51,7 @@ describe('NewFilterService ', () => {
cards = cards.concat(
getSeveralLightCards(1, {
process: 'process2',
state: 'state2',
startDate: new Date().valueOf(),
endDate: new Date().valueOf() + 2 * ONE_HOUR,
publishDate: new Date().valueOf() - ONE_HOUR * 2,
Expand All @@ -60,6 +63,7 @@ describe('NewFilterService ', () => {
cards = cards.concat(
getSeveralLightCards(1, {
process: 'process3',
state: 'state3',
startDate: new Date().valueOf(),
endDate: new Date().valueOf() + 3 * ONE_HOUR,
publishDate: new Date().valueOf() - ONE_HOUR * 3,
Expand Down Expand Up @@ -349,5 +353,30 @@ describe('NewFilterService ', () => {
const filteredCards = service.filterLightCards(cards);
expect(filteredCards.length).toBe(4);
});

it('filter 4 cards by process and state => shall return the cards with selected process and state only', () => {
const cards = getFourCards();
service.updateFilter(FilterType.ACKNOWLEDGEMENT_FILTER, false, false);
service.updateFilter(FilterType.PROCESS_FILTER, true, {
process: 'process1',
state: 'process1.second'
});
const filteredCards = service.filterLightCards(cards);
expect(filteredCards.length).toBe(1);
expect(filteredCards).toContain(cards[1]);
});

it('filter 4 cards by process and empty state => shall return the cards with selected process', () => {
const cards = getFourCards();
service.updateFilter(FilterType.ACKNOWLEDGEMENT_FILTER, false, false);
service.updateFilter(FilterType.PROCESS_FILTER, true, {
process: 'process1',
state: ''
});
const filteredCards = service.filterLightCards(cards);
expect(filteredCards.length).toBe(2);
expect(filteredCards).toContain(cards[0]);
expect(filteredCards).toContain(cards[1]);
});
});
});
Expand Up @@ -185,7 +185,9 @@ export class LightCardsFilter {
private initProcessFilter(): Filter {
return new Filter(
(card: LightCard, status) => {
if (status.process) {
if (status.process && status.state) {
return status.process === card.process && status.state === card.process + '.' + card.state;
} else if (status.process) {
return status.process === card.process;
}
return true;
Expand Down
Expand Up @@ -16,7 +16,7 @@
<div id="opfab-card-list-container" style="display: flex;">
<div id="opfab-filters" [class.opfab-filters-hidden]="!filterOpen" class="opfab-filters opfab-card-list" style="width:600px">
<of-feed-filter (filterActiveChange)="onFilterActiveChange($event)" [hideTimerTags]="hideTimerTags"
[hideProcessFilter]="hideProcessFilter"
[hideProcessFilter]="hideProcessFilter" [hideStateFilter]="hideStateFilter"
[defaultAcknowledgmentFilter]="defaultAcknowledgmentFilter" [hideResponseFilter]="hideResponseFilter"
[hideApplyFiltersToTimeLineChoice]="hideApplyFiltersToTimeLineChoice" [defaultSorting]="defaultSorting"></of-feed-filter>
</div>
Expand Down
Expand Up @@ -48,6 +48,7 @@ export class CardListComponent implements AfterViewChecked, OnInit {
hideResponseFilter: boolean;
hideTimerTags: boolean;
hideProcessFilter: boolean;
hideStateFilter: boolean;
hideApplyFiltersToTimeLineChoice: boolean;
defaultSorting: string;
defaultAcknowledgmentFilter: string;
Expand Down Expand Up @@ -81,6 +82,7 @@ export class CardListComponent implements AfterViewChecked, OnInit {
this.hideTimerTags = ConfigService.getConfigValue('feed.card.hideTimeFilter', false);
this.hideResponseFilter = ConfigService.getConfigValue('feed.card.hideResponseFilter', false);
this.hideProcessFilter = ConfigService.getConfigValue('feed.card.hideProcessFilter', false);
this.hideStateFilter = ConfigService.getConfigValue('feed.card.hideStateFilter', false);
this.hideApplyFiltersToTimeLineChoice = ConfigService.getConfigValue(
'feed.card.hideApplyFiltersToTimeLineChoice',
false
Expand Down
Expand Up @@ -78,7 +78,15 @@
</of-multi-select>
</div>
</div>
<div *ngIf="!hideProcessFilter && stateMultiSelect?.options?.length > 0" style="margin-left:2px; margin-top:20px; width:280px">
<div class="form-group" id="opfab-state">

<of-multi-select id="opfab-state-select" [multiSelectId]="stateMultiSelect.id" [parentForm]="processFilterForm"
[config]="stateMultiSelect.config" [options]="stateMultiSelect.options"
[selectedOptions]="stateMultiSelect.selectedOptions">
</of-multi-select>
</div>
</div>
</form>

</div>
Expand Down
Expand Up @@ -24,6 +24,7 @@ import {OpfabStore} from 'app/business/store/opfabStore';
import {MultiSelect, MultiSelectOption} from '@ofModel/multiselect.model';
import {ProcessesService} from 'app/business/services/businessconfig/processes.service';
import {UserService} from 'app/business/services/users/user.service';
import {ProcessStatesMultiSelectOptionsService} from 'app/business/services/process-states-multi-select-options.service';

@Component({
selector: 'of-feed-filter',
Expand All @@ -36,6 +37,7 @@ export class FeedFilterComponent implements OnInit, OnDestroy {
@Input() defaultAcknowledgmentFilter: string;
@Input() hideResponseFilter: boolean;
@Input() hideProcessFilter: boolean;
@Input() hideStateFilter: boolean;

@Input() defaultSorting: string;

Expand Down Expand Up @@ -69,18 +71,21 @@ export class FeedFilterComponent implements OnInit, OnDestroy {

processFilterForm: FormGroup<{
process: FormControl<string | null>;
state: FormControl<string | null>;
}>;

endMinDate: {year: number; month: number; day: number} = null;
startMaxDate: {year: number; month: number; day: number} = null;

processMultiSelect: MultiSelect;
processList = [];
selectedProcess: string;
stateMultiSelect: MultiSelect;

private dateFilterType = FilterType.PUBLISHDATE_FILTER;
private filteredLightCardStore: FilteredLightCardsStore;

constructor() {
constructor(private processStatesDropdownListService: ProcessStatesMultiSelectOptionsService) {
this.filteredLightCardStore = OpfabStore.getFilteredLightCardStore();
this.typeFilterForm = this.createFormGroup();
this.ackFilterForm = this.createAckFormGroup();
Expand Down Expand Up @@ -140,7 +145,8 @@ export class FeedFilterComponent implements OnInit, OnDestroy {
private createProcessForm() {
return new FormGroup(
{
process: new FormControl<string | null>('')
process: new FormControl<string | null>(''),
state: new FormControl<string | null>('')
},
{updateOn: 'change'}
);
Expand All @@ -161,6 +167,21 @@ export class FeedFilterComponent implements OnInit, OnDestroy {
};
}

private initializeStateMultiSelect() {
this.stateMultiSelect = {
id: 'state',
options: [],
config: {
labelKey: 'shared.filters.state',
placeholderKey: 'shared.filters.selectStateText',
sortOptions: true,
nbOfDisplayValues: 4,
multiple: false
},
selectedOptions: []
};
}

ngOnDestroy() {
this.ngUnsubscribe$.next();
this.ngUnsubscribe$.complete();
Expand All @@ -186,6 +207,9 @@ export class FeedFilterComponent implements OnInit, OnDestroy {
this.initializeProcessMultiSelect();
this.initProcessFilter();
}
if (!this.hideStateFilter) {
this.initializeStateMultiSelect();
}
}

private loadVisibleProcessesForCurrentUser() {
Expand All @@ -196,6 +220,20 @@ export class FeedFilterComponent implements OnInit, OnDestroy {
});
}

private loadVisibleStatesForCurrentUserAndProcess() {
this.stateMultiSelect.options = [];
if (this.selectedProcess?.length > 0) {
const selected = this.processList.find((process) => process.id === this.selectedProcess);
const stateOptions = this.processStatesDropdownListService.getStatesMultiSelectOptionsPerSingleProcess(
selected,
false,
true
);
this.stateMultiSelect.options.push(new MultiSelectOption('', ''));
stateOptions.forEach((option) => this.stateMultiSelect.options.push(option));
}
}

private initProcessFilter() {
this.loadVisibleProcessesForCurrentUser();
this.processMultiSelect.options.push(new MultiSelectOption('', ''));
Expand All @@ -204,7 +242,15 @@ export class FeedFilterComponent implements OnInit, OnDestroy {
);
this.processFilterForm.valueChanges.pipe(takeUntil(this.ngUnsubscribe$)).subscribe((form) => {
this.filterActiveChange.next(this.isFilterActive());
return this.filteredLightCardStore.updateFilter(FilterType.PROCESS_FILTER, true, {process: form.process});
const selectedProcessChanged = form.process !== this.selectedProcess;
this.selectedProcess = form.process;
if (!this.hideStateFilter && selectedProcessChanged) {
this.loadVisibleStatesForCurrentUserAndProcess();
}
return this.filteredLightCardStore.updateFilter(FilterType.PROCESS_FILTER, true, {
process: form.process,
state: form.state
});
});
}

Expand Down

0 comments on commit f059d8b

Please sign in to comment.