@valtimo/task 13.37.0 → 13.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,6 +15,7 @@ import * as i2$1 from 'carbon-components-angular';
15
15
  import { LoadingModule, NotificationModule, ButtonModule, IconModule, ModalModule, ToggletipModule, DatePickerModule, LayerModule, LinkModule, TabsModule, ContentSwitcherModule, DropdownModule, TooltipModule as TooltipModule$1 } from 'carbon-components-angular';
16
16
  import { BehaviorSubject, combineLatest, Subject, switchMap, of, tap, filter, take as take$1, map as map$1, catchError, Subscription, distinctUntilChanged, shareReplay, EMPTY } from 'rxjs';
17
17
  import * as i2 from '@valtimo/document';
18
+ import { CaseTagsUtils } from '@valtimo/document';
18
19
  import * as i4 from 'ngx-logger';
19
20
  import * as i3 from '@valtimo/access-control';
20
21
  import * as i1$2 from '@angular/router';
@@ -162,14 +163,27 @@ class TaskService extends BaseApiService {
162
163
  getTasks() {
163
164
  return this.httpClient.get(this.getApiUrl('/v1/task?filter=all'));
164
165
  }
165
- getTask(id) {
166
- return this.httpClient.get(this.getApiUrl(`/v1/task/${id}`));
166
+ getTask(id, skipStatusCodes) {
167
+ // Skipping status codes prevents the global HttpErrorInterceptor from showing an error toast
168
+ // for those responses, so callers that expect and handle a status (e.g. a 403/404 after a
169
+ // task assignment change removes the user's access) can do so silently.
170
+ const options = skipStatusCodes && skipStatusCodes.length > 0
171
+ ? { headers: new HttpHeaders().set(InterceptorSkip, skipStatusCodes.join(',')) }
172
+ : {};
173
+ return this.httpClient.get(this.getApiUrl(`/v1/task/${id}`), options);
167
174
  }
168
175
  getCandidateUsers(id) {
169
- return this.httpClient.get(this.getApiUrl(`/v2/task/${id}/candidate-user`));
176
+ // The endpoint requires the assign permission. Right after an assignment change the task can be
177
+ // re-fetched while the (soon to be invalidated) assign permission still reads as allowed, which
178
+ // triggers this request and a 403. That 403 is expected, so it is skipped to avoid an error
179
+ // toast; callers fall back to an empty candidate list.
180
+ return this.httpClient.get(this.getApiUrl(`/v2/task/${id}/candidate-user`), {
181
+ headers: new HttpHeaders().set(InterceptorSkip, '403'),
182
+ });
170
183
  }
171
184
  getCandidateTeams(id) {
172
- return this.httpClient.get(this.getApiUrl(`/v1/task/${id}/candidate-team`), { params: { size: '1000' } });
185
+ // See getCandidateUsers: a 403 is expected right after an assignment change and is skipped.
186
+ return this.httpClient.get(this.getApiUrl(`/v1/task/${id}/candidate-team`), { params: { size: '1000' }, headers: new HttpHeaders().set(InterceptorSkip, '403') });
173
187
  }
174
188
  assignTask(id, assigneeRequest) {
175
189
  return this.httpClient.post(this.getApiUrl(`/v1/task/${id}/assign`), assigneeRequest);
@@ -417,6 +431,12 @@ class TaskListColumnService {
417
431
  get availableFields$() {
418
432
  return this._availableFields$.asObservable();
419
433
  }
434
+ getTagColumnKeys() {
435
+ return this._availableFields$
436
+ .getValue()
437
+ .filter((field) => field.viewType === ViewType.TAGS)
438
+ .map((field) => field.key);
439
+ }
420
440
  get fields$() {
421
441
  return combineLatest([this._availableFields$, this.hiddenColumns$]).pipe(map(([availableFields, hiddenColumns]) => {
422
442
  if (!hiddenColumns || hiddenColumns.length === 0) {
@@ -1823,11 +1843,15 @@ class TaskDetailModalComponent {
1823
1843
  this.candidateUsers$ = combineLatest([
1824
1844
  this.task$.pipe(filter$1(task => !!task)),
1825
1845
  this.canAssignUserToTask$,
1826
- ]).pipe(switchMap$1(([task, canAssign]) => canAssign ? this.taskService.getCandidateUsers(task.id) : of([])), shareReplay(1));
1846
+ ]).pipe(switchMap$1(([task, canAssign]) => canAssign
1847
+ ? this.taskService.getCandidateUsers(task.id).pipe(catchError$1(() => of([])))
1848
+ : of([])), shareReplay(1));
1827
1849
  this.candidateTeams$ = combineLatest([
1828
1850
  this.task$.pipe(filter$1(task => !!task)),
1829
1851
  this.canAssignUserToTask$,
1830
- ]).pipe(switchMap$1(([task, canAssign]) => canAssign ? this.taskService.getCandidateTeams(task.id).pipe(map(page => page.content)) : of([])), shareReplay(1));
1852
+ ]).pipe(switchMap$1(([task, canAssign]) => canAssign
1853
+ ? this.taskService.getCandidateTeams(task.id).pipe(map(page => page.content), catchError$1(() => of([])))
1854
+ : of([])), shareReplay(1));
1831
1855
  this._subscriptions = new Subscription();
1832
1856
  this.iconService.registerAll([FolderDetailsReference16]);
1833
1857
  }
@@ -1869,23 +1893,42 @@ class TaskDetailModalComponent {
1869
1893
  .subscribe((allowed) => {
1870
1894
  this.canModifyTask$.next(allowed);
1871
1895
  });
1896
+ this.permissionService
1897
+ .requestPermission(CAN_VIEW_TASK_PERMISSION, {
1898
+ resource: TASK_DETAIL_PERMISSION_RESOURCE.task,
1899
+ identifier: task.id,
1900
+ })
1901
+ .subscribe((allowed) => {
1902
+ if (!allowed && this.task$.getValue()?.id === task.id) {
1903
+ this.logger.debug('Closing task detail as user is not allowed to view Task with id:', task.id);
1904
+ this.closeModal();
1905
+ }
1906
+ });
1872
1907
  }
1873
1908
  else {
1874
1909
  this.logger.debug('Reset is user allowed to assign a user to Task as task is null');
1875
1910
  this.canAssignUserToTask$.next(false);
1911
+ this.canModifyTask$.next(false);
1876
1912
  }
1877
1913
  }));
1878
1914
  }
1879
1915
  openTaskUpdateSseEventSubscription() {
1880
1916
  this._subscriptions.add(this.sseService
1881
1917
  .getSseEventObservable('TASK_UPDATE')
1882
- .pipe(filter$1(event => this.task$.getValue()?.id === event.taskId), switchMap$1(event => this.taskService.getTask(event.taskId).pipe(catchError$1(err => {
1883
- if (err.status === 404) {
1884
- return of(null);
1885
- }
1886
- this.logger.error('Failed to fetch task on SSE update', err);
1887
- return EMPTY;
1888
- }))))
1918
+ .pipe(filter$1(event => this.task$.getValue()?.id === event.taskId), switchMap$1(event => {
1919
+ // A task update (e.g. an assignment by another user) can change the outcome of
1920
+ // permission checks for this task, so drop cached permissions before re-checking
1921
+ this.permissionService.invalidateResource(TASK_DETAIL_PERMISSION_RESOURCE.task, event.taskId);
1922
+ // a 403 or 404 means the user can no longer view the task; these are expected
1923
+ // outcomes here, so they are skipped to avoid a global error toast
1924
+ return this.taskService.getTask(event.taskId, ['403', '404']).pipe(catchError$1(err => {
1925
+ if (err.status === 403 || err.status === 404) {
1926
+ return of(null);
1927
+ }
1928
+ this.logger.error('Failed to fetch task on SSE update', err);
1929
+ return EMPTY;
1930
+ }));
1931
+ }))
1889
1932
  .subscribe(response => {
1890
1933
  if (!response) {
1891
1934
  this.closeModal();
@@ -1985,10 +2028,9 @@ class TaskDetailModalComponent {
1985
2028
  assignRequest.assignedTeamKey = event.teamKey ?? '';
1986
2029
  this.taskService
1987
2030
  .assignTask(task.id, assignRequest)
1988
- .pipe(switchMap$1(() => this.taskService.getTask(task.id)), take(1))
2031
+ .pipe(switchMap$1(() => this.refreshTaskAfterAssignmentChange(task.id)), take(1))
1989
2032
  .subscribe(response => {
1990
- this.refreshTask(response);
1991
- this.assignmentOfTaskChanged.emit();
2033
+ this.handleAssignmentChangeResponse(response);
1992
2034
  });
1993
2035
  }
1994
2036
  onUnassigned() {
@@ -1997,12 +2039,34 @@ class TaskDetailModalComponent {
1997
2039
  return;
1998
2040
  this.taskService
1999
2041
  .unassignTask(task.id)
2000
- .pipe(switchMap$1(() => this.taskService.getTask(task.id)), take(1))
2042
+ .pipe(switchMap$1(() => this.refreshTaskAfterAssignmentChange(task.id)), take(1))
2001
2043
  .subscribe(response => {
2002
- this.refreshTask(response);
2003
- this.assignmentOfTaskChanged.emit();
2044
+ this.handleAssignmentChangeResponse(response);
2004
2045
  });
2005
2046
  }
2047
+ refreshTaskAfterAssignmentChange(taskId) {
2048
+ // The new assignment can change the outcome of permission checks for this task,
2049
+ // so drop cached permissions before the task is re-fetched and re-checked
2050
+ this.permissionService.invalidateResource(TASK_DETAIL_PERMISSION_RESOURCE.task, taskId);
2051
+ // a 403 or 404 means the user can no longer view the task; these are expected
2052
+ // outcomes here, so they are skipped to avoid a global error toast
2053
+ return this.taskService.getTask(taskId, ['403', '404']).pipe(catchError$1(error => {
2054
+ if (error?.status === 403 || error?.status === 404) {
2055
+ return of(null);
2056
+ }
2057
+ this.logger.error('Failed to fetch task after assignment change', error);
2058
+ return EMPTY;
2059
+ }));
2060
+ }
2061
+ handleAssignmentChangeResponse(response) {
2062
+ if (response) {
2063
+ this.refreshTask(response);
2064
+ }
2065
+ else {
2066
+ this.closeModal();
2067
+ }
2068
+ this.assignmentOfTaskChanged.emit();
2069
+ }
2006
2070
  onFormSubmit() {
2007
2071
  this.formSubmit.emit();
2008
2072
  }
@@ -2417,6 +2481,7 @@ class TaskListComponent {
2417
2481
  mapTasksForList(isSpecified, tasks, canViewTaskPermissions, canViewCasePermissions) {
2418
2482
  const MOMENT_FORMAT = 'DD MMM YYYY HH:mm';
2419
2483
  if (isSpecified) {
2484
+ const tagColumnKeys = this.taskListColumnService.getTagColumnKeys();
2420
2485
  return tasks.content.map((specifiedTask, specifiedTaskIndex) => specifiedTask.items.reduce((acc, curr) => ({
2421
2486
  id: specifiedTask.id,
2422
2487
  businessKey: specifiedTask.businessKey,
@@ -2432,7 +2497,9 @@ class TaskListComponent {
2432
2497
  caseLocked: !canViewCasePermissions[specifiedTaskIndex],
2433
2498
  }),
2434
2499
  ...acc,
2435
- [curr.key]: curr.value,
2500
+ [curr.key]: tagColumnKeys.includes(curr.key)
2501
+ ? this.mapCaseTagsToCarbonTags(curr.value)
2502
+ : curr.value,
2436
2503
  }), {}));
2437
2504
  }
2438
2505
  return tasks?.content?.map((task, taskIndex) => {
@@ -2450,6 +2517,14 @@ class TaskListComponent {
2450
2517
  return taskCopy;
2451
2518
  });
2452
2519
  }
2520
+ mapCaseTagsToCarbonTags(value) {
2521
+ if (!Array.isArray(value))
2522
+ return value;
2523
+ return value.map((tag) => ({
2524
+ content: tag.title,
2525
+ type: CaseTagsUtils.getTagTypeFromCaseTagColor(tag.color),
2526
+ }));
2527
+ }
2453
2528
  setParamsFromQueryParams() {
2454
2529
  const decodedParams = this.taskListQueryParamService.getTaskListQueryParams();
2455
2530
  if (decodedParams.caseDefinitionKey) {
@@ -2490,7 +2565,7 @@ class TaskListComponent {
2490
2565
  provide: QUICK_SEARCH_SERVICE,
2491
2566
  useClass: TaskListQuickSearchService,
2492
2567
  },
2493
- ], viewQueries: [{ propertyName: "_taskDetail", first: true, predicate: ["taskDetail"], descendants: true }, { propertyName: "_unreadIndicator", first: true, predicate: ["unreadIndicator"], descendants: true, static: true }], ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<div\n *ngIf=\"{\n loading: loadingTasks$ | async,\n selectedTaskType: selectedTaskType$ | async,\n tasks: tasks$ | async,\n fields: fields$ | async,\n availableFields: availableFields$ | async,\n hiddenColumns: hiddenColumns$ | async,\n visibleTabs: visibleTabs$ | async,\n pagination: paginationForCurrentTaskTypeForList$ | async,\n taskListColumnsForCase: taskListColumnsForCase$ | async,\n sortState: sortStateForCurrentTaskType$ | async,\n overrideSortState: overrideSortState$ | async,\n searchFields: searchFields$ | async,\n loadingSearchFields: loadingSearchFields$ | async,\n caseDefinitionKey: caseDefinitionKey$ | async,\n noResultsMessage: noResultsMessage$ | async,\n } as obs\"\n class=\"main-content\"\n>\n <div class=\"container-fluid\">\n @if (obs.caseDefinitionKey && obs.caseDefinitionKey !== ALL_CASES_ID) {\n <ng-container\n *ngTemplateOutlet=\"\n searchFields;\n context: {\n obs: obs,\n }\n \"\n ></ng-container>\n\n <div class=\"mb-3\">\n <valtimo-quick-search (quickSearchEvent)=\"onQuickSearchEvent($event)\"></valtimo-quick-search>\n </div>\n }\n\n <ng-container\n *ngTemplateOutlet=\"\n tasksList;\n context: {\n obs: obs,\n }\n \"\n ></ng-container>\n\n <ng-container\n *ngTemplateOutlet=\"\n tasksListLoading;\n context: {\n obs: obs,\n }\n \"\n ></ng-container>\n\n <valtimo-task-detail-modal\n #taskDetail\n (formSubmit)=\"reload()\"\n (assignmentOfTaskChanged)=\"reload()\"\n (dueDateChanged)=\"reload()\"\n (modalClosed)=\"reload()\"\n ></valtimo-task-detail-modal>\n </div>\n</div>\n\n<ng-template #configuredTabs let-selectedTaskType=\"selectedTaskType\" let-visibleTabs=\"visibleTabs\">\n <cds-tabs *ngIf=\"visibleTabs\" type=\"contained\" class=\"valtimo-carbon-list__tabs\">\n <cds-tab\n *ngFor=\"let tab of visibleTabs\"\n [attr.data-testid]=\"'task-list-tab-' + tab\"\n [heading]=\"'task-list.' + tab + '.title' | translate\"\n [active]=\"selectedTaskType === tab\"\n (selected)=\"tabChange(tab)\"\n ></cds-tab>\n </cds-tabs>\n</ng-template>\n\n<ng-template #unreadIndicator let-data=\"data\">\n <span *ngIf=\"!data.item?.isOpened\" class=\"valtimo-task-list__unread-dot\"></span>\n</ng-template>\n\n<ng-template #caseLink let-data=\"data\">\n <ng-container *ngIf=\"cachedTasks$ | async as cachedTasks\">\n <div *ngIf=\"cachedTasks[data.index].caseLocked\">\n <a\n class=\"float-left cds--link--disabled\"\n cdsLink\n href=\"javascript:void(0)\"\n ngbTooltip=\"{{ 'task-list.caseLocked' | translate }}\"\n (click)=\"$event.stopPropagation()\"\n >\n {{ 'task-list.goToCase' | translate }}\n </a>\n </div>\n <div *ngIf=\"!cachedTasks[data.index].caseLocked\">\n <a\n class=\"float-left cds--link\"\n cdsLink\n href=\"javascript:void(0)\"\n (click)=\"openRelatedCase($event, data.index)\"\n >\n {{ 'task-list.goToCase' | translate }}\n </a>\n </div>\n </ng-container>\n</ng-template>\n\n<ng-template #tasksList let-obs=\"obs\">\n <valtimo-carbon-list\n *ngIf=\"!obs.loading\"\n [fields]=\"obs.fields\"\n [header]=\"false\"\n [items]=\"obs.tasks\"\n [lastColumnTemplate]=\"caseLink\"\n [pagination]=\"obs.pagination\"\n\n lockedTooltipTranslationKey=\"task-list.rowLocked\"\n [sortState]=\"obs.overrideSortState || obs.sortState\"\n (paginationClicked)=\"paginationClicked($event, obs.selectedTaskType)\"\n (paginationSet)=\"paginationSet($event)\"\n (rowClicked)=\"rowOpenTaskClick($event)\"\n (sortChanged)=\"sortChanged($event)\"\n >\n <div tabs>\n <ng-container *ngIf=\"obs.visibleTabs\">\n <ng-container\n *ngTemplateOutlet=\"\n configuredTabs;\n context: {selectedTaskType: obs.selectedTaskType, visibleTabs: obs.visibleTabs}\n \"\n ></ng-container>\n </ng-container>\n </div>\n\n <div carbonToolbarContent>\n <valtimo-list-column-view\n *ngIf=\"obs.caseDefinitionKey && obs.caseDefinitionKey !== ALL_CASES_ID\"\n [availableFields]=\"obs.availableFields\"\n [hiddenColumns]=\"obs.hiddenColumns\"\n (viewUpdateEvent)=\"onViewUpdateEvent($event)\"\n ></valtimo-list-column-view>\n </div>\n\n <valtimo-no-results\n [description]=\"obs.noResultsMessage.description | translate\"\n [title]=\"obs.noResultsMessage.title | translate\"\n >\n </valtimo-no-results>\n </valtimo-carbon-list>\n</ng-template>\n\n<ng-template #tasksListLoading let-obs=\"obs\">\n <valtimo-carbon-list *ngIf=\"obs.loading\" [loading]=\"true\">\n <div tabs>\n <cds-tabs *ngIf=\"!obs.visibleTabs\" type=\"contained\" class=\"valtimo-carbon-list__tabs\">\n <cds-tab\n [heading]=\"'task-list.mine.title' | translate\"\n [active]=\"obs.selectedTaskType === 'mine'\"\n >\n </cds-tab>\n\n <cds-tab\n [heading]=\"'task-list.open.title' | translate\"\n [active]=\"obs.selectedTaskType === 'open'\"\n >\n </cds-tab>\n\n <cds-tab\n [heading]=\"'task-list.all.title' | translate\"\n [active]=\"obs.selectedTaskType === 'all'\"\n >\n </cds-tab>\n </cds-tabs>\n\n <cds-tabs *ngIf=\"obs.visibleTabs\" type=\"contained\" class=\"valtimo-carbon-list__tabs\">\n <cds-tab\n *ngFor=\"let tab of obs.visibleTabs\"\n [heading]=\"'task-list.' + tab + '.title' | translate\"\n [active]=\"obs.selectedTaskType === tab\"\n ></cds-tab>\n </cds-tabs>\n </div>\n </valtimo-carbon-list>\n</ng-template>\n\n<ng-template #searchFields let-obs=\"obs\">\n <div class=\"mb-3\">\n <valtimo-search-fields\n [canSaveSearch]=\"true\"\n [searchFields]=\"obs.searchFields\"\n [inputDisabled]=\"obs.loadingSearchFields\"\n [caseDefinitionKey]=\"obs.caseDefinitionKey\"\n [setValuesSubject$]=\"setSearchFieldValuesSubject$\"\n [clearValuesSubject$]=\"clearSearchFieldValuesSubject$\"\n (doSearch)=\"search($event)\"\n (saveSearchEvent)=\"onSaveSearchEvent($event)\"\n >\n </valtimo-search-fields>\n </div>\n</ng-template>\n\n<ng-container renderInPageHeader [fullWidth]=\"true\">\n <ng-template>\n <cds-dropdown\n class=\"case-definition-selection\"\n *ngIf=\"{\n loadingCaseListItems: loadingCaseListItems$ | async,\n caseListItems: caseListItems$ | async,\n } as obs\"\n [attr.data-testid]=\"'task-list-case-dropdown'\"\n [disabled]=\"obs.loadingCaseListItems || (obs.caseListItems || []).length === 1\"\n [skeleton]=\"obs.loadingCaseListItems\"\n (selected)=\"setCaseDefinition($event)\"\n >\n <cds-dropdown-list [items]=\"obs.caseListItems || []\"></cds-dropdown-list>\n </cds-dropdown>\n </ng-template>\n</ng-container>\n", styles: [".cds--link--disabled{cursor:not-allowed;pointer-events:auto!important;outline:0!important}.case-definition-selection{display:flex;width:250px}.valtimo-task-list__unread-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background-color:var(--cds-link-primary)}::ng-deep .valtimo-task-list__unread-column{width:2rem;padding-right:0!important}\n/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"], dependencies: [{ kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i9.CarbonListComponent, selector: "valtimo-carbon-list", inputs: ["items", "fields", "tableTranslations", "paginatorConfig", "pagination", "loading", "skeletonRowCount", "actions", "actionItems", "showActionItems", "header", "hideColumnHeader", "initialSortState", "sortState", "isSearchable", "enableSingleSelection", "lastColumnTemplate", "paginationIdentifier", "showSelectionColumn", "striped", "hideToolbar", "lockedTooltipTranslationKey", "movingRowsEnabled", "dragAndDrop", "dragAndDropDisabled"], outputs: ["rowClicked", "paginationClicked", "paginationSet", "search", "sortChanged", "moveRow", "itemsReordered"] }, { kind: "component", type: i9.CarbonNoResultsComponent, selector: "valtimo-no-results", inputs: ["action", "description", "illustration", "title", "smallPadding", "collapseVertically", "alwaysRenderVertically"] }, { kind: "directive", type: i13.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "triggers", "container", "disableTooltip", "tooltipClass", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "directive", type: i2$1.Link, selector: "[cdsLink], [ibmLink]", inputs: ["inline", "disabled"] }, { kind: "component", type: i2$1.Tabs, selector: "cds-tabs, ibm-tabs", inputs: ["position", "cacheActive", "followFocus", "isNavigation", "ariaLabel", "ariaLabelledby", "type", "theme", "skeleton"] }, { kind: "component", type: i2$1.Tab, selector: "cds-tab, ibm-tab", inputs: ["heading", "title", "context", "active", "disabled", "tabIndex", "id", "cacheActive", "tabContent", "templateContext"], outputs: ["selected"] }, { kind: "directive", type: i9.RenderInPageHeaderDirective, selector: "[renderInPageHeader]", inputs: ["fullWidth"] }, { kind: "component", type: i2$1.Dropdown, selector: "cds-dropdown, ibm-dropdown", inputs: ["id", "label", "hideLabel", "helperText", "placeholder", "displayValue", "clearText", "size", "type", "theme", "disabled", "readonly", "skeleton", "inline", "disableArrowKeys", "invalid", "invalidText", "warn", "warnText", "appendInline", "scrollableContainer", "itemValueKey", "selectionFeedback", "menuButtonLabel", "selectedLabel", "dropUp", "fluid"], outputs: ["selected", "onClose", "close"] }, { kind: "component", type: i2$1.DropdownList, selector: "cds-dropdown-list, ibm-dropdown-list", inputs: ["ariaLabel", "items", "listTpl", "type", "showTitles"], outputs: ["select", "scroll", "blurIntent"] }, { kind: "component", type: i9.SearchFieldsComponent, selector: "valtimo-search-fields", inputs: ["loading", "searchFields", "caseDefinitionKey", "setValuesSubject$", "clearValuesSubject$", "defaultValues", "disableSaveSearch", "inputDisabled", "externalSearchField", "canSaveSearch"], outputs: ["doSearch", "saveSearchEvent", "clearEvent"] }, { kind: "component", type: i9.QuickSearchComponent, selector: "valtimo-quick-search", outputs: ["quickSearchEvent"] }, { kind: "component", type: i9.ListColumnViewComponent, selector: "valtimo-list-column-view", inputs: ["availableFields", "hiddenColumns", "disabled"], outputs: ["viewUpdateEvent"] }, { kind: "component", type: TaskDetailModalComponent, selector: "valtimo-task-detail-modal", inputs: ["modalSize", "openFromCaseManagement"], outputs: ["formSubmit", "assignmentOfTaskChanged", "dueDateChanged", "modalClosed"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i4$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2568
+ ], viewQueries: [{ propertyName: "_taskDetail", first: true, predicate: ["taskDetail"], descendants: true }, { propertyName: "_unreadIndicator", first: true, predicate: ["unreadIndicator"], descendants: true, static: true }], ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<div\n *ngIf=\"{\n loading: loadingTasks$ | async,\n selectedTaskType: selectedTaskType$ | async,\n tasks: tasks$ | async,\n fields: fields$ | async,\n availableFields: availableFields$ | async,\n hiddenColumns: hiddenColumns$ | async,\n visibleTabs: visibleTabs$ | async,\n pagination: paginationForCurrentTaskTypeForList$ | async,\n taskListColumnsForCase: taskListColumnsForCase$ | async,\n sortState: sortStateForCurrentTaskType$ | async,\n overrideSortState: overrideSortState$ | async,\n searchFields: searchFields$ | async,\n loadingSearchFields: loadingSearchFields$ | async,\n caseDefinitionKey: caseDefinitionKey$ | async,\n noResultsMessage: noResultsMessage$ | async,\n } as obs\"\n class=\"main-content\"\n>\n <div class=\"container-fluid\">\n @if (obs.caseDefinitionKey && obs.caseDefinitionKey !== ALL_CASES_ID) {\n <ng-container\n *ngTemplateOutlet=\"\n searchFields;\n context: {\n obs: obs,\n }\n \"\n ></ng-container>\n\n <div class=\"mb-3\">\n <valtimo-quick-search (quickSearchEvent)=\"onQuickSearchEvent($event)\"></valtimo-quick-search>\n </div>\n }\n\n <ng-container\n *ngTemplateOutlet=\"\n tasksList;\n context: {\n obs: obs,\n }\n \"\n ></ng-container>\n\n <ng-container\n *ngTemplateOutlet=\"\n tasksListLoading;\n context: {\n obs: obs,\n }\n \"\n ></ng-container>\n\n <valtimo-task-detail-modal\n #taskDetail\n (formSubmit)=\"reload()\"\n (assignmentOfTaskChanged)=\"reload()\"\n (dueDateChanged)=\"reload()\"\n (modalClosed)=\"reload()\"\n ></valtimo-task-detail-modal>\n </div>\n</div>\n\n<ng-template #configuredTabs let-selectedTaskType=\"selectedTaskType\" let-visibleTabs=\"visibleTabs\">\n <cds-tabs *ngIf=\"visibleTabs\" type=\"contained\" class=\"valtimo-carbon-list__tabs\">\n <cds-tab\n *ngFor=\"let tab of visibleTabs\"\n [attr.data-testid]=\"'task-list-tab-' + tab\"\n [heading]=\"'task-list.' + tab + '.title' | translate\"\n [active]=\"selectedTaskType === tab\"\n (selected)=\"tabChange(tab)\"\n ></cds-tab>\n </cds-tabs>\n</ng-template>\n\n<ng-template #unreadIndicator let-data=\"data\">\n <span *ngIf=\"!data.item?.isOpened\" class=\"valtimo-task-list__unread-dot\"></span>\n</ng-template>\n\n<ng-template #caseLink let-data=\"data\">\n <ng-container *ngIf=\"cachedTasks$ | async as cachedTasks\">\n <div *ngIf=\"cachedTasks[data.index].caseLocked\">\n <a\n class=\"float-left cds--link--disabled\"\n cdsLink\n href=\"javascript:void(0)\"\n ngbTooltip=\"{{ 'task-list.caseLocked' | translate }}\"\n (click)=\"$event.stopPropagation()\"\n >\n {{ 'task-list.goToCase' | translate }}\n </a>\n </div>\n <div *ngIf=\"!cachedTasks[data.index].caseLocked\">\n <a\n class=\"float-left cds--link\"\n cdsLink\n href=\"javascript:void(0)\"\n (click)=\"openRelatedCase($event, data.index)\"\n >\n {{ 'task-list.goToCase' | translate }}\n </a>\n </div>\n </ng-container>\n</ng-template>\n\n<ng-template #tasksList let-obs=\"obs\">\n <valtimo-carbon-list\n *ngIf=\"!obs.loading\"\n [fields]=\"obs.fields\"\n [header]=\"false\"\n [items]=\"obs.tasks\"\n [lastColumnTemplate]=\"caseLink\"\n [pagination]=\"obs.pagination\"\n\n lockedTooltipTranslationKey=\"task-list.rowLocked\"\n [sortState]=\"obs.overrideSortState || obs.sortState\"\n (paginationClicked)=\"paginationClicked($event, obs.selectedTaskType)\"\n (paginationSet)=\"paginationSet($event)\"\n (rowClicked)=\"rowOpenTaskClick($event)\"\n (sortChanged)=\"sortChanged($event)\"\n >\n <div tabs>\n <ng-container *ngIf=\"obs.visibleTabs\">\n <ng-container\n *ngTemplateOutlet=\"\n configuredTabs;\n context: {selectedTaskType: obs.selectedTaskType, visibleTabs: obs.visibleTabs}\n \"\n ></ng-container>\n </ng-container>\n </div>\n\n <div carbonToolbarContent>\n <valtimo-list-column-view\n *ngIf=\"obs.caseDefinitionKey && obs.caseDefinitionKey !== ALL_CASES_ID\"\n [availableFields]=\"obs.availableFields\"\n [hiddenColumns]=\"obs.hiddenColumns\"\n (viewUpdateEvent)=\"onViewUpdateEvent($event)\"\n ></valtimo-list-column-view>\n </div>\n\n <valtimo-no-results\n [description]=\"obs.noResultsMessage.description | translate\"\n [title]=\"obs.noResultsMessage.title | translate\"\n >\n </valtimo-no-results>\n </valtimo-carbon-list>\n</ng-template>\n\n<ng-template #tasksListLoading let-obs=\"obs\">\n <valtimo-carbon-list *ngIf=\"obs.loading\" [loading]=\"true\">\n <div tabs>\n <cds-tabs *ngIf=\"!obs.visibleTabs\" type=\"contained\" class=\"valtimo-carbon-list__tabs\">\n <cds-tab\n [heading]=\"'task-list.mine.title' | translate\"\n [active]=\"obs.selectedTaskType === 'mine'\"\n >\n </cds-tab>\n\n <cds-tab\n [heading]=\"'task-list.open.title' | translate\"\n [active]=\"obs.selectedTaskType === 'open'\"\n >\n </cds-tab>\n\n <cds-tab\n [heading]=\"'task-list.all.title' | translate\"\n [active]=\"obs.selectedTaskType === 'all'\"\n >\n </cds-tab>\n </cds-tabs>\n\n <cds-tabs *ngIf=\"obs.visibleTabs\" type=\"contained\" class=\"valtimo-carbon-list__tabs\">\n <cds-tab\n *ngFor=\"let tab of obs.visibleTabs\"\n [heading]=\"'task-list.' + tab + '.title' | translate\"\n [active]=\"obs.selectedTaskType === tab\"\n ></cds-tab>\n </cds-tabs>\n </div>\n </valtimo-carbon-list>\n</ng-template>\n\n<ng-template #searchFields let-obs=\"obs\">\n <div class=\"mb-3\">\n <valtimo-search-fields\n [canSaveSearch]=\"true\"\n [searchFields]=\"obs.searchFields\"\n [inputDisabled]=\"obs.loadingSearchFields\"\n [caseDefinitionKey]=\"obs.caseDefinitionKey\"\n [setValuesSubject$]=\"setSearchFieldValuesSubject$\"\n [clearValuesSubject$]=\"clearSearchFieldValuesSubject$\"\n (doSearch)=\"search($event)\"\n (saveSearchEvent)=\"onSaveSearchEvent($event)\"\n >\n </valtimo-search-fields>\n </div>\n</ng-template>\n\n<ng-container renderInPageHeader [fullWidth]=\"true\">\n <ng-template>\n <cds-dropdown\n class=\"case-definition-selection\"\n *ngIf=\"{\n loadingCaseListItems: loadingCaseListItems$ | async,\n caseListItems: caseListItems$ | async,\n } as obs\"\n [attr.data-testid]=\"'task-list-case-dropdown'\"\n [disabled]=\"obs.loadingCaseListItems || (obs.caseListItems || []).length === 1\"\n [skeleton]=\"obs.loadingCaseListItems\"\n (selected)=\"setCaseDefinition($event)\"\n >\n <cds-dropdown-list [items]=\"obs.caseListItems || []\"></cds-dropdown-list>\n </cds-dropdown>\n </ng-template>\n</ng-container>\n", styles: [".cds--link--disabled{cursor:not-allowed;pointer-events:auto!important;outline:0!important}.case-definition-selection{display:flex;width:250px}.valtimo-task-list__unread-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background-color:var(--cds-link-primary)}::ng-deep .valtimo-task-list__unread-column{width:2rem;padding-right:0!important}\n/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"], dependencies: [{ kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i9.CarbonListComponent, selector: "valtimo-carbon-list", inputs: ["items", "fields", "tableTranslations", "paginatorConfig", "pagination", "loading", "skeletonRowCount", "actions", "actionItems", "showActionItems", "header", "hideColumnHeader", "initialSortState", "sortState", "isSearchable", "initialSearchValue", "searchDebounceMs", "invalidSearchFields", "searchFields", "enableSingleSelection", "lastColumnTemplate", "paginationIdentifier", "showSelectionColumn", "striped", "hideToolbar", "lockedTooltipTranslationKey", "movingRowsEnabled", "dragAndDrop", "dragAndDropDisabled", "expandedRowTemplate", "expandedRowKey", "trackByKey"], outputs: ["rowClicked", "paginationClicked", "paginationSet", "search", "sortChanged", "moveRow", "itemsReordered"] }, { kind: "component", type: i9.CarbonNoResultsComponent, selector: "valtimo-no-results", inputs: ["action", "description", "illustration", "title", "smallPadding", "collapseVertically", "alwaysRenderVertically"] }, { kind: "directive", type: i13.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "triggers", "container", "disableTooltip", "tooltipClass", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "directive", type: i2$1.Link, selector: "[cdsLink], [ibmLink]", inputs: ["inline", "disabled"] }, { kind: "component", type: i2$1.Tabs, selector: "cds-tabs, ibm-tabs", inputs: ["position", "cacheActive", "followFocus", "isNavigation", "ariaLabel", "ariaLabelledby", "type", "theme", "skeleton"] }, { kind: "component", type: i2$1.Tab, selector: "cds-tab, ibm-tab", inputs: ["heading", "title", "context", "active", "disabled", "tabIndex", "id", "cacheActive", "tabContent", "templateContext"], outputs: ["selected"] }, { kind: "directive", type: i9.RenderInPageHeaderDirective, selector: "[renderInPageHeader]", inputs: ["fullWidth"] }, { kind: "component", type: i2$1.Dropdown, selector: "cds-dropdown, ibm-dropdown", inputs: ["id", "label", "hideLabel", "helperText", "placeholder", "displayValue", "clearText", "size", "type", "theme", "disabled", "readonly", "skeleton", "inline", "disableArrowKeys", "invalid", "invalidText", "warn", "warnText", "appendInline", "scrollableContainer", "itemValueKey", "selectionFeedback", "menuButtonLabel", "selectedLabel", "dropUp", "fluid"], outputs: ["selected", "onClose", "close"] }, { kind: "component", type: i2$1.DropdownList, selector: "cds-dropdown-list, ibm-dropdown-list", inputs: ["ariaLabel", "items", "listTpl", "type", "showTitles"], outputs: ["select", "scroll", "blurIntent"] }, { kind: "component", type: i9.SearchFieldsComponent, selector: "valtimo-search-fields", inputs: ["loading", "searchFields", "caseDefinitionKey", "setValuesSubject$", "clearValuesSubject$", "defaultValues", "disableSaveSearch", "inputDisabled", "externalSearchField", "canSaveSearch"], outputs: ["doSearch", "saveSearchEvent", "clearEvent"] }, { kind: "component", type: i9.QuickSearchComponent, selector: "valtimo-quick-search", outputs: ["quickSearchEvent"] }, { kind: "component", type: i9.ListColumnViewComponent, selector: "valtimo-list-column-view", inputs: ["availableFields", "hiddenColumns", "disabled"], outputs: ["viewUpdateEvent"] }, { kind: "component", type: TaskDetailModalComponent, selector: "valtimo-task-detail-modal", inputs: ["modalSize", "openFromCaseManagement"], outputs: ["formSubmit", "assignmentOfTaskChanged", "dueDateChanged", "modalClosed"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i4$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2494
2569
  }
2495
2570
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TaskListComponent, decorators: [{
2496
2571
  type: Component,