@zeniai/client-epic-state 5.1.45-betaDI3 → 5.1.45

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.
Files changed (85) hide show
  1. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  2. package/lib/entity/snackbar/snackbarTypes.js +0 -3
  3. package/lib/entity/task/taskPayload.d.ts +1 -3
  4. package/lib/entity/task/taskPayload.js +2 -24
  5. package/lib/entity/task/taskReducer.d.ts +1 -8
  6. package/lib/entity/task/taskReducer.js +4 -29
  7. package/lib/entity/task/taskState.d.ts +0 -2
  8. package/lib/entity/tenant/epic/saveExternalConnectionEpic.d.ts +1 -2
  9. package/lib/entity/tenant/epic/saveExternalConnectionEpic.js +0 -17
  10. package/lib/epic.d.ts +3 -6
  11. package/lib/epic.js +3 -6
  12. package/lib/esm/entity/snackbar/snackbarTypes.js +0 -3
  13. package/lib/esm/entity/task/taskPayload.js +2 -24
  14. package/lib/esm/entity/task/taskReducer.js +3 -28
  15. package/lib/esm/entity/tenant/epic/saveExternalConnectionEpic.js +0 -17
  16. package/lib/esm/epic.js +3 -6
  17. package/lib/esm/index.js +8 -8
  18. package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +1 -31
  19. package/lib/esm/view/aiCfoView/epics/fetchSkillsEpic.js +8 -33
  20. package/lib/esm/view/companyTaskManagerView/epics/fetchCompanyTaskManagerViewEpic.js +0 -3
  21. package/lib/esm/view/companyTaskManagerView/epics/fetchTaskManagerMetricsEpic.js +1 -7
  22. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +0 -7
  23. package/lib/esm/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +0 -1
  24. package/lib/esm/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +9 -70
  25. package/lib/esm/view/taskManager/taskDetailView/taskDetailReducer.js +2 -56
  26. package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +9 -35
  27. package/lib/esm/view/taskManager/taskListView/epics/fetchTaskListEpic.js +1 -3
  28. package/lib/esm/view/taskManager/taskListView/taskList.js +0 -1
  29. package/lib/esm/view/taskManager/taskListView/taskListReducer.js +18 -310
  30. package/lib/esm/view/taskManager/taskListView/taskListSelector.js +0 -1
  31. package/lib/esm/view/taskManager/taskListView/taskListViewHelpers.js +0 -58
  32. package/lib/esm/view/transactionDetail/epics/saveTransactionHelper.js +0 -22
  33. package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +3 -75
  34. package/lib/esm/view/transactionDetail/journalEntryLinesViewModel.js +0 -58
  35. package/lib/esm/view/transactionDetail/transactionDetailLocalDataHelper.js +8 -10
  36. package/lib/esm/view/transactionDetail/transactionDetailReducer.js +1 -66
  37. package/lib/index.d.ts +11 -12
  38. package/lib/index.js +28 -37
  39. package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +0 -10
  40. package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +2 -7
  41. package/lib/view/aiCfoView/aiCfoViewReducer.js +2 -32
  42. package/lib/view/aiCfoView/aiCfoViewState.d.ts +1 -5
  43. package/lib/view/aiCfoView/epics/fetchSkillsEpic.js +8 -33
  44. package/lib/view/companyTaskManagerView/epics/fetchCompanyTaskManagerViewEpic.js +0 -3
  45. package/lib/view/companyTaskManagerView/epics/fetchTaskManagerMetricsEpic.js +1 -7
  46. package/lib/view/companyView/types/cockpitTypes.d.ts +0 -3
  47. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  48. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +0 -7
  49. package/lib/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +0 -1
  50. package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.d.ts +2 -2
  51. package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +8 -69
  52. package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +0 -15
  53. package/lib/view/taskManager/taskDetailView/taskDetailReducer.d.ts +2 -14
  54. package/lib/view/taskManager/taskDetailView/taskDetailReducer.js +3 -57
  55. package/lib/view/taskManager/taskDetailView/taskDetailSelector.d.ts +1 -3
  56. package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +7 -33
  57. package/lib/view/taskManager/taskListView/epics/fetchTaskListEpic.js +1 -3
  58. package/lib/view/taskManager/taskListView/taskList.d.ts +1 -1
  59. package/lib/view/taskManager/taskListView/taskList.js +0 -1
  60. package/lib/view/taskManager/taskListView/taskListPayload.d.ts +0 -4
  61. package/lib/view/taskManager/taskListView/taskListReducer.d.ts +2 -6
  62. package/lib/view/taskManager/taskListView/taskListReducer.js +19 -311
  63. package/lib/view/taskManager/taskListView/taskListSelector.js +0 -1
  64. package/lib/view/taskManager/taskListView/taskListViewHelpers.d.ts +0 -11
  65. package/lib/view/taskManager/taskListView/taskListViewHelpers.js +1 -60
  66. package/lib/view/transactionDetail/epics/saveTransactionHelper.js +0 -22
  67. package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.d.ts +1 -5
  68. package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +4 -77
  69. package/lib/view/transactionDetail/journalEntryLinesViewModel.d.ts +0 -27
  70. package/lib/view/transactionDetail/journalEntryLinesViewModel.js +1 -61
  71. package/lib/view/transactionDetail/transactionDetailLocalDataHelper.js +8 -10
  72. package/lib/view/transactionDetail/transactionDetailReducer.d.ts +2 -11
  73. package/lib/view/transactionDetail/transactionDetailReducer.js +2 -67
  74. package/lib/view/transactionDetail/transactionDetailState.d.ts +1 -8
  75. package/lib/view/transactionDetail/transactionDetailTypes.d.ts +0 -2
  76. package/package.json +1 -1
  77. package/lib/esm/view/aiCfoView/epics/submitFeedbackEpic.js +0 -39
  78. package/lib/esm/view/taskManager/taskDetailView/epics/createSubTaskEpic.js +0 -96
  79. package/lib/esm/view/taskManager/taskDetailView/epics/fetchSubTasksEpic.js +0 -53
  80. package/lib/view/aiCfoView/epics/submitFeedbackEpic.d.ts +0 -13
  81. package/lib/view/aiCfoView/epics/submitFeedbackEpic.js +0 -43
  82. package/lib/view/taskManager/taskDetailView/epics/createSubTaskEpic.d.ts +0 -9
  83. package/lib/view/taskManager/taskDetailView/epics/createSubTaskEpic.js +0 -100
  84. package/lib/view/taskManager/taskDetailView/epics/fetchSubTasksEpic.d.ts +0 -8
  85. package/lib/view/taskManager/taskDetailView/epics/fetchSubTasksEpic.js +0 -57
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.clearTaskList = exports.removeTaskFromGroupBucket = exports.removeTaskFromList = exports.updateTaskListOnCreateTaskFromTemplateSuccess = exports.updateTasksListOnUpdateTaskFailure = exports.updateTasksListOnUpdateTaskSuccess = exports.updateTaskFromListView = exports.updateTaskListOnTaskGroupNameUpdate = exports.updateTaskListOnNewTaskCreationSuccess = exports.dragNDropTasks = exports.updateTaskListOnTaskGroupDeletion = exports.updateTaskListLocalData = exports.initiateTaskListLocalData = exports.updateTasksListOnBulkUpdateTasksFailure = exports.updateTasksListOnBulkUpdateTasksSuccess = exports.bulkUpdateTaskList = exports.updateTaskListOnNewGroupCreationSuccess = exports.updateTaskFilters = exports.updateTaskListUIState = exports.updateTaskListSearchText = exports.updateTaskListFetchStatus = exports.updateTaskListTab = exports.updateTaskList = exports.fetchTaskList = exports.fetchTaskListPage = exports.initialState = void 0;
4
+ exports.clearTaskList = exports.removeTaskFromList = exports.updateTaskListOnCreateTaskFromTemplateSuccess = exports.updateTasksListOnUpdateTaskFailure = exports.updateTasksListOnUpdateTaskSuccess = exports.updateTaskFromListView = exports.updateTaskListOnTaskGroupNameUpdate = exports.updateTaskListOnNewTaskCreationSuccess = exports.dragNDropTasks = exports.updateTaskListOnTaskGroupDeletion = exports.updateTaskListLocalData = exports.initiateTaskListLocalData = exports.updateTasksListOnBulkUpdateTasksFailure = exports.updateTasksListOnBulkUpdateTasksSuccess = exports.bulkUpdateTaskList = exports.updateTaskListOnNewGroupCreationSuccess = exports.updateTaskFilters = exports.updateTaskListUIState = exports.updateTaskListSearchText = exports.updateTaskListFetchStatus = exports.updateTaskListTab = exports.updateTaskList = exports.fetchTaskList = exports.fetchTaskListPage = exports.initialState = void 0;
5
5
  const toolkit_1 = require("@reduxjs/toolkit");
6
- const taskReducer_1 = require("../../../entity/task/taskReducer");
7
6
  const taskState_1 = require("../../../entity/task/taskState");
8
7
  const zeniDayJS_1 = require("../../../zeniDayJS");
9
8
  const taskList_1 = require("./taskList");
@@ -47,7 +46,6 @@ exports.initialState = {
47
46
  currentTab: 'live',
48
47
  byTab: {
49
48
  live: { ...initialTabData },
50
- completed: { ...initialTabData },
51
49
  archived: { ...initialTabData },
52
50
  deleted: { ...initialTabData },
53
51
  snoozed: { ...initialTabData },
@@ -69,12 +67,14 @@ exports.initialState = {
69
67
  },
70
68
  filters: {
71
69
  categoryCombinationOperator: 'AND',
72
- // Default to no filters. The Completed tab now owns the "hide resolved
73
- // tasks from the live list" responsibility via the byTab split in
74
- // updateTaskList / updateTaskFromListView / the updateTasks
75
- // extraReducer. Keeping the historical `status != resolved` filter
76
- // here would empty out the Completed tab.
77
- categories: [],
70
+ categories: [
71
+ {
72
+ field: 'status',
73
+ matchingOperator: 'not_equal',
74
+ values: ['resolved'],
75
+ valuesCombinationOperator: 'ANY',
76
+ },
77
+ ],
78
78
  },
79
79
  hasValidState() {
80
80
  return this.fetchState == 'Completed';
@@ -106,37 +106,21 @@ const taskList = (0, toolkit_1.createSlice)({
106
106
  draft.error = undefined;
107
107
  },
108
108
  updateTaskList(draft, action) {
109
- const { data, archived, completed, deleted, snoozed } = action.payload;
109
+ const { data, archived, deleted, snoozed } = action.payload;
110
110
  draft.fetchState = 'Completed';
111
111
  draft.error = undefined;
112
- // Build the nested-subtask set from the UNION of every bucket in
113
- // this payload — not per-bucket. A resolved subtask can arrive in
114
- // `completed` while its parent (which claims it via `subtasks`)
115
- // is still in `data`; a per-bucket scan would miss the cross-tab
116
- // claim and surface the subtask as a phantom top-level row in
117
- // the Completed tab.
118
- const nestedSubtaskIds = collectNestedSubtaskIds([
119
- data,
120
- completed,
121
- archived,
122
- deleted,
123
- snoozed,
124
- ]);
125
112
  // Group live tasks
126
- const liveGrouped = getGroupedTaskIds(data, nestedSubtaskIds);
113
+ const liveGrouped = getGroupedTaskIds(data);
127
114
  draft.byTab.live = toTabData(liveGrouped);
128
115
  // Group other tabs if provided
129
- if (completed != null) {
130
- draft.byTab.completed = toTabData(getGroupedTaskIds(completed, nestedSubtaskIds));
131
- }
132
116
  if (archived != null) {
133
- draft.byTab.archived = toTabData(getGroupedTaskIds(archived, nestedSubtaskIds));
117
+ draft.byTab.archived = toTabData(getGroupedTaskIds(archived));
134
118
  }
135
119
  if (deleted != null) {
136
- draft.byTab.deleted = toTabData(getGroupedTaskIds(deleted, nestedSubtaskIds));
120
+ draft.byTab.deleted = toTabData(getGroupedTaskIds(deleted));
137
121
  }
138
122
  if (snoozed != null) {
139
- draft.byTab.snoozed = toTabData(getGroupedTaskIds(snoozed, nestedSubtaskIds));
123
+ draft.byTab.snoozed = toTabData(getGroupedTaskIds(snoozed));
140
124
  }
141
125
  // Copy active tab data to top-level fields
142
126
  const activeTabData = draft.byTab[draft.currentTab];
@@ -374,26 +358,9 @@ const taskList = (0, toolkit_1.createSlice)({
374
358
  draft.taskIdsByAssignees[assigneeKey] = draft.taskIdsByAssignees[assigneeKey].filter((taskId) => taskId !== currentTaskState.id);
375
359
  draft.taskIdsByTags[tagsKey] = draft.taskIdsByTags[tagsKey].filter((taskId) => taskId !== currentTaskState.id);
376
360
  draft.taskIdsByDueDate[dueDateKey] = draft.taskIdsByDueDate[dueDateKey].filter((taskId) => taskId !== currentTaskState.id);
377
- // Remove from EVERY previous group bucket the task lived in, not
378
- // just the destination bucket. Otherwise a detail-page save that
379
- // moves a task from group A to group B leaves the row listed
380
- // under both A and B until refetch.
381
- const previousGroupIds = currentTaskState.taskGroupIds ?? [];
382
- const allGroupIdsToClean = new Set([
383
- ...previousGroupIds,
384
- taskGroupId,
385
- ]);
386
- allGroupIdsToClean.forEach((gid) => {
387
- if (draft.taskIdsByGroupsIds[gid] != null) {
388
- draft.taskIdsByGroupsIds[gid] = draft.taskIdsByGroupsIds[gid].filter((id) => id !== currentTaskState.id);
389
- }
390
- });
361
+ draft.taskIdsByGroupsIds[taskGroupId] = draft.taskIdsByGroupsIds[taskGroupId].filter((taskId) => taskId !== currentTaskState.id);
391
362
  }
392
363
  doUpdateTaskList(draft, task, taskGroupId);
393
- // Mirror top-level grouping into the active tab's byTab snapshot,
394
- // otherwise the next updateTaskListTab call copies stale byTab data
395
- // back over this optimistic update.
396
- syncTopLevelToActiveTab(draft);
397
364
  },
398
365
  updateTaskListOnCreateTaskFromTemplateSuccess(draft, action) {
399
366
  const { tasks } = action.payload;
@@ -417,7 +384,6 @@ const taskList = (0, toolkit_1.createSlice)({
417
384
  const taskId = task.id;
418
385
  draft.updateTasksFetchState.fetchState = 'In-Progress';
419
386
  draft.updateTasksFetchState.error = undefined;
420
- let didMigrateTab = false;
421
387
  if (updates.priority != null) {
422
388
  const prevPriorityCode = (0, taskState_1.toPriorityCodeType)(task.priority.code);
423
389
  draft.taskIdsByPriority[prevPriorityCode] = draft.taskIdsByPriority[prevPriorityCode].filter((id) => id != taskId);
@@ -429,32 +395,6 @@ const taskList = (0, toolkit_1.createSlice)({
429
395
  draft.taskIdsByStatus[prevStatusCode] = draft.taskIdsByStatus[prevStatusCode].filter((id) => id != taskId);
430
396
  const newStatusCode = (0, taskState_1.toTaskStatusCodeType)(updates.status.code);
431
397
  draft.taskIdsByStatus[newStatusCode].push(taskId);
432
- // Optimistically re-bucket between the live and completed tabs
433
- // when status transitions in/out of "resolved", so the task
434
- // moves to the Completed tab without waiting for the next
435
- // fetch. Mirrors backend split in task_handler.py: only
436
- // `resolved` counts as completed; `done` stays Active.
437
- //
438
- // "Top-level" here means: currently rendered as a standalone
439
- // row in the live or completed tab (i.e. present in
440
- // `byTab.<tab>.taskIds`). We use presence in byTab — NOT a
441
- // `parent_task_id == null` check — so orphan subtasks (parent
442
- // hidden from the customer's payload, so we render them flat)
443
- // ALSO migrate between tabs on status flip. This matches the
444
- // criterion `getGroupedTaskIds` uses when it builds byTab from
445
- // the initial fetch — a task is nested iff a visible parent's
446
- // `subtasks` array claims it, otherwise it's top-level here.
447
- const isTopLevelTask = draft.byTab.live.taskIds.includes(taskId) ||
448
- draft.byTab.completed.taskIds.includes(taskId);
449
- const wasCompleted = prevStatusCode === 'resolved';
450
- const isCompleted = newStatusCode === 'resolved';
451
- if (isTopLevelTask && wasCompleted !== isCompleted) {
452
- const from = isCompleted ? 'live' : 'completed';
453
- const to = isCompleted ? 'completed' : 'live';
454
- const updatedTask = { ...task, ...updates };
455
- migrateTaskBetweenTabs(draft, taskId, updatedTask, from, to);
456
- didMigrateTab = true;
457
- }
458
398
  }
459
399
  if (updates.assignees != null) {
460
400
  const prevGroupId = getAssigneesGroupKey(task.assignees);
@@ -494,18 +434,7 @@ const taskList = (0, toolkit_1.createSlice)({
494
434
  };
495
435
  }
496
436
  }
497
- if (didMigrateTab) {
498
- // The migration moved the task out of the source byTab and into
499
- // the destination byTab. The active tab's grouping arrays are
500
- // now authoritative — mirror them back to the top-level so the
501
- // UI sees the task gone from Live (or freshly arrived in
502
- // Completed). Inverse of syncTopLevelToActiveTab, used only on
503
- // this path.
504
- copyTabDataToTopLevel(draft, draft.byTab[draft.currentTab]);
505
- }
506
- else {
507
- syncTopLevelToActiveTab(draft);
508
- }
437
+ syncTopLevelToActiveTab(draft);
509
438
  },
510
439
  updateTasksListOnUpdateTaskSuccess(draft) {
511
440
  draft.updateTasksFetchState.fetchState = 'Completed';
@@ -518,83 +447,12 @@ const taskList = (0, toolkit_1.createSlice)({
518
447
  removeTaskFromList(draft, action) {
519
448
  removeTaskIds(draft, [action.payload]);
520
449
  },
521
- /**
522
- * Remove a task id from a single group bucket without touching tab
523
- * membership or other groupings. Used when the user clears a task's
524
- * group on the Detail page so the row stops appearing under the old
525
- * group while saveTaskDetailEpic skips the standard list re-insert.
526
- */
527
- removeTaskFromGroupBucket(draft, action) {
528
- const { taskId, taskGroupId } = action.payload;
529
- if (draft.taskIdsByGroupsIds[taskGroupId] != null) {
530
- draft.taskIdsByGroupsIds[taskGroupId] = draft.taskIdsByGroupsIds[taskGroupId].filter((id) => id !== taskId);
531
- }
532
- // Mirror to the active tab's grouping so the UI re-renders.
533
- const activeTab = draft.byTab[draft.currentTab];
534
- if (activeTab.taskIdsByGroupsIds[taskGroupId] != null) {
535
- activeTab.taskIdsByGroupsIds[taskGroupId] =
536
- activeTab.taskIdsByGroupsIds[taskGroupId].filter((id) => id !== taskId);
537
- }
538
- },
539
450
  clearTaskList(draft) {
540
451
  Object.assign(draft, exports.initialState);
541
452
  },
542
453
  },
543
- extraReducers: (builder) => {
544
- // When the entity store receives updated tasks (e.g. from task detail
545
- // save, snooze/archive/unarchive, etc.), re-bucket top-level tasks
546
- // between the live and completed tabs based on the new status. Mirrors
547
- // the backend split in task_handler.py: only `resolved` counts as
548
- // completed.
549
- //
550
- // "Top-level" here means: currently rendered as a standalone row in
551
- // the live or completed tab (i.e. present in
552
- // `byTab.<tab>.taskIds`). Tasks that are nested under a parent's
553
- // expanded subtask row live outside byTab.taskIds and are silently
554
- // skipped by the "in-bucket" check below. This uses the same
555
- // criterion as `getGroupedTaskIds` — a task is nested iff a visible
556
- // parent's `subtasks` array claims it, otherwise it's top-level —
557
- // so orphan subtasks (parent hidden from the customer's payload)
558
- // migrate correctly on status flip via pusher / detail-save.
559
- builder.addCase(taskReducer_1.updateTasks, (draft, action) => {
560
- action.payload.forEach((taskPayload) => {
561
- const taskId = taskPayload.task_id;
562
- // `TaskPayload.status` is required per the type — every producer
563
- // in this repo sends it, and `mapTaskPayloadToTask` dereferences
564
- // it unguarded. The optional chain + null guard are defensive
565
- // only, in case a downstream consumer (web-app-ui / cockpit-ui)
566
- // ever dispatches `updateTasks` with a partial payload; in that
567
- // case we treat missing status as "no status change" and skip
568
- // re-bucketing so we don't migrate a Completed task back into
569
- // the Live tab.
570
- const statusCode = taskPayload.status?.code;
571
- if (statusCode == null) {
572
- return;
573
- }
574
- const isCompleted = statusCode === 'resolved';
575
- const targetTab = isCompleted ? 'completed' : 'live';
576
- const otherTab = isCompleted ? 'live' : 'completed';
577
- // Skip if the task isn't currently in either of these buckets
578
- // (archived/snoozed/deleted are managed by their own actions).
579
- const inLive = draft.byTab.live.taskIds.includes(taskId);
580
- const inCompleted = draft.byTab.completed.taskIds.includes(taskId);
581
- if (!inLive && !inCompleted) {
582
- return;
583
- }
584
- if (draft.byTab[otherTab].taskIds.includes(taskId)) {
585
- migrateTaskPayloadBetweenTabs(draft, taskId, taskPayload, otherTab, targetTab);
586
- }
587
- else if (!draft.byTab[targetTab].taskIds.includes(taskId)) {
588
- draft.byTab[targetTab].taskIds.push(taskId);
589
- }
590
- });
591
- // Re-sync the top-level taskIds / grouping arrays for whichever
592
- // tab the user is currently looking at.
593
- copyTabDataToTopLevel(draft, draft.byTab[draft.currentTab]);
594
- });
595
- },
596
454
  });
597
- _a = taskList.actions, exports.fetchTaskListPage = _a.fetchTaskListPage, exports.fetchTaskList = _a.fetchTaskList, exports.updateTaskList = _a.updateTaskList, exports.updateTaskListTab = _a.updateTaskListTab, exports.updateTaskListFetchStatus = _a.updateTaskListFetchStatus, exports.updateTaskListSearchText = _a.updateTaskListSearchText, exports.updateTaskListUIState = _a.updateTaskListUIState, exports.updateTaskFilters = _a.updateTaskFilters, exports.updateTaskListOnNewGroupCreationSuccess = _a.updateTaskListOnNewGroupCreationSuccess, exports.bulkUpdateTaskList = _a.bulkUpdateTaskList, exports.updateTasksListOnBulkUpdateTasksSuccess = _a.updateTasksListOnBulkUpdateTasksSuccess, exports.updateTasksListOnBulkUpdateTasksFailure = _a.updateTasksListOnBulkUpdateTasksFailure, exports.initiateTaskListLocalData = _a.initiateTaskListLocalData, exports.updateTaskListLocalData = _a.updateTaskListLocalData, exports.updateTaskListOnTaskGroupDeletion = _a.updateTaskListOnTaskGroupDeletion, exports.dragNDropTasks = _a.dragNDropTasks, exports.updateTaskListOnNewTaskCreationSuccess = _a.updateTaskListOnNewTaskCreationSuccess, exports.updateTaskListOnTaskGroupNameUpdate = _a.updateTaskListOnTaskGroupNameUpdate, exports.updateTaskFromListView = _a.updateTaskFromListView, exports.updateTasksListOnUpdateTaskSuccess = _a.updateTasksListOnUpdateTaskSuccess, exports.updateTasksListOnUpdateTaskFailure = _a.updateTasksListOnUpdateTaskFailure, exports.updateTaskListOnCreateTaskFromTemplateSuccess = _a.updateTaskListOnCreateTaskFromTemplateSuccess, exports.removeTaskFromList = _a.removeTaskFromList, exports.removeTaskFromGroupBucket = _a.removeTaskFromGroupBucket, exports.clearTaskList = _a.clearTaskList;
455
+ _a = taskList.actions, exports.fetchTaskListPage = _a.fetchTaskListPage, exports.fetchTaskList = _a.fetchTaskList, exports.updateTaskList = _a.updateTaskList, exports.updateTaskListTab = _a.updateTaskListTab, exports.updateTaskListFetchStatus = _a.updateTaskListFetchStatus, exports.updateTaskListSearchText = _a.updateTaskListSearchText, exports.updateTaskListUIState = _a.updateTaskListUIState, exports.updateTaskFilters = _a.updateTaskFilters, exports.updateTaskListOnNewGroupCreationSuccess = _a.updateTaskListOnNewGroupCreationSuccess, exports.bulkUpdateTaskList = _a.bulkUpdateTaskList, exports.updateTasksListOnBulkUpdateTasksSuccess = _a.updateTasksListOnBulkUpdateTasksSuccess, exports.updateTasksListOnBulkUpdateTasksFailure = _a.updateTasksListOnBulkUpdateTasksFailure, exports.initiateTaskListLocalData = _a.initiateTaskListLocalData, exports.updateTaskListLocalData = _a.updateTaskListLocalData, exports.updateTaskListOnTaskGroupDeletion = _a.updateTaskListOnTaskGroupDeletion, exports.dragNDropTasks = _a.dragNDropTasks, exports.updateTaskListOnNewTaskCreationSuccess = _a.updateTaskListOnNewTaskCreationSuccess, exports.updateTaskListOnTaskGroupNameUpdate = _a.updateTaskListOnTaskGroupNameUpdate, exports.updateTaskFromListView = _a.updateTaskFromListView, exports.updateTasksListOnUpdateTaskSuccess = _a.updateTasksListOnUpdateTaskSuccess, exports.updateTasksListOnUpdateTaskFailure = _a.updateTasksListOnUpdateTaskFailure, exports.updateTaskListOnCreateTaskFromTemplateSuccess = _a.updateTaskListOnCreateTaskFromTemplateSuccess, exports.removeTaskFromList = _a.removeTaskFromList, exports.clearTaskList = _a.clearTaskList;
598
456
  exports.default = taskList.reducer;
599
457
  /**
600
458
  * helpers
@@ -701,115 +559,6 @@ const copyTabDataToTopLevel = (draft, tabData) => {
701
559
  draft.taskIdsByDueDate = tabData.taskIdsByDueDate;
702
560
  draft.taskIdsByTags = tabData.taskIdsByTags;
703
561
  };
704
- /**
705
- * Migrate a parent task between two `byTab` buckets (live ↔ completed)
706
- * when its status flips into / out of `resolved`. The destination tab
707
- * picks up the task in EVERY grouping dimension (status, priority,
708
- * group id, assignees, dueDate, tags) using the UPDATED task as the
709
- * source-of-truth for the new bucket keys. Otherwise the Completed tab
710
- * shows the task in the right tab-level list but the grouped views
711
- * (Group by Status, Group by Priority, etc.) miss it until the next
712
- * full fetch.
713
- */
714
- const migrateTaskBetweenTabs = (draft, taskId, updatedTask, from, to) => {
715
- const fromTab = draft.byTab[from];
716
- const toTab = draft.byTab[to];
717
- // Source tab: drop the task from every grouping dimension.
718
- removeIdsFromTabData(fromTab, [taskId]);
719
- // Destination tab: add the task to taskIds (deduped) plus the
720
- // appropriate bucket inside each grouping dimension based on the
721
- // updated task.
722
- if (!toTab.taskIds.includes(taskId)) {
723
- toTab.taskIds.push(taskId);
724
- }
725
- const priorityKey = (0, taskState_1.toPriorityCodeType)(updatedTask.priority.code);
726
- if (!toTab.taskIdsByPriority[priorityKey].includes(taskId)) {
727
- toTab.taskIdsByPriority[priorityKey].push(taskId);
728
- }
729
- const statusKey = (0, taskState_1.toTaskStatusCodeType)(updatedTask.status.code);
730
- if (!toTab.taskIdsByStatus[statusKey].includes(taskId)) {
731
- toTab.taskIdsByStatus[statusKey].push(taskId);
732
- }
733
- const dueDateKey = updatedTask.dueDate != null
734
- ? getDueDateGroupKey(updatedTask.dueDate.toString())
735
- : 'upcoming';
736
- if (!toTab.taskIdsByDueDate[dueDateKey].includes(taskId)) {
737
- toTab.taskIdsByDueDate[dueDateKey].push(taskId);
738
- }
739
- const assigneeKey = getAssigneesGroupKey(updatedTask.assignees);
740
- if (toTab.taskIdsByAssignees[assigneeKey] == null) {
741
- toTab.taskIdsByAssignees[assigneeKey] = [taskId];
742
- }
743
- else if (!toTab.taskIdsByAssignees[assigneeKey].includes(taskId)) {
744
- toTab.taskIdsByAssignees[assigneeKey].push(taskId);
745
- }
746
- const tagIds = [...updatedTask.tagIds].sort();
747
- const tagsKey = tagIds.join(',');
748
- if (toTab.taskIdsByTags[tagsKey] == null) {
749
- toTab.taskIdsByTags[tagsKey] = [taskId];
750
- }
751
- else if (!toTab.taskIdsByTags[tagsKey].includes(taskId)) {
752
- toTab.taskIdsByTags[tagsKey].push(taskId);
753
- }
754
- (updatedTask.taskGroupIds ?? []).forEach((groupId) => {
755
- if (toTab.taskIdsByGroupsIds[groupId] == null) {
756
- toTab.taskIdsByGroupsIds[groupId] = [taskId];
757
- }
758
- else if (!toTab.taskIdsByGroupsIds[groupId].includes(taskId)) {
759
- toTab.taskIdsByGroupsIds[groupId].push(taskId);
760
- }
761
- });
762
- };
763
- /**
764
- * `updateTasks` extraReducer variant — same migration semantics but
765
- * keyed off the raw `TaskPayload` instead of the rich `Task` entity.
766
- */
767
- const migrateTaskPayloadBetweenTabs = (draft, taskId, payload, from, to) => {
768
- const fromTab = draft.byTab[from];
769
- const toTab = draft.byTab[to];
770
- removeIdsFromTabData(fromTab, [taskId]);
771
- if (!toTab.taskIds.includes(taskId)) {
772
- toTab.taskIds.push(taskId);
773
- }
774
- if (payload.priority?.code != null) {
775
- const priorityKey = (0, taskState_1.toPriorityCodeType)(payload.priority.code);
776
- if (!toTab.taskIdsByPriority[priorityKey].includes(taskId)) {
777
- toTab.taskIdsByPriority[priorityKey].push(taskId);
778
- }
779
- }
780
- if (payload.status?.code != null) {
781
- const statusKey = (0, taskState_1.toTaskStatusCodeType)(payload.status.code);
782
- if (!toTab.taskIdsByStatus[statusKey].includes(taskId)) {
783
- toTab.taskIdsByStatus[statusKey].push(taskId);
784
- }
785
- }
786
- const dueDateKey = getDueDateGroupKey(payload.due_date);
787
- if (!toTab.taskIdsByDueDate[dueDateKey].includes(taskId)) {
788
- toTab.taskIdsByDueDate[dueDateKey].push(taskId);
789
- }
790
- const assigneeKey = getAssigneesGroupKey(payload.assignees ?? []);
791
- if (toTab.taskIdsByAssignees[assigneeKey] == null) {
792
- toTab.taskIdsByAssignees[assigneeKey] = [taskId];
793
- }
794
- else if (!toTab.taskIdsByAssignees[assigneeKey].includes(taskId)) {
795
- toTab.taskIdsByAssignees[assigneeKey].push(taskId);
796
- }
797
- const tagsKey = getTagsGroupKey(payload.tags ?? []);
798
- if (toTab.taskIdsByTags[tagsKey] == null) {
799
- toTab.taskIdsByTags[tagsKey] = [taskId];
800
- }
801
- else if (!toTab.taskIdsByTags[tagsKey].includes(taskId)) {
802
- toTab.taskIdsByTags[tagsKey].push(taskId);
803
- }
804
- (payload.task_group_ids ?? []).forEach((groupId) => {
805
- if (toTab.taskIdsByGroupsIds[groupId] == null) {
806
- toTab.taskIdsByGroupsIds[groupId] = [taskId];
807
- }
808
- else if (!toTab.taskIdsByGroupsIds[groupId].includes(taskId)) {
809
- toTab.taskIdsByGroupsIds[groupId].push(taskId);
810
- }
811
- });
812
- };
813
562
  const removeIdsFromTabData = (tabData, taskIds) => {
814
563
  const removedSet = new Set(taskIds);
815
564
  const isRemoved = (id) => removedSet.has(id);
@@ -837,39 +586,7 @@ const removeTaskIds = (draft, taskIds) => {
837
586
  removeIdsFromTabData(draft, taskIds);
838
587
  removeIdsFromTabData(draft.byTab[draft.currentTab], taskIds);
839
588
  };
840
- // Collect the union of subtask ids claimed by any parent across every
841
- // bucket in the payload. See the callsite in `updateTaskList` for why
842
- // this must be cross-bucket rather than per-bucket.
843
- const collectNestedSubtaskIds = (buckets) => {
844
- const nestedSubtaskIds = new Set();
845
- buckets.forEach((bucket) => {
846
- if (bucket == null) {
847
- return;
848
- }
849
- bucket.forEach((task) => {
850
- (task.subtasks ?? []).forEach((subtaskId) => nestedSubtaskIds.add(subtaskId));
851
- });
852
- });
853
- return nestedSubtaskIds;
854
- };
855
- // A task is a "nested subtask" (hidden from the flat top-level list +
856
- // dropped from the tab count) iff a parent in the same payload claims
857
- // it via its `subtasks: [...]` array. Match this criterion exactly to
858
- // WC's `allSubtaskIds` union in TaskManagementPage.tsx — otherwise
859
- // the tab count and the visible top-level row count disagree
860
- // whenever the BE emits `parent_task_id` on a subtask but omits it
861
- // from the parent's `subtasks` array (a real inconsistency this UI
862
- // sees today).
863
- //
864
- // Using `parent_task_id` here would sometimes drop a task from the
865
- // count that WC still renders as a flat top-level row — that's the
866
- // bug we're fixing.
867
- //
868
- // `nestedSubtaskIds` is passed in from the caller and covers subtasks
869
- // claimed by parents in ANY bucket (live/completed/archived/deleted/
870
- // snoozed), so a subtask resolved into `completed` while its parent
871
- // stays in `data` is still correctly recognized as nested.
872
- const getGroupedTaskIds = (tasks, nestedSubtaskIds) => {
589
+ const getGroupedTaskIds = (tasks) => {
873
590
  const taskIds = [];
874
591
  const taskIdsByGroupIds = {};
875
592
  const taskIdsByAssignees = {};
@@ -884,21 +601,12 @@ const getGroupedTaskIds = (tasks, nestedSubtaskIds) => {
884
601
  };
885
602
  const taskIdsByTags = {};
886
603
  tasks.forEach((task) => {
887
- const isNestedSubtask = nestedSubtaskIds.has(task.task_id);
888
- // Subtasks stay in every groupBy array so the UI can render them
889
- // nested under their parent (WC's TaskManagementPage builds
890
- // `subtasksByParentId` from `group.tasks` and then filters them
891
- // out of top-level rows via `filterOutSubtasks`). Only the flat
892
- // top-level `taskIds` array — which drives the Active/Completed/…
893
- // tab counts — must exclude nested subtasks.
604
+ taskIds.push(task.task_id);
894
605
  const priorityKey = (0, taskState_1.toPriorityCodeType)(task.priority.code);
895
606
  const statusKey = (0, taskState_1.toTaskStatusCodeType)(task.status.code);
896
607
  const assigneeKey = getAssigneesGroupKey(task.assignees);
897
608
  const dueDateKey = getDueDateGroupKey(task.due_date);
898
609
  const tagsKey = getTagsGroupKey(task.tags);
899
- if (!isNestedSubtask) {
900
- taskIds.push(task.task_id);
901
- }
902
610
  taskIdsGroupedByPriority[priorityKey] = [
903
611
  ...taskIdsGroupedByPriority[priorityKey],
904
612
  task.task_id,
@@ -342,7 +342,6 @@ exports.getAllTasks = (0, toolkit_1.createSelector)((state) => state.taskListSta
342
342
  const taskGroupTemplates = (0, taskGroupTemplateSelector_1.getTaskGroupTemplateByIds)(taskGroupTemplateState, taskGroupTemplateViewState.taskGroupTemplateIds);
343
343
  const tabCounts = {
344
344
  live: taskListState.byTab.live.taskIds.length,
345
- completed: taskListState.byTab.completed.taskIds.length,
346
345
  archived: taskListState.byTab.archived.taskIds.length,
347
346
  deleted: taskListState.byTab.deleted.taskIds.length,
348
347
  snoozed: taskListState.byTab.snoozed.taskIds.length,
@@ -1,16 +1,5 @@
1
- import { Tag } from '../../../entity/tag/tagState';
2
1
  import { Task } from '../../../entity/task/taskState';
3
- import { User } from '../../../entity/user/userState';
4
2
  import { ZeniDate } from '../../../zeniDayJS';
5
3
  import { TaskGroupKey } from './taskList';
6
- export type SubtaskSortKey = 'name' | 'status' | 'assignee' | 'tag';
7
- export type SubtaskSortOrder = 'asc' | 'desc';
8
4
  export declare const getDueDateValueFromDueDateGroupId: (groupId: string) => ZeniDate;
9
5
  export declare const getTaskUpdates: (groupByKey: TaskGroupKey, groupId: string) => Partial<Task>;
10
- /**
11
- * Sort a subtask list by one of the sortable columns. Pure — no state
12
- * dependency. `statusOrder` is derived from `allTaskStatus` so any new
13
- * status added upstream slots in by its enum position instead of
14
- * falling into a catch-all bucket.
15
- */
16
- export declare const sortSubtasks: (subtasks: Task[], sortKey: SubtaskSortKey | null, sortOrder: SubtaskSortOrder, userList: User[], tagList: Tag[]) => Task[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sortSubtasks = exports.getTaskUpdates = exports.getDueDateValueFromDueDateGroupId = void 0;
3
+ exports.getTaskUpdates = exports.getDueDateValueFromDueDateGroupId = void 0;
4
4
  const zeniDayJS_1 = require("../../../zeniDayJS");
5
5
  const taskDetailSelector_1 = require("../taskDetailView/taskDetailSelector");
6
6
  const taskList_1 = require("./taskList");
@@ -53,62 +53,3 @@ const getTaskUpdates = (groupByKey, groupId) => {
53
53
  };
54
54
  };
55
55
  exports.getTaskUpdates = getTaskUpdates;
56
- /**
57
- * Sort a subtask list by one of the sortable columns. Pure — no state
58
- * dependency. `statusOrder` is derived from `allTaskStatus` so any new
59
- * status added upstream slots in by its enum position instead of
60
- * falling into a catch-all bucket.
61
- */
62
- const sortSubtasks = (subtasks, sortKey, sortOrder, userList, tagList) => {
63
- if (sortKey == null) {
64
- return subtasks;
65
- }
66
- const statusOrder = taskDetailSelector_1.allTaskStatus.reduce((acc, status, index) => {
67
- acc[status.code] = index;
68
- return acc;
69
- }, {});
70
- const unknownStatusRank = taskDetailSelector_1.allTaskStatus.length;
71
- const cmpStr = (a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' });
72
- const keyFn = (task) => {
73
- if (sortKey === 'name') {
74
- return task.name ?? '';
75
- }
76
- if (sortKey === 'status') {
77
- return statusOrder[task.status.code] ?? unknownStatusRank;
78
- }
79
- if (sortKey === 'assignee') {
80
- const firstId = task.assignees?.[0];
81
- if (firstId == null) {
82
- return '';
83
- }
84
- const user = userList.find((candidate) => candidate.userId === firstId);
85
- return user
86
- ? `${user.firstName ?? ''} ${user.lastName ?? ''}`.trim()
87
- : '';
88
- }
89
- if (sortKey === 'tag') {
90
- const firstTagId = task.tagIds?.[0];
91
- if (firstTagId == null) {
92
- return '';
93
- }
94
- const tag = tagList.find((candidate) => candidate.tagId === firstTagId);
95
- return tag?.name ?? '';
96
- }
97
- return '';
98
- };
99
- const copy = [...subtasks];
100
- copy.sort((a, b) => {
101
- const av = keyFn(a);
102
- const bv = keyFn(b);
103
- let cmp;
104
- if (typeof av === 'number' && typeof bv === 'number') {
105
- cmp = av - bv;
106
- }
107
- else {
108
- cmp = cmpStr(String(av), String(bv));
109
- }
110
- return sortOrder === 'asc' ? cmp : -cmp;
111
- });
112
- return copy;
113
- };
114
- exports.sortSubtasks = sortSubtasks;
@@ -48,15 +48,7 @@ const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLoc
48
48
  let lastUpdatedCategory;
49
49
  let lastUpdatedClass;
50
50
  // single recommendation to just pick the last recommendation in the list of lines
51
- const existingLineIds = new Set(transaction.lines?.map((l) => l.id) ?? []);
52
- const deletedLineIds = new Set((transactionDetailLocalData.deletedLineIds ?? []).filter((id) => existingLineIds.has(id)));
53
- // Collect new lines — in lineItemById but not yet in transaction.lines.
54
- const addedLines = Object.values(transactionDetailLocalData.lineItemById).filter((item) => !existingLineIds.has(item.id));
55
51
  transaction.lines?.forEach((line) => {
56
- // Skip lines the user deleted in edit mode.
57
- if (deletedLineIds.has(line.id)) {
58
- return;
59
- }
60
52
  const lineItem = transactionDetailLocalData.lineItemById[line.id];
61
53
  if (line.type === 'transaction_with_account_and_class_line' ||
62
54
  line.type === 'transaction_with_product_or_service_line' ||
@@ -67,7 +59,6 @@ const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLoc
67
59
  const entityDetails = getEntityDetails(selectedEntity, lineItem, transactionDetailLocalData.vendorUpdates, transactionDetailLocalData.customerUpdates);
68
60
  updatesByLineId[line.id] = {
69
61
  lineDescription: lineItem.lineDescription,
70
- amount: lineItem.amount,
71
62
  class: lineItem.class,
72
63
  account: lineItem.account,
73
64
  // Project is at the transaction level for invoice/credit_memo; omit from lines.
@@ -89,17 +80,6 @@ const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLoc
89
80
  currentSelectedEntityLine.type === 'vendor'
90
81
  ? lineItem.vendor
91
82
  : undefined,
92
- // Carry the JE debit/credit side so a split edit that flips an
93
- // existing line's posting side persists through the line patch.
94
- ...(line.type === 'journal_entry_transaction_line'
95
- ? {
96
- postingType: lineItem.postingType,
97
- postingTypeName: lineItem.postingType != null
98
- ? lineItem.postingType.charAt(0).toUpperCase() +
99
- lineItem.postingType.slice(1)
100
- : lineItem.postingTypeName,
101
- }
102
- : {}),
103
83
  };
104
84
  }
105
85
  let hasCategoryChanged = false;
@@ -186,8 +166,6 @@ const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLoc
186
166
  and all the line items are NOT uncategorized*/
187
167
  markAsMiscatUpdates: isTransactionMisCategorized,
188
168
  anyBulkUpdates: isBulkUpdate,
189
- addedLines: addedLines.length > 0 ? addedLines : undefined,
190
- deletedLineIds: deletedLineIds.size > 0 ? [...deletedLineIds] : undefined,
191
169
  };
192
170
  };
193
171
  exports.toTransactionUpdatesFromTransactionDetailLocalData = toTransactionUpdatesFromTransactionDetailLocalData;
@@ -1,11 +1,9 @@
1
1
  import { ActionsObservable, StateObservable } from 'redux-observable';
2
- import { ID } from '../../../commonStateTypes/common';
3
2
  import { COTTransactionTracking } from '../../../commonStateTypes/recommendationBase';
4
3
  import { CustomerBase } from '../../../entity/customer/customerState';
5
4
  import { Entity } from '../../../entity/genericEntity/entity';
6
5
  import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
7
6
  import { TransactionPayload } from '../../../entity/transaction/payloadTypes/transactionPayload';
8
- import { Line } from '../../../entity/transaction/stateTypes/transactionLine';
9
7
  import { updateTransaction, updateTransactions } from '../../../entity/transaction/transactionReducer';
10
8
  import { SupportedTransaction } from '../../../entity/transaction/transactionState';
11
9
  import { updateVendors } from '../../../entity/vendor/vendorReducer';
@@ -15,8 +13,6 @@ import { ZeniAPI } from '../../../zeniAPI';
15
13
  import { syncTransactionCategorizationFromDetailSave } from '../../expenseAutomationView/reducers/transactionsViewReducer';
16
14
  import { initializeTransactionDetailLocalData, markTransactionAsNotMiscategorized, updateStatusConsolidatedSaveTransactionDetail, updateTransactionDetail, updateTransactionDetailSaveStatus, updateTransactionStateIfUpdateActionNotAllowed } from '../transactionDetailReducer';
17
15
  import { TransactionUpdates } from '../transactionDetailState';
18
- import { TransactionDetailLineItemData } from '../transactionDetailTypes';
19
16
  export type ActionType = ReturnType<typeof updateTransactionDetail> | ReturnType<typeof updateTransaction> | ReturnType<typeof updateTransactions> | ReturnType<typeof updateTransactionStateIfUpdateActionNotAllowed> | ReturnType<typeof openSnackbar> | ReturnType<typeof updateTransactionDetailSaveStatus> | ReturnType<typeof updateStatusConsolidatedSaveTransactionDetail> | ReturnType<typeof initializeTransactionDetailLocalData> | ReturnType<typeof updateVendors> | ReturnType<typeof markTransactionAsNotMiscategorized> | ReturnType<typeof syncTransactionCategorizationFromDetailSave>;
20
17
  export declare const updateTransactionDetailEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => import("rxjs").Observable<ActionType>;
21
- export declare const toTransactionUpdatePayload: (updates: TransactionUpdates, detail: SupportedTransaction, cotTransactionTracking: COTTransactionTracking, isAccountingProjectsEnabled: boolean, vendorUpdates?: VendorBase, customerUpdates?: CustomerBase, tranSelectedEntity?: Entity, deletedLineIds?: ID[], addedLines?: TransactionDetailLineItemData[]) => Partial<TransactionPayload>;
22
- export declare const toNewTransactionLine: (item: TransactionDetailLineItemData) => Line;
18
+ export declare const toTransactionUpdatePayload: (updates: TransactionUpdates, detail: SupportedTransaction, cotTransactionTracking: COTTransactionTracking, isAccountingProjectsEnabled: boolean, vendorUpdates?: VendorBase, customerUpdates?: CustomerBase, tranSelectedEntity?: Entity) => Partial<TransactionPayload>;