@zeniai/client-epic-state 5.2.75 → 5.2.76-betaNB1

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 (47) hide show
  1. package/lib/commonStateTypes/common.d.ts +3 -0
  2. package/lib/commonStateTypes/common.js +10 -1
  3. package/lib/entity/reconciliationReport/reconciliationReportPayload.d.ts +124 -0
  4. package/lib/entity/reconciliationReport/reconciliationReportPayload.js +2 -0
  5. package/lib/entity/reconciliationReport/reconciliationReportReducer.d.ts +7 -0
  6. package/lib/entity/reconciliationReport/reconciliationReportReducer.js +173 -0
  7. package/lib/entity/reconciliationReport/reconciliationReportSelector.d.ts +3 -0
  8. package/lib/entity/reconciliationReport/reconciliationReportSelector.js +10 -0
  9. package/lib/entity/reconciliationReport/reconciliationReportState.d.ts +133 -0
  10. package/lib/entity/reconciliationReport/reconciliationReportState.js +15 -0
  11. package/lib/epic.d.ts +2 -1
  12. package/lib/epic.js +2 -0
  13. package/lib/esm/commonStateTypes/common.js +8 -0
  14. package/lib/esm/entity/reconciliationReport/reconciliationReportPayload.js +1 -0
  15. package/lib/esm/entity/reconciliationReport/reconciliationReportReducer.js +168 -0
  16. package/lib/esm/entity/reconciliationReport/reconciliationReportSelector.js +4 -0
  17. package/lib/esm/entity/reconciliationReport/reconciliationReportState.js +10 -0
  18. package/lib/esm/epic.js +2 -0
  19. package/lib/esm/index.js +5 -2
  20. package/lib/esm/reducer.js +7 -1
  21. package/lib/esm/view/companyTaskManagerView/epics/fetchCompanyTaskManagerViewEpic.js +140 -9
  22. package/lib/esm/view/reconciliationReportView/epic/fetchReconciliationReportEpic.js +29 -0
  23. package/lib/esm/view/reconciliationReportView/reconciliationReportViewPayload.js +1 -0
  24. package/lib/esm/view/reconciliationReportView/reconciliationReportViewReducer.js +44 -0
  25. package/lib/esm/view/reconciliationReportView/reconciliationReportViewSelector.js +10 -0
  26. package/lib/esm/view/reconciliationReportView/reconciliationReportViewState.js +1 -0
  27. package/lib/esm/view/taskManager/taskListView/taskListSelector.js +70 -19
  28. package/lib/index.d.ts +6 -2
  29. package/lib/index.js +40 -34
  30. package/lib/reducer.d.ts +2 -0
  31. package/lib/reducer.js +7 -1
  32. package/lib/rootStateTypes.d.ts +5 -1
  33. package/lib/view/companyTaskManagerView/epics/fetchCompanyTaskManagerViewEpic.d.ts +1 -1
  34. package/lib/view/companyTaskManagerView/epics/fetchCompanyTaskManagerViewEpic.js +140 -9
  35. package/lib/view/reconciliationReportView/epic/fetchReconciliationReportEpic.d.ts +19 -0
  36. package/lib/view/reconciliationReportView/epic/fetchReconciliationReportEpic.js +33 -0
  37. package/lib/view/reconciliationReportView/reconciliationReportViewPayload.d.ts +3 -0
  38. package/lib/view/reconciliationReportView/reconciliationReportViewPayload.js +2 -0
  39. package/lib/view/reconciliationReportView/reconciliationReportViewReducer.d.ts +13 -0
  40. package/lib/view/reconciliationReportView/reconciliationReportViewReducer.js +48 -0
  41. package/lib/view/reconciliationReportView/reconciliationReportViewSelector.d.ts +9 -0
  42. package/lib/view/reconciliationReportView/reconciliationReportViewSelector.js +13 -0
  43. package/lib/view/reconciliationReportView/reconciliationReportViewState.d.ts +4 -0
  44. package/lib/view/reconciliationReportView/reconciliationReportViewState.js +2 -0
  45. package/lib/view/taskManager/taskListView/taskListSelector.d.ts +13 -2
  46. package/lib/view/taskManager/taskListView/taskListSelector.js +70 -19
  47. package/package.json +1 -1
package/lib/reducer.d.ts CHANGED
@@ -139,6 +139,7 @@ declare const reducers: import("redux").Reducer<import("redux").CombinedState<{
139
139
  profitAndLossState: import("./view/profitAndLoss/profitAndLossState").ProfitAndLossWithForecastState;
140
140
  projectListState: import("./view/projectList/projectListState").ProjectListState;
141
141
  realTimeApprovalState: import("./view/spendManagement/realTimeApprovalView/realTimeApprovalState").RealTimeApprovalState;
142
+ reconciliationReportViewState: import("./view/reconciliationReportView/reconciliationReportViewState").ReconciliationReportViewState;
142
143
  referralViewState: import(".").ReferralViewState;
143
144
  reimbursementCardState: import("./view/reimbursementCard/reimbursementCardState").ReimbursementCardState;
144
145
  reimbursementConfigState: import("./view/spendManagement/reimbursement/reimbursementConfig/reimbursementConfigState").ReimbursementConfigState;
@@ -249,6 +250,7 @@ declare const reducers: import("redux").Reducer<import("redux").CombinedState<{
249
250
  notificationState: import("./entity/notification/notificationState").NotificationState;
250
251
  onboardingCustomerState: import("./entity/onboardingCustomer/onboardingCustomerState").OnboardingCustomerState;
251
252
  paymentInstrumentState: import("./entity/paymentInstrument/paymentInstrument").PaymentInstrumentState;
253
+ reconciliationReportState: import("./entity/reconciliationReport/reconciliationReportState").ReconciliationReportState;
252
254
  recurringBillState: import("./entity/billPay/recurringBills/recurringBillsState").RecurringBillState;
253
255
  reimbursementState: import("./entity/reimbursement/reimbursementState").ReimbursementState;
254
256
  sectionAccountsViewState: import("./entity/sectionAccountsView/sectionAccountsViewState").SectionAccountsViewState;
package/lib/reducer.js CHANGED
@@ -77,10 +77,10 @@ const couponReducer_1 = __importStar(require("./entity/invoicing/coupon/couponRe
77
77
  const creditNoteReducer_1 = __importStar(require("./entity/invoicing/creditNote/creditNoteReducer"));
78
78
  const dunningCaseReducer_1 = __importStar(require("./entity/invoicing/dunningCase/dunningCaseReducer"));
79
79
  const invoiceReducer_1 = __importStar(require("./entity/invoicing/invoice/invoiceReducer"));
80
+ const invoicingCatalogReducer_1 = __importStar(require("./entity/invoicing/invoicingCatalog/invoicingCatalogReducer"));
80
81
  const invoicingCustomerReducer_1 = __importStar(require("./entity/invoicing/invoicingCustomer/invoicingCustomerReducer"));
81
82
  const invoicingSubscriptionReducer_1 = __importStar(require("./entity/invoicing/invoicingSubscription/invoicingSubscriptionReducer"));
82
83
  const invoicingTransactionReducer_1 = __importStar(require("./entity/invoicing/invoicingTransaction/invoicingTransactionReducer"));
83
- const invoicingCatalogReducer_1 = __importStar(require("./entity/invoicing/invoicingCatalog/invoicingCatalogReducer"));
84
84
  const jeSchedulesReducer_1 = __importStar(require("./entity/jeSchedules/jeSchedulesReducer"));
85
85
  const merchantReducer_1 = __importStar(require("./entity/merchant/merchantReducer"));
86
86
  const monthEndCloseChecksReducer_1 = __importStar(require("./entity/monthEndCloseChecks/monthEndCloseChecksReducer"));
@@ -91,6 +91,7 @@ const paymentAccountReducer_1 = __importStar(require("./entity/paymentAccount/pa
91
91
  const paymentInstrumentReducer_1 = __importStar(require("./entity/paymentInstrument/paymentInstrumentReducer"));
92
92
  const accountingSummaryReducer_1 = __importStar(require("./entity/portfolio/accountingSummary/accountingSummaryReducer"));
93
93
  const projectReducer_1 = __importStar(require("./entity/project/projectReducer"));
94
+ const reconciliationReportReducer_1 = __importStar(require("./entity/reconciliationReport/reconciliationReportReducer"));
94
95
  const reimbursementReducer_1 = __importStar(require("./entity/reimbursement/reimbursementReducer"));
95
96
  const sectionAccountsViewReducer_1 = __importStar(require("./entity/sectionAccountsView/sectionAccountsViewReducer"));
96
97
  const sectionClassesViewReducer_1 = __importStar(require("./entity/sectionClassesViewV2/sectionClassesViewReducer"));
@@ -218,6 +219,7 @@ const profitAndLossClassesViewReducer_1 = __importStar(require("./view/profitAnd
218
219
  const profitAndLossProjectViewReducer_1 = __importStar(require("./view/profitAndLossProjectView/profitAndLossProjectViewReducer"));
219
220
  const projectListReducer_1 = __importStar(require("./view/projectList/projectListReducer"));
220
221
  const recommendationReducer_1 = __importStar(require("./view/recommendation/recommendationReducer"));
222
+ const reconciliationReportViewReducer_1 = __importStar(require("./view/reconciliationReportView/reconciliationReportViewReducer"));
221
223
  const referralReducer_1 = __importStar(require("./view/referralView/referralReducer"));
222
224
  const reimbursementCardReducer_1 = __importStar(require("./view/reimbursementCard/reimbursementCardReducer"));
223
225
  const reportUIOptionsReducer_1 = __importStar(require("./view/reportUIOptions/reportUIOptionsReducer"));
@@ -364,6 +366,7 @@ const initialEntitiesState = {
364
366
  onboardingCustomerState: onboardingCustomerReducer_1.initialState,
365
367
  paymentAccountState: paymentAccountReducer_1.initialState,
366
368
  paymentInstrumentState: paymentInstrumentReducer_1.initialState,
369
+ reconciliationReportState: reconciliationReportReducer_1.initialState,
367
370
  recurringBillState: recurringBillsReducer_1.initialState,
368
371
  reimbursementConfigState: reimbursementConfigReducer_1.initialState,
369
372
  reimbursementState: reimbursementReducer_1.initialState,
@@ -532,6 +535,7 @@ const initialViewsState = {
532
535
  profitAndLossState: profitAndLossReducer_1.initialState,
533
536
  projectListState: projectListReducer_1.initialState,
534
537
  realTimeApprovalState: realTimeApprovalReducer_1.initialState,
538
+ reconciliationReportViewState: reconciliationReportViewReducer_1.initialState,
535
539
  referralViewState: referralReducer_1.initialState,
536
540
  reimbursementCardState: reimbursementCardReducer_1.initialState,
537
541
  reimbursementConfigState: reimbursementConfigReducer_1.initialState,
@@ -650,6 +654,7 @@ const entityReducers = {
650
654
  onboardingCustomerState: onboardingCustomerReducer_1.default,
651
655
  paymentAccountState: paymentAccountReducer_1.default,
652
656
  paymentInstrumentState: paymentInstrumentReducer_1.default,
657
+ reconciliationReportState: reconciliationReportReducer_1.default,
653
658
  recurringBillState: recurringBillsReducer_1.default,
654
659
  reimbursementConfigState: reimbursementConfigReducer_1.default,
655
660
  reimbursementState: reimbursementReducer_1.default,
@@ -818,6 +823,7 @@ const viewReducers = {
818
823
  profitAndLossState: profitAndLossReducer_1.default,
819
824
  projectListState: projectListReducer_1.default,
820
825
  realTimeApprovalState: realTimeApprovalReducer_1.default,
826
+ reconciliationReportViewState: reconciliationReportViewReducer_1.default,
821
827
  referralViewState: referralReducer_1.default,
822
828
  reimbursementCardState: reimbursementCardReducer_1.default,
823
829
  reimbursementConfigState: reimbursementConfigReducer_1.default,
@@ -37,10 +37,10 @@ import { InvoicingCouponState } from './entity/invoicing/coupon/couponState';
37
37
  import { InvoicingCreditNoteState } from './entity/invoicing/creditNote/creditNoteState';
38
38
  import { InvoicingDunningCaseState } from './entity/invoicing/dunningCase/dunningCaseState';
39
39
  import { InvoiceState as InvoicingInvoiceState } from './entity/invoicing/invoice/invoiceState';
40
+ import { InvoicingCatalogState } from './entity/invoicing/invoicingCatalog/invoicingCatalogState';
40
41
  import { InvoicingCustomerState } from './entity/invoicing/invoicingCustomer/invoicingCustomerState';
41
42
  import { InvoicingSubscriptionState } from './entity/invoicing/invoicingSubscription/invoicingSubscriptionState';
42
43
  import { InvoicingTransactionState } from './entity/invoicing/invoicingTransaction/invoicingTransactionState';
43
- import { InvoicingCatalogState } from './entity/invoicing/invoicingCatalog/invoicingCatalogState';
44
44
  import { JESchedulesState } from './entity/jeSchedules/jeSchedulesState';
45
45
  import { MerchantState } from './entity/merchant/merchant';
46
46
  import { MonthEndCloseChecksState } from './entity/monthEndCloseChecks/monthEndCloseChecksState';
@@ -51,6 +51,7 @@ import { PaymentAccountState } from './entity/paymentAccount/paymentAccountState
51
51
  import { PaymentInstrumentState } from './entity/paymentInstrument/paymentInstrument';
52
52
  import { AccountingSummaryState } from './entity/portfolio/accountingSummary/accountingSummaryState';
53
53
  import { ProjectState } from './entity/project/projectState';
54
+ import { ReconciliationReportState } from './entity/reconciliationReport/reconciliationReportState';
54
55
  import { ReimbursementState } from './entity/reimbursement/reimbursementState';
55
56
  import { SectionAccountsViewState } from './entity/sectionAccountsView/sectionAccountsViewState';
56
57
  import { SectionClassesViewStateV2 } from './entity/sectionClassesViewV2/sectionClassesViewState';
@@ -176,6 +177,7 @@ import { ProfitAndLossClassesViewState } from './view/profitAndLossClassesView/p
176
177
  import { ProfitAndLossProjectViewState } from './view/profitAndLossProjectView/profitAndLossProjectViewState';
177
178
  import { ProjectListState } from './view/projectList/projectListState';
178
179
  import { EntityRecommendationState } from './view/recommendation/recommendationState';
180
+ import { ReconciliationReportViewState } from './view/reconciliationReportView/reconciliationReportViewState';
179
181
  import { ReferralViewState } from './view/referralView/referralState';
180
182
  import { ReimbursementCardState } from './view/reimbursementCard/reimbursementCardState';
181
183
  import { ReportUIOptionsState } from './view/reportUIOptions/reportUIOptionsState';
@@ -321,6 +323,7 @@ export type EntitiesState = {
321
323
  paymentAccountState: PaymentAccountState;
322
324
  paymentInstrumentState: PaymentInstrumentState;
323
325
  projectState: ProjectState;
326
+ reconciliationReportState: ReconciliationReportState;
324
327
  recurringBillState: RecurringBillState;
325
328
  reimbursementConfigState: ReimbursementConfigState;
326
329
  reimbursementState: ReimbursementState;
@@ -489,6 +492,7 @@ export type ViewsState = {
489
492
  profitAndLossState: ProfitAndLossWithForecastState;
490
493
  projectListState: ProjectListState;
491
494
  realTimeApprovalState: RealTimeApprovalState;
495
+ reconciliationReportViewState: ReconciliationReportViewState;
492
496
  referralViewState: ReferralViewState;
493
497
  reimbursementCardState: ReimbursementCardState;
494
498
  reimbursementConfigState: ReimbursementConfigState;
@@ -6,4 +6,4 @@ import { RootState } from '../../../rootStateTypes';
6
6
  import { ZeniAPI } from '../../../zeniAPI';
7
7
  import { fetchCompanyTaskManagerView, updateCompanyTaskManagerViewOnFailure, updateCompanyTaskManagerViewOnSuccess } from '../companyTaskManagerViewReducer';
8
8
  export type ActionType = ReturnType<typeof fetchCompanyTaskManagerView> | ReturnType<typeof updateCompanyTaskManagerViewOnSuccess> | ReturnType<typeof updateTasks> | ReturnType<typeof updateTags> | ReturnType<typeof updateCompanyTaskManagerViewOnFailure>;
9
- export declare const fetchCompanyTaskManagerViewEpic: (actions$: ActionsObservable<ActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
9
+ export declare const fetchCompanyTaskManagerViewEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
@@ -7,19 +7,41 @@ const sortOrderPayload_1 = require("../../../commonPayloadTypes/sortOrderPayload
7
7
  const tagReducer_1 = require("../../../entity/tag/tagReducer");
8
8
  const taskReducer_1 = require("../../../entity/task/taskReducer");
9
9
  const responsePayload_1 = require("../../../responsePayload");
10
+ const zeniDayJS_1 = require("../../../zeniDayJS");
10
11
  const companyTaskManagerViewReducer_1 = require("../companyTaskManagerViewReducer");
11
12
  const DEFAULT_PAGE_SIZE = 100;
12
- const fetchCompanyTaskManagerViewEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(companyTaskManagerViewReducer_1.fetchCompanyTaskManagerView.match), (0, operators_1.switchMap)((action) => {
13
+ // Mutates the accumulator rather than spreading it: spreading rebuilds the whole
14
+ // map on every entry, which is O(n^2) over a tenant's tag list.
15
+ const toTagNameByID = (state) => Object.entries(state.tagState.tagByID).reduce((result, [tagId, tag]) => {
16
+ const name = tag?.name;
17
+ if (name != null && name !== '') {
18
+ result[tagId] = name;
19
+ }
20
+ return result;
21
+ }, {});
22
+ const hasTagCategory = (filters) => (filters?.categories ?? []).some((category) => category.field === 'tag');
23
+ const fetchCompanyTaskManagerViewEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(companyTaskManagerViewReducer_1.fetchCompanyTaskManagerView.match), (0, operators_1.switchMap)((action) => {
13
24
  const { from: fromOffset, searchString, sortKey, sortOrder, filters, } = action.payload;
14
25
  const queryValue = {
15
26
  size: DEFAULT_PAGE_SIZE,
16
27
  from: fromOffset,
17
28
  global_search: searchString ?? '',
29
+ // TasksEsSearch defaults this to true, which AND-injects an
30
+ // `assignees = <caller>` filter. Cockpit's task list is a cross-tenant
31
+ // view grouped by company (and offers an Assignee filter), so it must
32
+ // NOT be scoped to the operator — otherwise every category filter
33
+ // AND's down to their own tasks and returns nothing. The metrics panel
34
+ // deliberately passes `true`; this list deliberately passes `false`.
35
+ is_filter_by_logged_in_user: false,
18
36
  sort_by: toSortKeyPayload(sortKey),
19
37
  sort_order: (0, sortOrderPayload_1.getSortOrder)(sortOrder),
20
38
  filter_join: filters?.categoryCombinationOperator === 'AND' ? 'and' : 'or',
21
39
  ...(filters?.categories != null && filters.categories.length > 0
22
- ? { filter_by: toFilterByPayload(filters) }
40
+ ? {
41
+ // Only walk the tag map when a tag filter is actually in play;
42
+ // otherwise every dispatch pays for a map nothing reads.
43
+ filter_by: toFilterByPayload(filters, hasTagCategory(filters) ? toTagNameByID(state$.value) : {}),
44
+ }
23
45
  : {}),
24
46
  task_group_scopes: filters?.taskGroupScopes != null && filters.taskGroupScopes.length > 0
25
47
  ? filters.taskGroupScopes
@@ -67,14 +89,123 @@ const toSortKeyPayload = (sortKey) => {
67
89
  return sortKey;
68
90
  }
69
91
  };
70
- const toFilterByPayload = (filters) => {
92
+ // Cockpit filter-category keys are UI identifiers; the ES index uses its own
93
+ // field names (see TasksEsSearch.get). Anything not listed here already matches
94
+ // the contract (assignees, priority, status, company_id).
95
+ const ES_FIELD_BY_CATEGORY = {
96
+ creationDate: 'create_time',
97
+ dueDate: 'due_date',
98
+ tag: 'tags',
99
+ };
100
+ // ES rejects `is` / `is_not` on date fields — they only accept `between`, whose
101
+ // values are the [start, end] pair the dateRange picker already emits.
102
+ const ES_DATE_FIELDS = new Set(['create_time', 'due_date']);
103
+ // The cockpit date picker hands over ZeniDate objects; once filters have round-
104
+ // tripped through redux they can arrive as ISO or date-only strings instead.
105
+ // Both have to reach ES as instants: `create_time`/`update_time` carry a real
106
+ // timestamp, so a date-only upper bound lands on midnight and drops everything
107
+ // created later that day — a single-day Created filter would return almost
108
+ // nothing, which is the empty state this epic exists to fix.
109
+ // A real check rather than `value as ZeniDate`: the cast would silently lie
110
+ // about a raw Date, a number, or anything else redux hands back, leaving the
111
+ // runtime guard as the only thing standing between us and a crash.
112
+ const isZeniDateLike = (value) => value != null &&
113
+ typeof value.isValid === 'function' &&
114
+ typeof value.format === 'function';
115
+ const CALENDAR_DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
116
+ const toDateBound = (value, edge) => {
117
+ // A bare `YYYY-MM-DD` carries no instant to misread — use it verbatim. This
118
+ // is the only genuinely timezone-proof shape, which is why it is worth a
119
+ // fast path of its own.
120
+ if (typeof value === 'string' && CALENDAR_DATE_ONLY.test(value)) {
121
+ return edge === 'start'
122
+ ? `${value}T00:00:00.000Z`
123
+ : `${value}T23:59:59.999Z`;
124
+ }
125
+ // Everything else came from the picker, and the picker emits LOCAL midnight:
126
+ // `ZeniDatePicker` hands react-datepicker's local-midnight Date to
127
+ // `zeniDate(date.toISOString())`. So the instant encodes "midnight on the day
128
+ // the user clicked, in the user's zone" — and the day they clicked is
129
+ // recovered by reading it locally, never in UTC.
130
+ //
131
+ // Reading it in UTC subtracts the offset for every UTC+ operator: clicking
132
+ // "Mar 4" in Asia/Kolkata stores 2026-03-03T18:30:00Z, which is the 3rd in
133
+ // UTC. A single-day filter then returns the wrong day's tasks rather than
134
+ // none, and US-based testing never sees it.
135
+ const parsed = typeof value === 'string' ? (0, zeniDayJS_1.date)(value) : value;
136
+ if (!isZeniDateLike(parsed) || !parsed.isValid()) {
137
+ // Drop the row rather than send garbage: ES rejects the whole request on
138
+ // one bad bound, taking the other filters down with it.
139
+ return '';
140
+ }
141
+ const ymd = parsed.format('YYYY-MM-DD');
142
+ return edge === 'start' ? `${ymd}T00:00:00.000Z` : `${ymd}T23:59:59.999Z`;
143
+ };
144
+ const toFilterByPayload = (filters, tagNameByID) => {
71
145
  if (filters.categories == null) {
72
146
  return [];
73
147
  }
74
- return filters.categories.map((category) => ({
75
- field: category.field ?? '',
76
- operator: category.matchingOperator === 'equal' ? 'is' : 'is_not',
77
- values: category.values.map((v) => String(v)),
78
- join: category.valuesCombinationOperator === 'ALL' ? 'and' : 'or',
79
- }));
148
+ return filters.categories.flatMap((category) => {
149
+ const categoryField = category.field ?? '';
150
+ const field = ES_FIELD_BY_CATEGORY[categoryField] ?? categoryField;
151
+ // The dropdown is keyed by tagId, but ES matches `tags` on the tag NAME,
152
+ // so resolve through the tag entity this epic itself populates. Unknown ids
153
+ // fall through unchanged rather than being dropped.
154
+ const isDateField = ES_DATE_FIELDS.has(field);
155
+ // `between` is exactly [from, to]. A half-filled picker (one value) makes ES
156
+ // reject the query outright, and a longer array would quietly bind extras to
157
+ // `end` — both land the user back on an unexplained empty page, which is the
158
+ // failure this epic exists to remove. Drop the row instead.
159
+ if (isDateField && category.values.length !== 2) {
160
+ return [];
161
+ }
162
+ const values = category.values.map((value, index) => {
163
+ if (isDateField) {
164
+ // [from, to] — widen the upper bound to the end of its day.
165
+ return toDateBound(value, index === 0 ? 'start' : 'end');
166
+ }
167
+ const raw = String(value);
168
+ if (field !== 'tags') {
169
+ return raw;
170
+ }
171
+ // An id we cannot resolve would reach ES verbatim and match nothing —
172
+ // another silent empty page. Can happen when a filter is hydrated from the
173
+ // URL before `updateTags` has populated `tagByID`, so keep the value
174
+ // (dropping it would widen the result set) but make it visible in logs.
175
+ const tagName = tagNameByID[raw];
176
+ if (tagName == null) {
177
+ console.debug(`[taskManager] unresolved tagId "${raw}" sent to ES verbatim; expect no matches`);
178
+ }
179
+ return tagName ?? raw;
180
+ });
181
+ // `toDateBound` returns '' for a value it cannot parse. Honour that here:
182
+ // emitting a `between` with an empty bound fails the whole ES query, which
183
+ // takes every OTHER filter in the same request down with it — the silent
184
+ // empty page this epic exists to remove, from one unparseable value that a
185
+ // URL-hydrated filter can supply.
186
+ if (isDateField && values.some((value) => value === '')) {
187
+ return [];
188
+ }
189
+ // ES has no date-exclusion operator: `is`/`is_not` are rejected on date
190
+ // fields, and `between` can only select a range, never exclude one. The
191
+ // operator dropdown still offers "is not" for every category, so an excluded
192
+ // date range would otherwise be sent as a plain `between` — returning exactly
193
+ // the rows the user asked to hide. Drop the row instead: a superset is
194
+ // wrong-but-obvious, an inverted result is wrong-and-invisible.
195
+ if (isDateField && category.matchingOperator !== 'equal') {
196
+ return [];
197
+ }
198
+ return [
199
+ {
200
+ field,
201
+ operator: isDateField
202
+ ? 'between'
203
+ : category.matchingOperator === 'equal'
204
+ ? 'is'
205
+ : 'is_not',
206
+ values,
207
+ join: category.valuesCombinationOperator === 'ALL' ? 'and' : 'or',
208
+ },
209
+ ];
210
+ });
80
211
  };
@@ -0,0 +1,19 @@
1
+ import { ActionsObservable, StateObservable } from 'redux-observable';
2
+ import { updateReconciliationReport } from '../../../entity/reconciliationReport/reconciliationReportReducer';
3
+ import { RootState } from '../../../rootStateTypes';
4
+ import { ZeniAPI } from '../../../zeniAPI';
5
+ import { fetchReconciliationReport, fetchReconciliationReportFailure, fetchReconciliationReportSuccess } from '../reconciliationReportViewReducer';
6
+ export type ActionType = ReturnType<typeof fetchReconciliationReport> | ReturnType<typeof updateReconciliationReport> | ReturnType<typeof fetchReconciliationReportSuccess> | ReturnType<typeof fetchReconciliationReportFailure>;
7
+ export declare const fetchReconciliationReportEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => import("rxjs").Observable<{
8
+ payload: import("../../../entity/reconciliationReport/reconciliationReportPayload").ReconciliationReportPayload;
9
+ type: "reconciliationReport/updateReconciliationReport";
10
+ } | {
11
+ payload: string;
12
+ type: "reconciliationReportView/fetchReconciliationReportSuccess";
13
+ } | {
14
+ payload: {
15
+ reconciliationId: import("../../..").ID;
16
+ status: import("../../../zeniAPIStatus").ZeniAPIStatus;
17
+ };
18
+ type: "reconciliationReportView/fetchReconciliationReportFailure";
19
+ }>;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchReconciliationReportEpic = void 0;
4
+ const rxjs_1 = require("rxjs");
5
+ const operators_1 = require("rxjs/operators");
6
+ const reconciliationReportReducer_1 = require("../../../entity/reconciliationReport/reconciliationReportReducer");
7
+ const reconciliationReportSelector_1 = require("../../../entity/reconciliationReport/reconciliationReportSelector");
8
+ const responsePayload_1 = require("../../../responsePayload");
9
+ const reconciliationReportViewReducer_1 = require("../reconciliationReportViewReducer");
10
+ const fetchReconciliationReportEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(reconciliationReportViewReducer_1.fetchReconciliationReport.match), (0, operators_1.switchMap)((action) => {
11
+ const { reconciliationId, cacheOverride } = action.payload;
12
+ const cachedReport = (0, reconciliationReportSelector_1.getReconciliationReportByReconciliationId)(state$.value.reconciliationReportState, reconciliationId);
13
+ if (cacheOverride === true || cachedReport == null) {
14
+ return zeniAPI
15
+ .getJSON(`${zeniAPI.apiEndPoints.reconciliationMicroServiceBaseUrl}/2.0/reconciliation/${reconciliationId}/report`)
16
+ .pipe((0, operators_1.mergeMap)((response) => {
17
+ if ((0, responsePayload_1.isSuccessResponse)(response) === true &&
18
+ response.data != null) {
19
+ return (0, rxjs_1.of)((0, reconciliationReportReducer_1.updateReconciliationReport)(response.data), (0, reconciliationReportViewReducer_1.fetchReconciliationReportSuccess)(reconciliationId));
20
+ }
21
+ return (0, rxjs_1.of)((0, reconciliationReportViewReducer_1.fetchReconciliationReportFailure)({
22
+ reconciliationId,
23
+ status: response.status,
24
+ }));
25
+ }), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, reconciliationReportViewReducer_1.fetchReconciliationReportFailure)({
26
+ reconciliationId,
27
+ status: (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Fetch Reconciliation Report REST API call errored out' +
28
+ JSON.stringify(error)),
29
+ }))));
30
+ }
31
+ return (0, rxjs_1.of)((0, reconciliationReportViewReducer_1.fetchReconciliationReportSuccess)(reconciliationId));
32
+ }));
33
+ exports.fetchReconciliationReportEpic = fetchReconciliationReportEpic;
@@ -0,0 +1,3 @@
1
+ import { ReconciliationReportPayload } from '../../entity/reconciliationReport/reconciliationReportPayload';
2
+ import { ZeniAPIResponse } from '../../responsePayload';
3
+ export type ReconciliationReportResponse = ZeniAPIResponse<ReconciliationReportPayload>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ import { ID } from '../../commonStateTypes/common';
2
+ import { ZeniAPIStatus } from '../../responsePayload';
3
+ import { ReconciliationReportViewState } from './reconciliationReportViewState';
4
+ export declare const initialState: ReconciliationReportViewState;
5
+ export declare const fetchReconciliationReport: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[reconciliationId: string, cacheOverride?: any], {
6
+ reconciliationId: string;
7
+ cacheOverride: any;
8
+ }, "reconciliationReportView/fetchReconciliationReport", never, never>, fetchReconciliationReportSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "reconciliationReportView/fetchReconciliationReportSuccess">, fetchReconciliationReportFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
9
+ reconciliationId: ID;
10
+ status: ZeniAPIStatus;
11
+ }, "reconciliationReportView/fetchReconciliationReportFailure">;
12
+ declare const _default: import("redux").Reducer<ReconciliationReportViewState>;
13
+ export default _default;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var _a;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.fetchReconciliationReportFailure = exports.fetchReconciliationReportSuccess = exports.fetchReconciliationReport = exports.initialState = void 0;
5
+ const toolkit_1 = require("@reduxjs/toolkit");
6
+ const rootActions_1 = require("../../rootActions");
7
+ exports.initialState = {
8
+ fetchReconciliationReportState: {},
9
+ };
10
+ const reconciliationReportView = (0, toolkit_1.createSlice)({
11
+ name: 'reconciliationReportView',
12
+ initialState: exports.initialState,
13
+ reducers: {
14
+ fetchReconciliationReport: {
15
+ prepare(reconciliationId, cacheOverride = false) {
16
+ return { payload: { reconciliationId, cacheOverride } };
17
+ },
18
+ reducer(draft, action) {
19
+ const { reconciliationId } = action.payload;
20
+ draft.fetchReconciliationReportState[reconciliationId] = {
21
+ fetchState: 'In-Progress',
22
+ error: undefined,
23
+ };
24
+ },
25
+ },
26
+ fetchReconciliationReportSuccess(draft, action) {
27
+ const reconciliationId = action.payload;
28
+ draft.fetchReconciliationReportState[reconciliationId] = {
29
+ fetchState: 'Completed',
30
+ error: undefined,
31
+ };
32
+ },
33
+ fetchReconciliationReportFailure(draft, action) {
34
+ const { reconciliationId, status } = action.payload;
35
+ draft.fetchReconciliationReportState[reconciliationId] = {
36
+ fetchState: 'Error',
37
+ error: status,
38
+ };
39
+ },
40
+ },
41
+ extraReducers: (builder) => {
42
+ builder.addCase(rootActions_1.clearAll, (draft) => {
43
+ Object.assign(draft, exports.initialState);
44
+ });
45
+ },
46
+ });
47
+ _a = reconciliationReportView.actions, exports.fetchReconciliationReport = _a.fetchReconciliationReport, exports.fetchReconciliationReportSuccess = _a.fetchReconciliationReportSuccess, exports.fetchReconciliationReportFailure = _a.fetchReconciliationReportFailure;
48
+ exports.default = reconciliationReportView.reducer;
@@ -0,0 +1,9 @@
1
+ import { FetchState, ID } from '../../commonStateTypes/common';
2
+ import { ReconciliationReport } from '../../entity/reconciliationReport/reconciliationReportState';
3
+ import { ZeniAPIStatus } from '../../responsePayload';
4
+ import { RootState } from '../../rootStateTypes';
5
+ export declare function getReconciliationReport(state: RootState, reconciliationId: ID): {
6
+ fetchState: FetchState;
7
+ fetchError?: ZeniAPIStatus;
8
+ report?: ReconciliationReport;
9
+ };
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getReconciliationReport = getReconciliationReport;
4
+ const reconciliationReportSelector_1 = require("../../entity/reconciliationReport/reconciliationReportSelector");
5
+ function getReconciliationReport(state, reconciliationId) {
6
+ const fetchReconciliationReportState = state.reconciliationReportViewState.fetchReconciliationReportState[reconciliationId];
7
+ const report = (0, reconciliationReportSelector_1.getReconciliationReportByReconciliationId)(state.reconciliationReportState, reconciliationId);
8
+ return {
9
+ fetchState: fetchReconciliationReportState?.fetchState ?? 'Not-Started',
10
+ fetchError: fetchReconciliationReportState?.error,
11
+ report,
12
+ };
13
+ }
@@ -0,0 +1,4 @@
1
+ import { FetchStateAndError, ID } from '../../commonStateTypes/common';
2
+ export interface ReconciliationReportViewState {
3
+ fetchReconciliationReportState: Record<ID, FetchStateAndError>;
4
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -38,10 +38,20 @@ export interface TaskListSelectorView extends SelectorView {
38
38
  userGroupList: UserGroupListSelectorView;
39
39
  userList: UserListSelectorView;
40
40
  }
41
+ /**
42
+ * Exactly the parts of `TaskListState` the grouping pipeline reads.
43
+ *
44
+ * `TaskListState` also carries `localData` — the current selection and the
45
+ * group name being typed — which changes on every checkbox click and every
46
+ * keystroke. None of the work below looks at it, so naming the real inputs is
47
+ * what lets the pipeline be memoised against them instead of against the whole
48
+ * slice. `TaskListState` still satisfies this, so callers are unaffected.
49
+ */
50
+ type TaskListGroupingInputs = Pick<TaskListState, 'filters' | 'taskIdsByAssignees' | 'taskIdsByDueDate' | 'taskIdsByGroupsIds' | 'taskIdsByPriority' | 'taskIdsByStatus' | 'taskIdsByTags' | 'uiState'>;
41
51
  export declare const getTaskListGroupedByAssignees: ({ taskListState, taskState, userState, userRoleState, addressState, tagState, userGroupsState, }: {
42
52
  addressState: AddressState;
43
53
  tagState: TagState;
44
- taskListState: TaskListState;
54
+ taskListState: TaskListGroupingInputs;
45
55
  taskState: TaskState;
46
56
  userGroupsState: UserGroupsState;
47
57
  userRoleState: UserRoleState;
@@ -55,7 +65,7 @@ export declare const getTaskListGroupedByAssignees: ({ taskListState, taskState,
55
65
  export declare const getTaskListGroupedByPriority: ({ taskListState, taskState, userState, userRoleState, addressState, tagState, userGroupsState, }: {
56
66
  addressState: AddressState;
57
67
  tagState: TagState;
58
- taskListState: TaskListState;
68
+ taskListState: TaskListGroupingInputs;
59
69
  taskState: TaskState;
60
70
  userGroupsState: UserGroupsState;
61
71
  userRoleState: UserRoleState;
@@ -67,3 +77,4 @@ export declare const getTaskListGroupedByPriority: ({ taskListState, taskState,
67
77
  tasks: TaskWithUserDetails[];
68
78
  }[];
69
79
  export declare const getAllTasks: (state: RootState, isTaskTemplatesEnabled: boolean) => TaskListSelectorView;
80
+ export {};