@aglyn/plugins-crm 1.0.0-beta.199 → 1.0.0-beta.200

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 (105) hide show
  1. package/package.json +13 -13
  2. package/src/lib/components/companies-section.d.ts +6 -6
  3. package/src/lib/components/companies-section.js +54 -84
  4. package/src/lib/components/companies-section.js.map +1 -1
  5. package/src/lib/components/company-edit-drawer.js +17 -4
  6. package/src/lib/components/company-edit-drawer.js.map +1 -1
  7. package/src/lib/components/company-picker.js +6 -2
  8. package/src/lib/components/company-picker.js.map +1 -1
  9. package/src/lib/components/contact-detail-page.js +14 -2
  10. package/src/lib/components/contact-detail-page.js.map +1 -1
  11. package/src/lib/components/contact-list-columns.d.ts +3 -5
  12. package/src/lib/components/contact-list-columns.js +6 -8
  13. package/src/lib/components/contact-list-columns.js.map +1 -1
  14. package/src/lib/components/contacts-bulk-bar.js +10 -1
  15. package/src/lib/components/contacts-bulk-bar.js.map +1 -1
  16. package/src/lib/components/contacts-section.js +115 -163
  17. package/src/lib/components/contacts-section.js.map +1 -1
  18. package/src/lib/components/crm-next-activity-column.d.ts +4 -2
  19. package/src/lib/components/crm-next-activity-column.js +6 -3
  20. package/src/lib/components/crm-next-activity-column.js.map +1 -1
  21. package/src/lib/components/deal-edit-drawer.js +8 -4
  22. package/src/lib/components/deal-edit-drawer.js.map +1 -1
  23. package/src/lib/components/deals-section.d.ts +2 -2
  24. package/src/lib/components/deals-section.js +59 -84
  25. package/src/lib/components/deals-section.js.map +1 -1
  26. package/src/lib/components/lead-campaigns-card.js +11 -3
  27. package/src/lib/components/lead-campaigns-card.js.map +1 -1
  28. package/src/lib/components/lead-properties-card.js +9 -1
  29. package/src/lib/components/lead-properties-card.js.map +1 -1
  30. package/src/lib/components/leads-bulk-bar.js +16 -3
  31. package/src/lib/components/leads-bulk-bar.js.map +1 -1
  32. package/src/lib/components/leads-section.d.ts +2 -1
  33. package/src/lib/components/leads-section.js +110 -148
  34. package/src/lib/components/leads-section.js.map +1 -1
  35. package/src/lib/components/tasks-section.js +128 -121
  36. package/src/lib/components/tasks-section.js.map +1 -1
  37. package/src/lib/constants/company-filters.d.ts +13 -0
  38. package/src/lib/constants/company-filters.js +47 -17
  39. package/src/lib/constants/company-filters.js.map +1 -1
  40. package/src/lib/constants/contact-filters.d.ts +61 -10
  41. package/src/lib/constants/contact-filters.js +373 -141
  42. package/src/lib/constants/contact-filters.js.map +1 -1
  43. package/src/lib/constants/deal-filters.d.ts +44 -0
  44. package/src/lib/constants/deal-filters.js +78 -0
  45. package/src/lib/constants/deal-filters.js.map +1 -0
  46. package/src/lib/hooks/use-crm-list-query.d.ts +68 -0
  47. package/src/lib/hooks/use-crm-list-query.js +182 -0
  48. package/src/lib/hooks/use-crm-list-query.js.map +1 -0
  49. package/src/lib/hooks/use-crm-tasks.d.ts +23 -6
  50. package/src/lib/hooks/use-crm-tasks.js +44 -42
  51. package/src/lib/hooks/use-crm-tasks.js.map +1 -1
  52. package/src/lib/hooks/use-deals.d.ts +2 -34
  53. package/src/lib/hooks/use-deals.js +3 -62
  54. package/src/lib/hooks/use-deals.js.map +1 -1
  55. package/src/lib/model/crm-list-query.d.ts +91 -0
  56. package/src/lib/model/crm-list-query.js +182 -0
  57. package/src/lib/model/crm-list-query.js.map +1 -0
  58. package/src/lib/model/lead-filters.d.ts +49 -43
  59. package/src/lib/model/lead-filters.js +194 -88
  60. package/src/lib/model/lead-filters.js.map +1 -1
  61. package/src/lib/model/list-fields-api.d.ts +26 -0
  62. package/src/lib/model/list-fields-api.js +47 -0
  63. package/src/lib/model/list-fields-api.js.map +1 -0
  64. package/src/lib/model/list-fields.d.ts +47 -0
  65. package/src/lib/model/list-fields.js +39 -0
  66. package/src/lib/model/list-fields.js.map +1 -0
  67. package/src/lib/model/task-views.d.ts +15 -10
  68. package/src/lib/model/task-views.js +68 -9
  69. package/src/lib/model/task-views.js.map +1 -1
  70. package/src/lib/server/companies-import.js +3 -3
  71. package/src/lib/server/companies-import.js.map +1 -1
  72. package/src/lib/server/company-delete.js +3 -1
  73. package/src/lib/server/company-delete.js.map +1 -1
  74. package/src/lib/server/consent-group-participant.js +4 -0
  75. package/src/lib/server/consent-group-participant.js.map +1 -1
  76. package/src/lib/server/contact-update.js +14 -8
  77. package/src/lib/server/contact-update.js.map +1 -1
  78. package/src/lib/server/contacts-import.js +4 -2
  79. package/src/lib/server/contacts-import.js.map +1 -1
  80. package/src/lib/server/deals-import.js +4 -2
  81. package/src/lib/server/deals-import.js.map +1 -1
  82. package/src/lib/server/erase-person.js +2 -1
  83. package/src/lib/server/erase-person.js.map +1 -1
  84. package/src/lib/server/lead-create.js +4 -1
  85. package/src/lib/server/lead-create.js.map +1 -1
  86. package/src/lib/server/lead-source-values.js +9 -5
  87. package/src/lib/server/lead-source-values.js.map +1 -1
  88. package/src/lib/server/leads-import.js +4 -1
  89. package/src/lib/server/leads-import.js.map +1 -1
  90. package/src/lib/server/list-fields-routes.d.ts +29 -0
  91. package/src/lib/server/list-fields-routes.js +85 -0
  92. package/src/lib/server/list-fields-routes.js.map +1 -0
  93. package/src/lib/server/record-email-state.js +5 -2
  94. package/src/lib/server/record-email-state.js.map +1 -1
  95. package/src/lib/server/record-timeline.js +3 -2
  96. package/src/lib/server/record-timeline.js.map +1 -1
  97. package/src/lib/server/task-routes.js +6 -3
  98. package/src/lib/server/task-routes.js.map +1 -1
  99. package/src/lib/server/tasks-import.js +5 -2
  100. package/src/lib/server/tasks-import.js.map +1 -1
  101. package/src/lib/server.js +10 -1
  102. package/src/lib/server.js.map +1 -1
  103. package/src/lib/hooks/use-org-leads.d.ts +0 -50
  104. package/src/lib/hooks/use-org-leads.js +0 -104
  105. package/src/lib/hooks/use-org-leads.js.map +0 -1
@@ -38,9 +38,11 @@ import { refreshCrmNextActivity } from "../model/next-activity-api.js";
38
38
  import { completeCrmTask } from "../model/task-api.js";
39
39
  import { crmTaskCallScope } from "../model/task-routes.js";
40
40
  import { tasksCsv } from "../model/tasks-csv.js";
41
- import { CRM_TASK_KIND_LABELS, CRM_TASK_KINDS, CRM_TASK_PRIORITIES, CRM_TASK_PRIORITY_LABELS, CRM_TASK_VIEW_LIMIT, CRM_TASK_VIEWS } from "../model/task-views.js";
42
- import { matchListFilter } from "@aglyn/shared-ui-jsx/const/list-filter";
43
- import { listFilterGridColumns, listRowMatchesSearch } from "@aglyn/shared-ui-jsx/const/list-grid-filter";
41
+ import { CRM_TASK_KIND_LABELS, CRM_TASK_KINDS, CRM_TASK_PRIORITIES, CRM_TASK_PRIORITY_LABELS, CRM_TASK_VIEWS, TASK_LIST_QUERY_FIELDS } from "../model/task-views.js";
42
+ import { listFilterGridColumns } from "@aglyn/shared-ui-jsx/const/list-grid-filter";
43
+ import { ListPagination } from "@aglyn/shared-ui-jsx/components/list-pagination.component";
44
+ import { TABLE_PAGE_SIZE_DEFAULT } from "@aglyn/shared-ui-jsx/const/table-pagination";
45
+ import ListQueryNotices, { listQueryRefusals } from "@aglyn/shared-ui-jsx/components/list-query-notices.component";
44
46
  import { useListGridFilter } from "@aglyn/shared-ui-jsx/hooks/use-list-grid-filter";
45
47
  import ListFilterChips from "@aglyn/shared-ui-jsx/components/list-filter-chips.component";
46
48
  import { CrmListToolbar } from "./crm-list-toolbar.js";
@@ -52,8 +54,9 @@ import TaskSnoozeMenu from "./task-snooze-menu.js";
52
54
  import TasksBulkBar from "./tasks-bulk-bar.js";
53
55
  /** What an empty view is headed, by view — "nothing overdue" is good news. */ /*
54
56
  * What the tasks grid's panel offers (AGL-3313). `view` is the task view
55
- * the query serves — a hidden column, since it is no field of a task — and
56
- * the rest narrow the rows that view loaded.
57
+ * the query's base answers — a hidden column, since it is no field of a
58
+ * task — and Kind, Priority and Assignee are predicates on the same query
59
+ * (AGL-3321).
57
60
  */ const TASK_FILTER_FIELDS = [
58
61
  {
59
62
  column: 'view',
@@ -63,33 +66,7 @@ import TasksBulkBar from "./tasks-bulk-bar.js";
63
66
  'equals'
64
67
  ]
65
68
  },
66
- {
67
- column: 'kind',
68
- kind: 'exact',
69
- path: 'kind',
70
- operators: [
71
- 'equals',
72
- 'isAnyOf'
73
- ]
74
- },
75
- {
76
- column: 'priority',
77
- kind: 'exact',
78
- path: 'priority',
79
- operators: [
80
- 'equals',
81
- 'isAnyOf'
82
- ]
83
- },
84
- {
85
- column: 'assigneeUid',
86
- kind: 'exact',
87
- path: 'assigneeUid',
88
- operators: [
89
- 'equals',
90
- 'isAnyOf'
91
- ]
92
- }
69
+ ...TASK_LIST_QUERY_FIELDS
93
70
  ];
94
71
  const TASK_FILTER_HEADERS = {
95
72
  view: 'Show',
@@ -100,15 +77,12 @@ const TASK_FILTER_HEADERS = {
100
77
  /** The filter-only `view` column never shows. */ const TASK_HIDDEN_COLUMNS = {
101
78
  view: false
102
79
  };
80
+ /** How many tasks the month view reads: one page, sized for a month of work. */ const CALENDAR_PAGE_SIZE = 200;
103
81
  /** No `view` clause is "My tasks", which the section opened on before views existed. */ const TASK_VIEW_DEFAULT = {
104
82
  field: 'view',
105
83
  op: 'equals',
106
84
  value: 'mine'
107
85
  };
108
- /** What the quick search reads on a task. */ const TASK_SEARCH_FIELDS = [
109
- 'title',
110
- 'notes'
111
- ];
112
86
  const EMPTY_LABEL = {
113
87
  mine: 'Nothing is assigned to you',
114
88
  overdue: 'Nothing is overdue',
@@ -183,9 +157,10 @@ const EMPTY_LABEL = {
183
157
  ]);
184
158
  /*
185
159
  * The grid's own Filters panel and quick search edit the view's clauses
186
- * (AGL-3313). "Show" is the task view the query serves — the hidden
187
- * `view` column, as the toggle stored it, with none meaning "My tasks" —
188
- * and Kind, Priority and Assignee narrow the rows it loaded.
160
+ * (AGL-3313). "Show" is the task view the query's base answers — the
161
+ * hidden `view` column, as the toggle stored it, with none meaning "My
162
+ * tasks" — and Kind, Priority, Assignee and the search word are on the
163
+ * same query (AGL-3321).
189
164
  */ const clauses = useMemo(()=>views.state.filters.some((clause)=>clause.field === 'view') ? views.state.filters : [
190
165
  TASK_VIEW_DEFAULT,
191
166
  ...views.state.filters
@@ -205,14 +180,19 @@ const EMPTY_LABEL = {
205
180
  'assigneeUid'
206
181
  ]
207
182
  });
183
+ const queryClauses = useMemo(()=>clauses.filter((clause)=>clause.field !== 'view'), [
184
+ clauses
185
+ ]);
208
186
  const list = useCrmTaskList({
209
187
  hostId,
210
188
  org: orgRecord,
211
189
  view,
212
190
  uid: user == null ? void 0 : user.uid,
213
- nowMs
191
+ nowMs,
192
+ clauses: queryClauses,
193
+ search: gridFilter.searchWords
214
194
  });
215
- const { tasks: loaded, status, fromCache, truncated, scope, orgId, readTokens } = list;
195
+ const { tasks, status, fromCache, scope, orgId, readTokens } = list;
216
196
  const directory = useOrgMemberDirectory(orgId);
217
197
  const filterOptions = useMemo(()=>({
218
198
  view: CRM_TASK_VIEWS.map((option)=>({
@@ -234,15 +214,16 @@ const EMPTY_LABEL = {
234
214
  }), [
235
215
  directory.members
236
216
  ]);
237
- // Every clause but the served view, and the search, over the loaded rows.
238
- const searchKey = gridFilter.searchWords.join(' ');
239
- const tasks = useMemo(()=>loaded.filter((task)=>clauses.every((clause)=>clause.field === 'view' || matchListFilter(task, TASK_FILTER_FIELDS, clause)) && listRowMatchesSearch(task, TASK_SEARCH_FIELDS, gridFilter.searchWords)), // `searchKey` stands for the words, which are a new array each render.
240
- // eslint-disable-next-line react-hooks/exhaustive-deps
241
- [
242
- loaded,
243
- clauses,
244
- searchKey
217
+ // What the query could not hold, said above the list rather than matched in memory.
218
+ const refused = useMemo(()=>listQueryRefusals(list.plan.refused, {
219
+ fields: TASK_FILTER_FIELDS,
220
+ headers: TASK_FILTER_HEADERS,
221
+ options: filterOptions
222
+ }), [
223
+ list.plan.refused,
224
+ filterOptions
245
225
  ]);
226
+ const filtered = queryClauses.length > 0 || gridFilter.searchWords.some((word)=>word.trim());
246
227
  /*
247
228
  * Every record a task names, not only the one its "For" cell shows: the
248
229
  * export writes the contact, the company and the deal each by name, and
@@ -276,10 +257,12 @@ const EMPTY_LABEL = {
276
257
  records: linked
277
258
  });
278
259
  const [selectedIds, setSelectedIds] = useState([]);
279
- // A view is a different set of rows; a selection made on the last one
280
- // would be a count over rows no longer on screen.
260
+ // A view, a filter or a page is a different set of rows; a selection made
261
+ // on the last one would be a count over rows no longer on screen.
281
262
  useEffect(()=>setSelectedIds([]), [
282
- view
263
+ view,
264
+ list.plan,
265
+ list.page
283
266
  ]);
284
267
  const csvOptions = useMemo(()=>({
285
268
  assigneeEmail: (uid)=>{
@@ -302,6 +285,20 @@ const EMPTY_LABEL = {
302
285
  * same view — switching does not narrow anything and costs no read, so
303
286
  * it is a toggle rather than another saved view.
304
287
  */ const [layout, setLayout] = useState('list');
288
+ /*
289
+ * The month draws one query page, so it asks for a month's worth: the
290
+ * calendar's page is {@link CALENDAR_PAGE_SIZE} tasks of the same view and
291
+ * filters, and it says when the view holds more. The list's own page size
292
+ * comes back with the list.
293
+ */ const { setPage: setListPage, setPageSize: setListPageSize } = list;
294
+ useEffect(()=>{
295
+ setListPage(0);
296
+ setListPageSize(layout === 'calendar' ? CALENDAR_PAGE_SIZE : TABLE_PAGE_SIZE_DEFAULT);
297
+ }, [
298
+ layout,
299
+ setListPage,
300
+ setListPageSize
301
+ ]);
305
302
  const [drawer, setDrawer] = useState({
306
303
  open: false,
307
304
  task: null
@@ -540,7 +537,7 @@ const EMPTY_LABEL = {
540
537
  clauses: clauses,
541
538
  onChange: setClauses,
542
539
  options: filterOptions,
543
- servedField: "view"
540
+ marksServed: false
544
541
  }),
545
542
  /*#__PURE__*/ _jsxs(ToggleButtonGroup, {
546
543
  exclusive: true,
@@ -578,84 +575,94 @@ const EMPTY_LABEL = {
578
575
  })
579
576
  ]
580
577
  }),
578
+ /*#__PURE__*/ _jsx(ListQueryNotices, {
579
+ refused: refused,
580
+ notices: list.plan.notices
581
+ }),
581
582
  status === 'error' ? /*#__PURE__*/ _jsx(Typography, {
582
583
  variant: "body2",
583
584
  color: "error",
584
585
  children: 'The tasks could not be loaded. Reload to try again.'
585
- }) : /*#__PURE__*/ _jsxs(_Fragment, {
586
- children: [
587
- truncated ? /*#__PURE__*/ _jsx(Typography, {
588
- variant: "caption",
589
- color: "text.secondary",
590
- children: `Showing the first ${CRM_TASK_VIEW_LIMIT} — narrow the view to see the rest.`
591
- }) : null,
592
- layout === 'calendar' ? /*#__PURE__*/ _jsx(TasksCalendar, {
593
- tasks: tasks,
594
- truncated: truncated,
595
- onOpen: (task)=>setDrawer({
596
- open: true,
597
- task
598
- })
599
- }) : /*#__PURE__*/ _jsxs(_Fragment, {
600
- children: [
601
- /*#__PURE__*/ _jsx(TasksBulkBar, {
602
- hostId: hostId,
603
- scope: scope,
586
+ }) : /*#__PURE__*/ _jsx(_Fragment, {
587
+ children: layout === 'calendar' ? /*#__PURE__*/ _jsx(TasksCalendar, {
588
+ tasks: tasks,
589
+ truncated: list.hasMore,
590
+ onOpen: (task)=>setDrawer({
591
+ open: true,
592
+ task
593
+ })
594
+ }) : /*#__PURE__*/ _jsxs(_Fragment, {
595
+ children: [
596
+ /*#__PURE__*/ _jsx(TasksBulkBar, {
597
+ hostId: hostId,
598
+ scope: scope,
599
+ rows: tasks,
600
+ selected: selectedIds,
601
+ onSelectedChange: setSelectedIds,
602
+ directory: directory,
603
+ csv: csvOptions
604
+ }),
605
+ /*#__PURE__*/ _jsx(CrmColumnOrderProvider, {
606
+ value: grid.columnOrder,
607
+ children: /*#__PURE__*/ _jsx(ListTable, {
604
608
  rows: tasks,
605
- selected: selectedIds,
606
- onSelectedChange: setSelectedIds,
607
- directory: directory,
608
- csv: csvOptions
609
- }),
610
- /*#__PURE__*/ _jsx(CrmColumnOrderProvider, {
611
- value: grid.columnOrder,
612
- children: /*#__PURE__*/ _jsx(ListTable, {
613
- rows: tasks,
614
- columns: grid.columns,
615
- slots: CRM_LIST_SLOTS,
616
- selectable: {
617
- selected: selectedIds,
618
- onChange: setSelectedIds
619
- },
620
- loading: status === 'loading',
621
- onOpen: (id)=>{
622
- const found = tasks.find((row)=>row.$id === id);
623
- if (found) setDrawer({
624
- open: true,
625
- task: found
626
- });
627
- },
628
- /*
609
+ columns: grid.columns,
610
+ slots: CRM_LIST_SLOTS,
611
+ selectable: {
612
+ selected: selectedIds,
613
+ onChange: setSelectedIds
614
+ },
615
+ loading: status === 'loading',
616
+ onOpen: (id)=>{
617
+ const found = tasks.find((row)=>row.$id === id);
618
+ if (found) setDrawer({
619
+ open: true,
620
+ task: found
621
+ });
622
+ },
623
+ /*
629
624
  * The panel and the search are the grid's; the section
630
625
  * answers them, the view through the query (AGL-3313). An
631
626
  * empty view is said inside the grid rather than instead of
632
627
  * it, so its toolbar stays to choose another view.
633
- */ noRowsLabel: loaded.length ? 'No tasks match these filters' : EMPTY_LABEL[view],
634
- noRowsDescription: loaded.length ? undefined : EMPTY_COPY[view],
635
- noRowsAction: loaded.length ? undefined : /*#__PURE__*/ _jsx(Button, {
636
- size: "small",
637
- variant: "contained",
638
- color: "primary",
639
- onClick: ()=>setDrawer({
640
- open: true,
641
- task: null
642
- }),
643
- children: 'New task'
644
- }),
645
- filterMode: "server",
646
- filterModel: gridFilter.filterModel,
647
- onFilterModelChange: gridFilter.onFilterModelChange,
648
- quickFilter: true,
649
- // Columns and sort are the view's, controlled (AGL-2617).
650
- columnVisibilityModel: grid.columnVisibilityModel,
651
- onColumnVisibilityModelChange: grid.onColumnVisibilityModelChange,
652
- sortModel: grid.sortModel,
653
- onSortModelChange: grid.onSortModelChange
654
- })
628
+ */ noRowsLabel: filtered ? 'No tasks match these filters' : EMPTY_LABEL[view],
629
+ noRowsDescription: filtered ? undefined : EMPTY_COPY[view],
630
+ noRowsAction: filtered ? undefined : /*#__PURE__*/ _jsx(Button, {
631
+ size: "small",
632
+ variant: "contained",
633
+ color: "primary",
634
+ onClick: ()=>setDrawer({
635
+ open: true,
636
+ task: null
637
+ }),
638
+ children: 'New task'
639
+ }),
640
+ filterMode: "server",
641
+ filterModel: gridFilter.filterModel,
642
+ onFilterModelChange: gridFilter.onFilterModelChange,
643
+ quickFilter: true,
644
+ // The view orders the query (due soonest, or Done most
645
+ // recently due), so the grid sorts nothing itself: a
646
+ // sort over one page would reorder ten rows.
647
+ sortingMode: "server",
648
+ disableColumnSorting: true,
649
+ // Columns are the view's, controlled (AGL-2617).
650
+ columnVisibilityModel: grid.columnVisibilityModel,
651
+ onColumnVisibilityModelChange: grid.onColumnVisibilityModelChange,
652
+ // Paged by the footer below, so the grid must not also slice.
653
+ hideFooter: true
655
654
  })
656
- ]
657
- })
658
- ]
655
+ }),
656
+ /*#__PURE__*/ _jsx(ListPagination, {
657
+ page: list.page,
658
+ pageSize: list.pageSize,
659
+ rowCount: tasks.length,
660
+ hasMore: list.hasMore,
661
+ onPageChange: list.setPage,
662
+ onPageSizeChange: list.setPageSize
663
+ })
664
+ ]
665
+ })
659
666
  })
660
667
  ]
661
668
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/tasks-section.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (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 * http://www.apache.org/licenses/LICENSE-2.0\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'use client'\n\nimport {\n type ConsolePluginPageProps,\n CRM_COLLECTIONS,\n type CrmViewFilterClause,\n findOrgMember,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { ListTable } from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport { useCrmSavedView } from '../hooks/use-crm-saved-view'\nimport { useCrmScope } from '../hooks/use-crm-scope'\nimport { useCrmViewGrid } from '../hooks/use-crm-view-grid'\nimport { CRM_LIST_SLOTS, CrmColumnOrderProvider } from './crm-column-menu'\nimport CrmViewsControl from './crm-views-control'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useFirestore, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Button,\n Checkbox,\n Stack,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n} from '@mui/material'\nimport type { GridColDef } from '@mui/x-data-grid'\nimport { deleteField, doc, serverTimestamp, updateDoc } from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useCrmRecordNames } from '../hooks/use-crm-record-names'\nimport { type CrmTaskRow, useCrmTaskList, useNowMs } from '../hooks/use-crm-tasks'\nimport { useOrgMemberDirectory } from '../hooks/use-org-member-directory'\nimport { downloadTextFile } from '../model/contacts-csv'\nimport { crmRoutes } from '../model/crm-routes'\nimport { refreshCrmNextActivity } from '../model/next-activity-api'\nimport { completeCrmTask } from '../model/task-api'\nimport { crmTaskCallScope } from '../model/task-routes'\nimport { type TaskCsvOptions, tasksCsv } from '../model/tasks-csv'\nimport {\n CRM_TASK_KIND_LABELS,\n CRM_TASK_KINDS,\n CRM_TASK_PRIORITIES,\n CRM_TASK_PRIORITY_LABELS,\n CRM_TASK_VIEW_LIMIT,\n CRM_TASK_VIEWS,\n type CrmTaskView,\n} from '../model/task-views'\nimport {\n type ListFilterField,\n matchListFilter,\n} from '@aglyn/shared-ui-jsx/const/list-filter'\nimport { listFilterGridColumns, listRowMatchesSearch } from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport { useListGridFilter } from '@aglyn/shared-ui-jsx/hooks/use-list-grid-filter'\nimport ListFilterChips from '@aglyn/shared-ui-jsx/components/list-filter-chips.component'\nimport { CrmListToolbar } from './crm-list-toolbar'\nimport {\n TaskDueText,\n TaskKindCell,\n TaskPriorityChip,\n TaskRecordLink,\n} from './task-cells'\nimport TaskEditDrawer from './task-edit-drawer'\nimport TasksCalendar from './tasks-calendar'\nimport { TaskImportButton } from './task-import-drawer'\nimport TaskSnoozeMenu from './task-snooze-menu'\nimport TasksBulkBar from './tasks-bulk-bar'\n\n/** What an empty view is headed, by view — \"nothing overdue\" is good news. */\n/*\n * What the tasks grid's panel offers (AGL-3313). `view` is the task view\n * the query serves — a hidden column, since it is no field of a task — and\n * the rest narrow the rows that view loaded.\n */\nconst TASK_FILTER_FIELDS: readonly ListFilterField[] = [\n { column: 'view', kind: 'exact', path: 'view', operators: ['equals'] },\n { column: 'kind', kind: 'exact', path: 'kind', operators: ['equals', 'isAnyOf'] },\n { column: 'priority', kind: 'exact', path: 'priority', operators: ['equals', 'isAnyOf'] },\n { column: 'assigneeUid', kind: 'exact', path: 'assigneeUid', operators: ['equals', 'isAnyOf'] },\n]\nconst TASK_FILTER_HEADERS: Readonly<Record<string, string>> = {\n view: 'Show',\n kind: 'Kind',\n priority: 'Priority',\n assigneeUid: 'Assignee',\n}\n/** The filter-only `view` column never shows. */\nconst TASK_HIDDEN_COLUMNS: Readonly<Record<string, boolean>> = { view: false }\n/** No `view` clause is \"My tasks\", which the section opened on before views existed. */\nconst TASK_VIEW_DEFAULT: CrmViewFilterClause = { field: 'view', op: 'equals', value: 'mine' }\n/** What the quick search reads on a task. */\nconst TASK_SEARCH_FIELDS = ['title', 'notes'] as const\n\nconst EMPTY_LABEL: Record<CrmTaskView, string> = {\n mine: 'Nothing is assigned to you',\n overdue: 'Nothing is overdue',\n today: 'Nothing is due today',\n upcoming: 'Nothing is scheduled beyond today',\n open: 'No open tasks',\n done: 'No completed tasks yet',\n}\n\n/** The one sentence under it, by view. */\nconst EMPTY_COPY: Record<CrmTaskView, string> = {\n mine: 'Tasks you create are yours unless you hand them to someone.',\n overdue: 'Every dated task is on or ahead of schedule.',\n today: 'Nothing on your calendar day is owed to anyone in the CRM.',\n upcoming: 'A task with a due date past today would be listed here.',\n open: 'A task is a call, an email, a meeting or a to-do owed to a contact, a company or a deal.',\n done: 'Tasks ticked off on their record, or here, are kept for the history.',\n}\n\n/**\n * `/crm/tasks` — what the team owes the people in the CRM (AGL-2599).\n *\n * Six views over `orgs/{orgId}/crmTasks`, each a bounded listener on one of\n * the collection's indexes, chosen by a segmented control. A task hangs off\n * a contact, a company or a deal, but it is listed HERE because \"what is due\n * today\" is a question about the team's day and not about any one record;\n * the record pages carry their own `RecordTasksCard` for the other\n * direction.\n *\n * Completing goes through `crm/task-complete`, because completing fires the\n * `taskCompleted` host event and only the server can run a workflow.\n * Reopening is client-direct: undoing a tick has no side effect beyond the\n * document, and the rules gate it like any other CRM write.\n *\n * The rows are selectable, and a selection raises `TasksBulkBar` over the\n * list — Complete and Assign through their routes, the due date and the\n * delete as batched writes (AGL-2621). Export CSV beside the view control\n * writes the view through `tasksCsv()`, naming the assignee and the linked\n * records; the bar writes the same file over the selection.\n */\nexport function TasksSection(props: ConsolePluginPageProps) {\n const { hostId, org, basePath = '' } = props\n const orgRecord = org as Record<string, unknown> | undefined\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const nowMs = useNowMs()\n const routes = useMemo(() => crmRoutes(basePath), [basePath])\n // The viewing group a linked contact is named through, or `null` at the\n // organization level, where each is named through its own holder.\n const { consentGroup } = useCrmScope({ hostId, org: orgRecord })\n const groupId = consentGroup?.groupId ?? null\n\n /*\n * Which of the six task views is open is the saved VIEW'S (AGL-2617): a\n * saved view of tasks holds the task view beside the columns and the\n * sort, and the toggle below writes into it. Unset reads as \"My tasks\",\n * which is what the section opened on before views existed.\n */\n const views = useCrmSavedView({ section: 'tasks', hostId, org: orgRecord, basePath })\n const view: CrmTaskView = useMemo(() => {\n const value = views.state.filters.find((clause) => clause.field === 'view')?.value\n return CRM_TASK_VIEWS.some((option) => option.id === value)\n ? (value as CrmTaskView)\n : 'mine'\n }, [views.state.filters])\n /*\n * The grid's own Filters panel and quick search edit the view's clauses\n * (AGL-3313). \"Show\" is the task view the query serves — the hidden\n * `view` column, as the toggle stored it, with none meaning \"My tasks\" —\n * and Kind, Priority and Assignee narrow the rows it loaded.\n */\n const clauses = useMemo(\n () =>\n views.state.filters.some((clause) => clause.field === 'view')\n ? views.state.filters\n : [TASK_VIEW_DEFAULT, ...views.state.filters],\n [views.state.filters],\n )\n const setClauses = useCallback(\n (next: CrmViewFilterClause[]) =>\n views.setFilters(\n next.filter(\n (clause) => !(clause.field === 'view' && clause.value === TASK_VIEW_DEFAULT.value),\n ),\n ),\n [views.setFilters],\n )\n const gridFilter = useListGridFilter({\n clauses,\n onChange: setClauses,\n selectFields: ['view', 'kind', 'priority', 'assigneeUid'],\n })\n const list = useCrmTaskList({\n hostId,\n org: orgRecord,\n view,\n uid: user?.uid,\n nowMs,\n })\n const { tasks: loaded, status, fromCache, truncated, scope, orgId, readTokens } = list\n const directory = useOrgMemberDirectory(orgId)\n const filterOptions = useMemo(\n () => ({\n view: CRM_TASK_VIEWS.map((option) => ({ value: option.id, label: option.label })),\n kind: CRM_TASK_KINDS.map((kind) => ({ value: kind, label: CRM_TASK_KIND_LABELS[kind] })),\n priority: CRM_TASK_PRIORITIES.map((priority) => ({\n value: priority,\n label: CRM_TASK_PRIORITY_LABELS[priority],\n })),\n assigneeUid: directory.members.map((member) => ({\n value: member.uid,\n label: member.label,\n })),\n }),\n [directory.members],\n )\n // Every clause but the served view, and the search, over the loaded rows.\n const searchKey = gridFilter.searchWords.join(' ')\n const tasks = useMemo(\n () =>\n loaded.filter(\n (task) =>\n clauses.every(\n (clause) =>\n clause.field === 'view' || matchListFilter(task, TASK_FILTER_FIELDS, clause),\n ) && listRowMatchesSearch(task, TASK_SEARCH_FIELDS, gridFilter.searchWords),\n ),\n // `searchKey` stands for the words, which are a new array each render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [loaded, clauses, searchKey],\n )\n\n /*\n * Every record a task names, not only the one its \"For\" cell shows: the\n * export writes the contact, the company and the deal each by name, and\n * a task that names two would otherwise carry an id in one column.\n */\n const linked = useMemo(\n () =>\n tasks.flatMap((task) => [\n ...(task.contactId ? [{ kind: 'contact' as const, id: task.contactId }] : []),\n ...(task.companyId ? [{ kind: 'company' as const, id: task.companyId }] : []),\n ...(task.dealId ? [{ kind: 'deal' as const, id: task.dealId }] : []),\n ]),\n [tasks],\n )\n const nameOf = useCrmRecordNames({ orgId, groupId, org: orgRecord, records: linked })\n\n const [selectedIds, setSelectedIds] = useState<string[]>([])\n // A view is a different set of rows; a selection made on the last one\n // would be a count over rows no longer on screen.\n useEffect(() => setSelectedIds([]), [view])\n const csvOptions: TaskCsvOptions = useMemo(\n () => ({\n assigneeEmail: (uid) => {\n const member = findOrgMember(directory.members, uid)\n return member?.email || member?.label || uid\n },\n recordName: nameOf,\n }),\n [directory.members, nameOf],\n )\n const handleExport = useCallback(() => {\n downloadTextFile('tasks.csv', 'text/csv', tasksCsv(tasks, csvOptions))\n }, [tasks, csvOptions])\n\n /*\n * List or month (AGL-2662). A layout choice over the SAME rows and the\n * same view — switching does not narrow anything and costs no read, so\n * it is a toggle rather than another saved view.\n */\n const [layout, setLayout] = useState<'list' | 'calendar'>('list')\n const [drawer, setDrawer] = useState<{ open: boolean; task: CrmTaskRow | null }>({\n open: false,\n task: null,\n })\n const [busyId, setBusyId] = useState<string | null>(null)\n\n /*\n * Tick or untick. The two directions are two different writes on purpose\n * — see the module comment — and the row is disabled while either is in\n * flight so a double-click cannot complete a task and reopen it in the\n * same breath.\n */\n const toggleDone = useCallback(\n async (task: CrmTaskRow) => {\n if (!scope || busyId) return\n setBusyId(task.$id)\n try {\n if (task.status === 'done') {\n await updateDoc(\n doc(firestore, scope[0], scope[1], CRM_COLLECTIONS.tasks, task.$id),\n {\n status: 'open',\n completedAtMs: null,\n completedByUid: deleteField(),\n updatedAt: serverTimestamp(),\n },\n )\n enqueueSnackbar('Task reopened', { variant: 'success' })\n // A client-direct write: the records it names are told (AGL-2661).\n await refreshCrmNextActivity(user, crmTaskCallScope(hostId, orgId), [task])\n } else {\n // The route runs as the mounted site, which hears the event, or\n // at the organization level as the org — the org variant, which\n // emits on the task's own site, or nowhere for an org task.\n const callScope = crmTaskCallScope(hostId, orgId)\n if (!callScope) return\n await completeCrmTask(user, { ...callScope, taskId: task.$id })\n enqueueSnackbar('Task completed', { variant: 'success' })\n }\n } catch (cause) {\n enqueueSnackbar(\n cause instanceof Error ? cause.message : 'The task could not be updated.',\n { variant: 'warning' },\n )\n } finally {\n setBusyId(null)\n }\n },\n [scope, busyId, firestore, user, hostId, orgId, enqueueSnackbar],\n )\n\n const columns: GridColDef[] = useMemo(\n () => [\n {\n field: 'status',\n headerName: '',\n width: 56,\n sortable: false,\n filterable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Checkbox\n size=\"small\"\n checked={row.status === 'done'}\n disabled={busyId === row.$id}\n onClick={(event) => {\n event.stopPropagation()\n void toggleDone(row)\n }}\n slotProps={{\n input: {\n 'aria-label':\n row.status === 'done'\n ? `Reopen \"${row.title}\"`\n : `Complete \"${row.title}\"`,\n },\n }}\n />\n ),\n },\n {\n field: 'title',\n headerName: 'Task',\n flex: 2,\n minWidth: 220,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Stack sx={{ justifyContent: 'center', height: '100%', minWidth: 0 }}>\n <Typography\n variant=\"body2\"\n noWrap\n sx={{\n textDecoration: row.status === 'done' ? 'line-through' : undefined,\n color: row.status === 'done' ? 'text.secondary' : undefined,\n }}\n >\n {row.title}\n </Typography>\n {row.notes ? (\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {row.notes}\n </Typography>\n ) : null}\n </Stack>\n ),\n },\n {\n field: 'kind',\n headerName: 'Kind',\n width: 120,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => <TaskKindCell kind={row.kind} />,\n },\n {\n field: 'priority',\n headerName: 'Priority',\n width: 110,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <TaskPriorityChip priority={row.priority} />\n ),\n },\n {\n field: 'dueAtMs',\n headerName: 'Due',\n width: 260,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Stack direction=\"row\" spacing={0.5} sx={{ alignItems: 'center', height: '100%' }}>\n <TaskDueText task={row} nowMs={nowMs} />\n {row.status === 'done' || !scope ? null : (\n <TaskSnoozeMenu\n dueAtMs={row.dueAtMs}\n remindAtMs={row.remindAtMs}\n target={{\n write: {\n scope,\n taskId: row.$id,\n call: crmTaskCallScope(hostId, orgId),\n links: row,\n },\n }}\n disabled={busyId === row.$id}\n />\n )}\n </Stack>\n ),\n },\n {\n field: 'assigneeUid',\n headerName: 'Assignee',\n flex: 1,\n minWidth: 140,\n sortable: false,\n valueGetter: (_value: unknown, row: CrmTaskRow) =>\n directory.nameOf(row.assigneeUid),\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Typography variant=\"body2\" color={row.assigneeUid ? undefined : 'text.secondary'}>\n {row.assigneeUid ? directory.nameOf(row.assigneeUid) : 'Unassigned'}\n </Typography>\n ),\n },\n {\n field: 'record',\n headerName: 'For',\n flex: 1,\n minWidth: 160,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <TaskRecordLink task={row} routes={routes} nameOf={nameOf} />\n ),\n },\n ],\n [busyId, toggleDone, nowMs, directory, routes, nameOf, scope],\n )\n /* The column and sort models are the view's (AGL-2617). */\n const filterColumns = useMemo(\n () => listFilterGridColumns(columns, TASK_FILTER_FIELDS, filterOptions, TASK_FILTER_HEADERS),\n [columns, filterOptions],\n )\n const grid = useCrmViewGrid(views, filterColumns, TASK_HIDDEN_COLUMNS)\n\n return (\n <>\n <CardDisplay\n header={'Tasks'}\n help={pluginDocsHelp('crmTasks', {\n anchor: '#the-tasks-page',\n excerpt:\n 'Calls, emails, meetings and to-dos, each linked to the contact, ' +\n 'company or deal it is for. Overdue and today are read off the ' +\n 'due date as you look.',\n })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n action: (\n <Button\n size=\"small\"\n variant=\"contained\"\n color=\"primary\"\n onClick={() => setDrawer({ open: true, task: null })}\n >\n {'New task'}\n </Button>\n ),\n }}\n >\n <Stack spacing={2}>\n {/*\n The saved view, and the clauses narrowing it as chips — \"Show\"\n among them — set in the grid's own Filters panel (AGL-3313).\n */}\n <CrmListToolbar label=\"Task filters\">\n <CrmViewsControl controller={views} allLabel=\"All tasks\" />\n <ListFilterChips\n fields={TASK_FILTER_FIELDS}\n headers={TASK_FILTER_HEADERS}\n clauses={clauses}\n onChange={setClauses}\n options={filterOptions}\n servedField=\"view\"\n />\n <ToggleButtonGroup\n exclusive\n size=\"small\"\n color=\"primary\"\n value={layout}\n onChange={(_event, next) => {\n if (next) setLayout(next as 'list' | 'calendar')\n }}\n aria-label=\"Task layout\"\n >\n <ToggleButton value=\"list\">{'List'}</ToggleButton>\n <ToggleButton value=\"calendar\">{'Calendar'}</ToggleButton>\n </ToggleButtonGroup>\n <Stack sx={{ flex: 1 }} />\n <TaskImportButton hostId={hostId} />\n <Button size=\"small\" onClick={handleExport} disabled={!tasks.length}>\n {'Export CSV'}\n </Button>\n </CrmListToolbar>\n {status === 'error' ? (\n <Typography variant=\"body2\" color=\"error\">\n {'The tasks could not be loaded. Reload to try again.'}\n </Typography>\n ) : (\n <>\n {truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Showing the first ${CRM_TASK_VIEW_LIMIT} — narrow the view to see the rest.`}\n </Typography>\n ) : null}\n {/*\n The calendar draws the same rows, so there is no bulk bar\n over it: a selection is a list gesture, and a month grid\n offers nowhere to make one.\n */}\n {layout === 'calendar' ? (\n <TasksCalendar\n tasks={tasks}\n truncated={truncated}\n onOpen={(task) => setDrawer({ open: true, task })}\n />\n ) : (\n <>\n <TasksBulkBar\n hostId={hostId}\n scope={scope}\n rows={tasks}\n selected={selectedIds}\n onSelectedChange={setSelectedIds}\n directory={directory}\n csv={csvOptions}\n />\n <CrmColumnOrderProvider value={grid.columnOrder}>\n <ListTable\n rows={tasks}\n columns={grid.columns}\n slots={CRM_LIST_SLOTS}\n selectable={{ selected: selectedIds, onChange: setSelectedIds }}\n loading={status === 'loading'}\n onOpen={(id) => {\n const found = tasks.find((row) => row.$id === id)\n if (found) setDrawer({ open: true, task: found })\n }}\n /*\n * The panel and the search are the grid's; the section\n * answers them, the view through the query (AGL-3313). An\n * empty view is said inside the grid rather than instead of\n * it, so its toolbar stays to choose another view.\n */\n noRowsLabel={loaded.length ? 'No tasks match these filters' : EMPTY_LABEL[view]}\n noRowsDescription={loaded.length ? undefined : EMPTY_COPY[view]}\n noRowsAction={\n loaded.length ? undefined : (\n <Button\n size=\"small\"\n variant=\"contained\"\n color=\"primary\"\n onClick={() => setDrawer({ open: true, task: null })}\n >\n {'New task'}\n </Button>\n )\n }\n filterMode=\"server\"\n filterModel={gridFilter.filterModel}\n onFilterModelChange={gridFilter.onFilterModelChange}\n quickFilter\n // Columns and sort are the view's, controlled (AGL-2617).\n columnVisibilityModel={grid.columnVisibilityModel}\n onColumnVisibilityModelChange={grid.onColumnVisibilityModelChange}\n sortModel={grid.sortModel}\n onSortModelChange={grid.onSortModelChange}\n />\n </CrmColumnOrderProvider>\n </>\n )}\n </>\n )}\n </Stack>\n </CardDisplay>\n <TaskEditDrawer\n open={drawer.open}\n onClose={() => setDrawer((prev) => ({ ...prev, open: false }))}\n hostId={hostId}\n org={orgRecord}\n orgId={orgId}\n scope={scope}\n readTokens={readTokens}\n task={drawer.task}\n seed={{ fromCache, unreadable: status === 'error' }}\n />\n </>\n )\n}\nTasksSection.displayName = 'TasksSection'\n\nexport default TasksSection\n"],"names":["CRM_COLLECTIONS","findOrgMember","pluginDocsHelp","CardDisplay","ListTable","useCrmSavedView","useCrmScope","useCrmViewGrid","CRM_LIST_SLOTS","CrmColumnOrderProvider","CrmViewsControl","useSnackbar","useFirestore","useUser","Button","Checkbox","Stack","ToggleButton","ToggleButtonGroup","Typography","deleteField","doc","serverTimestamp","updateDoc","useCallback","useEffect","useMemo","useState","useCrmRecordNames","useCrmTaskList","useNowMs","useOrgMemberDirectory","downloadTextFile","crmRoutes","refreshCrmNextActivity","completeCrmTask","crmTaskCallScope","tasksCsv","CRM_TASK_KIND_LABELS","CRM_TASK_KINDS","CRM_TASK_PRIORITIES","CRM_TASK_PRIORITY_LABELS","CRM_TASK_VIEW_LIMIT","CRM_TASK_VIEWS","matchListFilter","listFilterGridColumns","listRowMatchesSearch","useListGridFilter","ListFilterChips","CrmListToolbar","TaskDueText","TaskKindCell","TaskPriorityChip","TaskRecordLink","TaskEditDrawer","TasksCalendar","TaskImportButton","TaskSnoozeMenu","TasksBulkBar","TASK_FILTER_FIELDS","column","kind","path","operators","TASK_FILTER_HEADERS","view","priority","assigneeUid","TASK_HIDDEN_COLUMNS","TASK_VIEW_DEFAULT","field","op","value","TASK_SEARCH_FIELDS","EMPTY_LABEL","mine","overdue","today","upcoming","open","done","EMPTY_COPY","TasksSection","props","hostId","org","basePath","orgRecord","firestore","data","user","enqueueSnackbar","nowMs","routes","consentGroup","groupId","views","section","state","filters","find","clause","some","option","id","clauses","setClauses","next","setFilters","filter","gridFilter","onChange","selectFields","list","uid","tasks","loaded","status","fromCache","truncated","scope","orgId","readTokens","directory","filterOptions","map","label","members","member","searchKey","searchWords","join","task","every","linked","flatMap","contactId","companyId","dealId","nameOf","records","selectedIds","setSelectedIds","csvOptions","assigneeEmail","email","recordName","handleExport","layout","setLayout","drawer","setDrawer","busyId","setBusyId","toggleDone","$id","completedAtMs","completedByUid","updatedAt","variant","callScope","taskId","cause","Error","message","columns","headerName","width","sortable","filterable","renderCell","row","size","checked","disabled","onClick","event","stopPropagation","slotProps","input","title","flex","minWidth","sx","justifyContent","height","noWrap","textDecoration","undefined","color","notes","direction","spacing","alignItems","dueAtMs","remindAtMs","target","write","call","links","valueGetter","_value","filterColumns","grid","header","help","anchor","excerpt","contentGutterX","contentGutterY","HeaderProps","action","controller","allLabel","fields","headers","options","servedField","exclusive","_event","aria-label","length","onOpen","rows","selected","onSelectedChange","csv","columnOrder","slots","selectable","loading","found","noRowsLabel","noRowsDescription","noRowsAction","filterMode","filterModel","onFilterModelChange","quickFilter","columnVisibilityModel","onColumnVisibilityModelChange","sortModel","onSortModelChange","onClose","prev","seed","unreadable","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;;AAEA,SAEEA,eAAe,EAEfC,aAAa,EACbC,cAAc,QACT,eAAc;AACrB,SAASC,WAAW,QAAQ,uBAAsB;AAClD,SAASC,SAAS,QAAQ,uDAAsD;AAChF,SAASC,eAAe,QAAQ,iCAA6B;AAC7D,SAASC,WAAW,QAAQ,4BAAwB;AACpD,SAASC,cAAc,QAAQ,gCAA4B;AAC3D,SAASC,cAAc,EAAEC,sBAAsB,QAAQ,uBAAmB;AAC1E,OAAOC,qBAAqB,yBAAqB;AACjD,SAASC,WAAW,QAAQ,8BAA6B;AACzD,SAASC,YAAY,EAAEC,OAAO,QAAQ,iCAAgC;AACtE,SACEC,MAAM,EACNC,QAAQ,EACRC,KAAK,EACLC,YAAY,EACZC,iBAAiB,EACjBC,UAAU,QACL,gBAAe;AAEtB,SAASC,WAAW,EAAEC,GAAG,EAAEC,eAAe,EAAEC,SAAS,QAAQ,qBAAoB;AACjF,SAASC,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AACjE,SAASC,iBAAiB,QAAQ,mCAA+B;AACjE,SAA0BC,cAAc,EAAEC,QAAQ,QAAQ,4BAAwB;AAClF,SAASC,qBAAqB,QAAQ,uCAAmC;AACzE,SAASC,gBAAgB,QAAQ,2BAAuB;AACxD,SAASC,SAAS,QAAQ,yBAAqB;AAC/C,SAASC,sBAAsB,QAAQ,gCAA4B;AACnE,SAASC,eAAe,QAAQ,uBAAmB;AACnD,SAASC,gBAAgB,QAAQ,0BAAsB;AACvD,SAA8BC,QAAQ,QAAQ,wBAAoB;AAClE,SACEC,oBAAoB,EACpBC,cAAc,EACdC,mBAAmB,EACnBC,wBAAwB,EACxBC,mBAAmB,EACnBC,cAAc,QAET,yBAAqB;AAC5B,SAEEC,eAAe,QACV,yCAAwC;AAC/C,SAASC,qBAAqB,EAAEC,oBAAoB,QAAQ,8CAA6C;AACzG,SAASC,iBAAiB,QAAQ,kDAAiD;AACnF,OAAOC,qBAAqB,8DAA6D;AACzF,SAASC,cAAc,QAAQ,wBAAoB;AACnD,SACEC,WAAW,EACXC,YAAY,EACZC,gBAAgB,EAChBC,cAAc,QACT,kBAAc;AACrB,OAAOC,oBAAoB,wBAAoB;AAC/C,OAAOC,mBAAmB,sBAAkB;AAC5C,SAASC,gBAAgB,QAAQ,0BAAsB;AACvD,OAAOC,oBAAoB,wBAAoB;AAC/C,OAAOC,kBAAkB,sBAAkB;AAE3C,4EAA4E,GAC5E;;;;CAIC,GACD,MAAMC,qBAAiD;IACrD;QAAEC,QAAQ;QAAQC,MAAM;QAASC,MAAM;QAAQC,WAAW;YAAC;SAAS;IAAC;IACrE;QAAEH,QAAQ;QAAQC,MAAM;QAASC,MAAM;QAAQC,WAAW;YAAC;YAAU;SAAU;IAAC;IAChF;QAAEH,QAAQ;QAAYC,MAAM;QAASC,MAAM;QAAYC,WAAW;YAAC;YAAU;SAAU;IAAC;IACxF;QAAEH,QAAQ;QAAeC,MAAM;QAASC,MAAM;QAAeC,WAAW;YAAC;YAAU;SAAU;IAAC;CAC/F;AACD,MAAMC,sBAAwD;IAC5DC,MAAM;IACNJ,MAAM;IACNK,UAAU;IACVC,aAAa;AACf;AACA,+CAA+C,GAC/C,MAAMC,sBAAyD;IAAEH,MAAM;AAAM;AAC7E,sFAAsF,GACtF,MAAMI,oBAAyC;IAAEC,OAAO;IAAQC,IAAI;IAAUC,OAAO;AAAO;AAC5F,2CAA2C,GAC3C,MAAMC,qBAAqB;IAAC;IAAS;CAAQ;AAE7C,MAAMC,cAA2C;IAC/CC,MAAM;IACNC,SAAS;IACTC,OAAO;IACPC,UAAU;IACVC,MAAM;IACNC,MAAM;AACR;AAEA,wCAAwC,GACxC,MAAMC,aAA0C;IAC9CN,MAAM;IACNC,SAAS;IACTC,OAAO;IACPC,UAAU;IACVC,MAAM;IACNC,MAAM;AACR;AAEA;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,SAASE,aAAaC,KAA6B;;IACxD,MAAM,EAAEC,MAAM,EAAEC,GAAG,EAAEC,WAAW,EAAE,EAAE,GAAGH;IACvC,MAAMI,YAAYF;IAClB,MAAMG,YAAY5E;IAClB,MAAM,EAAE6E,MAAMC,IAAI,EAAE,GAAG7E;IACvB,MAAM,EAAE8E,eAAe,EAAE,GAAGhF;IAC5B,MAAMiF,QAAQ9D;IACd,MAAM+D,SAASnE,QAAQ,IAAMO,UAAUqD,WAAW;QAACA;KAAS;IAC5D,wEAAwE;IACxE,kEAAkE;IAClE,MAAM,EAAEQ,YAAY,EAAE,GAAGxF,YAAY;QAAE8E;QAAQC,KAAKE;IAAU;IAC9D,MAAMQ,kBAAUD,gCAAAA,aAAcC,OAAO,mBAAI;IAEzC;;;;;GAKC,GACD,MAAMC,QAAQ3F,gBAAgB;QAAE4F,SAAS;QAASb;QAAQC,KAAKE;QAAWD;IAAS;IACnF,MAAMrB,OAAoBvC,QAAQ;YAClBsE;QAAd,MAAMxB,SAAQwB,4BAAAA,MAAME,KAAK,CAACC,OAAO,CAACC,IAAI,CAAC,CAACC,SAAWA,OAAO/B,KAAK,KAAK,4BAAtD0B,0BAA+DxB,KAAK;QAClF,OAAO7B,eAAe2D,IAAI,CAAC,CAACC,SAAWA,OAAOC,EAAE,KAAKhC,SAChDA,QACD;IACN,GAAG;QAACwB,MAAME,KAAK,CAACC,OAAO;KAAC;IACxB;;;;;GAKC,GACD,MAAMM,UAAU/E,QACd,IACEsE,MAAME,KAAK,CAACC,OAAO,CAACG,IAAI,CAAC,CAACD,SAAWA,OAAO/B,KAAK,KAAK,UAClD0B,MAAME,KAAK,CAACC,OAAO,GACnB;YAAC9B;eAAsB2B,MAAME,KAAK,CAACC,OAAO;SAAC,EACjD;QAACH,MAAME,KAAK,CAACC,OAAO;KAAC;IAEvB,MAAMO,aAAalF,YACjB,CAACmF,OACCX,MAAMY,UAAU,CACdD,KAAKE,MAAM,CACT,CAACR,SAAW,CAAEA,CAAAA,OAAO/B,KAAK,KAAK,UAAU+B,OAAO7B,KAAK,KAAKH,kBAAkBG,KAAK,AAAD,KAGtF;QAACwB,MAAMY,UAAU;KAAC;IAEpB,MAAME,aAAa/D,kBAAkB;QACnC0D;QACAM,UAAUL;QACVM,cAAc;YAAC;YAAQ;YAAQ;YAAY;SAAc;IAC3D;IACA,MAAMC,OAAOpF,eAAe;QAC1BuD;QACAC,KAAKE;QACLtB;QACAiD,GAAG,EAAExB,wBAAAA,KAAMwB,GAAG;QACdtB;IACF;IACA,MAAM,EAAEuB,OAAOC,MAAM,EAAEC,MAAM,EAAEC,SAAS,EAAEC,SAAS,EAAEC,KAAK,EAAEC,KAAK,EAAEC,UAAU,EAAE,GAAGT;IAClF,MAAMU,YAAY5F,sBAAsB0F;IACxC,MAAMG,gBAAgBlG,QACpB,IAAO,CAAA;YACLuC,MAAMtB,eAAekF,GAAG,CAAC,CAACtB,SAAY,CAAA;oBAAE/B,OAAO+B,OAAOC,EAAE;oBAAEsB,OAAOvB,OAAOuB,KAAK;gBAAC,CAAA;YAC9EjE,MAAMtB,eAAesF,GAAG,CAAC,CAAChE,OAAU,CAAA;oBAAEW,OAAOX;oBAAMiE,OAAOxF,oBAAoB,CAACuB,KAAK;gBAAC,CAAA;YACrFK,UAAU1B,oBAAoBqF,GAAG,CAAC,CAAC3D,WAAc,CAAA;oBAC/CM,OAAON;oBACP4D,OAAOrF,wBAAwB,CAACyB,SAAS;gBAC3C,CAAA;YACAC,aAAawD,UAAUI,OAAO,CAACF,GAAG,CAAC,CAACG,SAAY,CAAA;oBAC9CxD,OAAOwD,OAAOd,GAAG;oBACjBY,OAAOE,OAAOF,KAAK;gBACrB,CAAA;QACF,CAAA,GACA;QAACH,UAAUI,OAAO;KAAC;IAErB,0EAA0E;IAC1E,MAAME,YAAYnB,WAAWoB,WAAW,CAACC,IAAI,CAAC;IAC9C,MAAMhB,QAAQzF,QACZ,IACE0F,OAAOP,MAAM,CACX,CAACuB,OACC3B,QAAQ4B,KAAK,CACX,CAAChC,SACCA,OAAO/B,KAAK,KAAK,UAAU1B,gBAAgBwF,MAAMzE,oBAAoB0C,YACpEvD,qBAAqBsF,MAAM3D,oBAAoBqC,WAAWoB,WAAW,IAEhF,uEAAuE;IACvE,uDAAuD;IACvD;QAACd;QAAQX;QAASwB;KAAU;IAG9B;;;;GAIC,GACD,MAAMK,SAAS5G,QACb,IACEyF,MAAMoB,OAAO,CAAC,CAACH,OAAS;mBAClBA,KAAKI,SAAS,GAAG;oBAAC;wBAAE3E,MAAM;wBAAoB2C,IAAI4B,KAAKI,SAAS;oBAAC;iBAAE,GAAG,EAAE;mBACxEJ,KAAKK,SAAS,GAAG;oBAAC;wBAAE5E,MAAM;wBAAoB2C,IAAI4B,KAAKK,SAAS;oBAAC;iBAAE,GAAG,EAAE;mBACxEL,KAAKM,MAAM,GAAG;oBAAC;wBAAE7E,MAAM;wBAAiB2C,IAAI4B,KAAKM,MAAM;oBAAC;iBAAE,GAAG,EAAE;aACpE,GACH;QAACvB;KAAM;IAET,MAAMwB,SAAS/G,kBAAkB;QAAE6F;QAAO1B;QAASV,KAAKE;QAAWqD,SAASN;IAAO;IAEnF,MAAM,CAACO,aAAaC,eAAe,GAAGnH,SAAmB,EAAE;IAC3D,sEAAsE;IACtE,kDAAkD;IAClDF,UAAU,IAAMqH,eAAe,EAAE,GAAG;QAAC7E;KAAK;IAC1C,MAAM8E,aAA6BrH,QACjC,IAAO,CAAA;YACLsH,eAAe,CAAC9B;gBACd,MAAMc,SAAS/H,cAAc0H,UAAUI,OAAO,EAAEb;gBAChD,OAAOc,CAAAA,0BAAAA,OAAQiB,KAAK,MAAIjB,0BAAAA,OAAQF,KAAK,KAAIZ;YAC3C;YACAgC,YAAYP;QACd,CAAA,GACA;QAAChB,UAAUI,OAAO;QAAEY;KAAO;IAE7B,MAAMQ,eAAe3H,YAAY;QAC/BQ,iBAAiB,aAAa,YAAYK,SAAS8E,OAAO4B;IAC5D,GAAG;QAAC5B;QAAO4B;KAAW;IAEtB;;;;GAIC,GACD,MAAM,CAACK,QAAQC,UAAU,GAAG1H,SAA8B;IAC1D,MAAM,CAAC2H,QAAQC,UAAU,GAAG5H,SAAqD;QAC/EoD,MAAM;QACNqD,MAAM;IACR;IACA,MAAM,CAACoB,QAAQC,UAAU,GAAG9H,SAAwB;IAEpD;;;;;GAKC,GACD,MAAM+H,aAAalI,YACjB,OAAO4G;QACL,IAAI,CAACZ,SAASgC,QAAQ;QACtBC,UAAUrB,KAAKuB,GAAG;QAClB,IAAI;YACF,IAAIvB,KAAKf,MAAM,KAAK,QAAQ;gBAC1B,MAAM9F,UACJF,IAAImE,WAAWgC,KAAK,CAAC,EAAE,EAAEA,KAAK,CAAC,EAAE,EAAExH,gBAAgBmH,KAAK,EAAEiB,KAAKuB,GAAG,GAClE;oBACEtC,QAAQ;oBACRuC,eAAe;oBACfC,gBAAgBzI;oBAChB0I,WAAWxI;gBACb;gBAEFqE,gBAAgB,iBAAiB;oBAAEoE,SAAS;gBAAU;gBACtD,mEAAmE;gBACnE,MAAM7H,uBAAuBwD,MAAMtD,iBAAiBgD,QAAQqC,QAAQ;oBAACW;iBAAK;YAC5E,OAAO;gBACL,gEAAgE;gBAChE,gEAAgE;gBAChE,4DAA4D;gBAC5D,MAAM4B,YAAY5H,iBAAiBgD,QAAQqC;gBAC3C,IAAI,CAACuC,WAAW;gBAChB,MAAM7H,gBAAgBuD,MAAM,aAAKsE;oBAAWC,QAAQ7B,KAAKuB,GAAG;;gBAC5DhE,gBAAgB,kBAAkB;oBAAEoE,SAAS;gBAAU;YACzD;QACF,EAAE,OAAOG,OAAO;YACdvE,gBACEuE,iBAAiBC,QAAQD,MAAME,OAAO,GAAG,kCACzC;gBAAEL,SAAS;YAAU;QAEzB,SAAU;YACRN,UAAU;QACZ;IACF,GACA;QAACjC;QAAOgC;QAAQhE;QAAWE;QAAMN;QAAQqC;QAAO9B;KAAgB;IAGlE,MAAM0E,UAAwB3I,QAC5B,IAAM;YACJ;gBACE4C,OAAO;gBACPgG,YAAY;gBACZC,OAAO;gBACPC,UAAU;gBACVC,YAAY;gBACZC,YAAY,CAAC,EAAEC,GAAG,EAAuB,iBACvC,KAAC5J;wBACC6J,MAAK;wBACLC,SAASF,IAAItD,MAAM,KAAK;wBACxByD,UAAUtB,WAAWmB,IAAIhB,GAAG;wBAC5BoB,SAAS,CAACC;4BACRA,MAAMC,eAAe;4BACrB,KAAKvB,WAAWiB;wBAClB;wBACAO,WAAW;4BACTC,OAAO;gCACL,cACER,IAAItD,MAAM,KAAK,SACX,CAAC,QAAQ,EAAEsD,IAAIS,KAAK,CAAC,CAAC,CAAC,GACvB,CAAC,UAAU,EAAET,IAAIS,KAAK,CAAC,CAAC,CAAC;4BACjC;wBACF;;YAGN;YACA;gBACE9G,OAAO;gBACPgG,YAAY;gBACZe,MAAM;gBACNC,UAAU;gBACVd,UAAU;gBACVE,YAAY,CAAC,EAAEC,GAAG,EAAuB,iBACvC,MAAC3J;wBAAMuK,IAAI;4BAAEC,gBAAgB;4BAAUC,QAAQ;4BAAQH,UAAU;wBAAE;;0CACjE,KAACnK;gCACC4I,SAAQ;gCACR2B,MAAM;gCACNH,IAAI;oCACFI,gBAAgBhB,IAAItD,MAAM,KAAK,SAAS,iBAAiBuE;oCACzDC,OAAOlB,IAAItD,MAAM,KAAK,SAAS,mBAAmBuE;gCACpD;0CAECjB,IAAIS,KAAK;;4BAEXT,IAAImB,KAAK,iBACR,KAAC3K;gCAAW4I,SAAQ;gCAAU8B,OAAM;gCAAiBH,MAAM;0CACxDf,IAAImB,KAAK;iCAEV;;;YAGV;YACA;gBACExH,OAAO;gBACPgG,YAAY;gBACZC,OAAO;gBACPC,UAAU;gBACVE,YAAY,CAAC,EAAEC,GAAG,EAAuB,iBAAK,KAACxH;wBAAaU,MAAM8G,IAAI9G,IAAI;;YAC5E;YACA;gBACES,OAAO;gBACPgG,YAAY;gBACZC,OAAO;gBACPC,UAAU;gBACVE,YAAY,CAAC,EAAEC,GAAG,EAAuB,iBACvC,KAACvH;wBAAiBc,UAAUyG,IAAIzG,QAAQ;;YAE5C;YACA;gBACEI,OAAO;gBACPgG,YAAY;gBACZC,OAAO;gBACPC,UAAU;gBACVE,YAAY,CAAC,EAAEC,GAAG,EAAuB,iBACvC,MAAC3J;wBAAM+K,WAAU;wBAAMC,SAAS;wBAAKT,IAAI;4BAAEU,YAAY;4BAAUR,QAAQ;wBAAO;;0CAC9E,KAACvI;gCAAYkF,MAAMuC;gCAAK/E,OAAOA;;4BAC9B+E,IAAItD,MAAM,KAAK,UAAU,CAACG,QAAQ,qBACjC,KAAC/D;gCACCyI,SAASvB,IAAIuB,OAAO;gCACpBC,YAAYxB,IAAIwB,UAAU;gCAC1BC,QAAQ;oCACNC,OAAO;wCACL7E;wCACAyC,QAAQU,IAAIhB,GAAG;wCACf2C,MAAMlK,iBAAiBgD,QAAQqC;wCAC/B8E,OAAO5B;oCACT;gCACF;gCACAG,UAAUtB,WAAWmB,IAAIhB,GAAG;;;;YAKtC;YACA;gBACErF,OAAO;gBACPgG,YAAY;gBACZe,MAAM;gBACNC,UAAU;gBACVd,UAAU;gBACVgC,aAAa,CAACC,QAAiB9B,MAC7BhD,UAAUgB,MAAM,CAACgC,IAAIxG,WAAW;gBAClCuG,YAAY,CAAC,EAAEC,GAAG,EAAuB,iBACvC,KAACxJ;wBAAW4I,SAAQ;wBAAQ8B,OAAOlB,IAAIxG,WAAW,GAAGyH,YAAY;kCAC9DjB,IAAIxG,WAAW,GAAGwD,UAAUgB,MAAM,CAACgC,IAAIxG,WAAW,IAAI;;YAG7D;YACA;gBACEG,OAAO;gBACPgG,YAAY;gBACZe,MAAM;gBACNC,UAAU;gBACVd,UAAU;gBACVE,YAAY,CAAC,EAAEC,GAAG,EAAuB,iBACvC,KAACtH;wBAAe+E,MAAMuC;wBAAK9E,QAAQA;wBAAQ8C,QAAQA;;YAEvD;SACD,EACD;QAACa;QAAQE;QAAY9D;QAAO+B;QAAW9B;QAAQ8C;QAAQnB;KAAM;IAE/D,yDAAyD,GACzD,MAAMkF,gBAAgBhL,QACpB,IAAMmB,sBAAsBwH,SAAS1G,oBAAoBiE,eAAe5D,sBACxE;QAACqG;QAASzC;KAAc;IAE1B,MAAM+E,OAAOpM,eAAeyF,OAAO0G,eAAetI;IAElD,qBACE;;0BACE,KAACjE;gBACCyM,QAAQ;gBACRC,MAAM3M,eAAe,YAAY;oBAC/B4M,QAAQ;oBACRC,SACE,qEACA,mEACA;gBACJ;gBACAC,cAAc;gBACdC,cAAc;gBACdC,aAAa;oBACXC,sBACE,KAACrM;wBACC8J,MAAK;wBACLb,SAAQ;wBACR8B,OAAM;wBACNd,SAAS,IAAMxB,UAAU;gCAAExE,MAAM;gCAAMqD,MAAM;4BAAK;kCAEjD;;gBAGP;0BAEA,cAAA,MAACpH;oBAAMgL,SAAS;;sCAKd,MAAC/I;4BAAe6E,OAAM;;8CACpB,KAACpH;oCAAgB0M,YAAYpH;oCAAOqH,UAAS;;8CAC7C,KAACrK;oCACCsK,QAAQ3J;oCACR4J,SAASvJ;oCACTyC,SAASA;oCACTM,UAAUL;oCACV8G,SAAS5F;oCACT6F,aAAY;;8CAEd,MAACvM;oCACCwM,SAAS;oCACT9C,MAAK;oCACLiB,OAAM;oCACNrH,OAAO4E;oCACPrC,UAAU,CAAC4G,QAAQhH;wCACjB,IAAIA,MAAM0C,UAAU1C;oCACtB;oCACAiH,cAAW;;sDAEX,KAAC3M;4CAAauD,OAAM;sDAAQ;;sDAC5B,KAACvD;4CAAauD,OAAM;sDAAY;;;;8CAElC,KAACxD;oCAAMuK,IAAI;wCAAEF,MAAM;oCAAE;;8CACrB,KAAC7H;oCAAiB4B,QAAQA;;8CAC1B,KAACtE;oCAAO8J,MAAK;oCAAQG,SAAS5B;oCAAc2B,UAAU,CAAC3D,MAAM0G,MAAM;8CAChE;;;;wBAGJxG,WAAW,wBACV,KAAClG;4BAAW4I,SAAQ;4BAAQ8B,OAAM;sCAC/B;2CAGH;;gCACGtE,0BACC,KAACpG;oCAAW4I,SAAQ;oCAAU8B,OAAM;8CACjC,CAAC,kBAAkB,EAAEnJ,oBAAoB,mCAAmC,CAAC;qCAE9E;gCAMH0G,WAAW,2BACV,KAAC7F;oCACC4D,OAAOA;oCACPI,WAAWA;oCACXuG,QAAQ,CAAC1F,OAASmB,UAAU;4CAAExE,MAAM;4CAAMqD;wCAAK;mDAGjD;;sDACF,KAAC1E;4CACC0B,QAAQA;4CACRoC,OAAOA;4CACPuG,MAAM5G;4CACN6G,UAAUnF;4CACVoF,kBAAkBnF;4CAClBnB,WAAWA;4CACXuG,KAAKnF;;sDAEP,KAACtI;4CAAuB+D,OAAOmI,KAAKwB,WAAW;sDAC7C,cAAA,KAAC/N;gDACC2N,MAAM5G;gDACNkD,SAASsC,KAAKtC,OAAO;gDACrB+D,OAAO5N;gDACP6N,YAAY;oDAAEL,UAAUnF;oDAAa9B,UAAU+B;gDAAe;gDAC9DwF,SAASjH,WAAW;gDACpByG,QAAQ,CAACtH;oDACP,MAAM+H,QAAQpH,MAAMf,IAAI,CAAC,CAACuE,MAAQA,IAAIhB,GAAG,KAAKnD;oDAC9C,IAAI+H,OAAOhF,UAAU;wDAAExE,MAAM;wDAAMqD,MAAMmG;oDAAM;gDACjD;gDACA;;;;;mBAKC,GACDC,aAAapH,OAAOyG,MAAM,GAAG,iCAAiCnJ,WAAW,CAACT,KAAK;gDAC/EwK,mBAAmBrH,OAAOyG,MAAM,GAAGjC,YAAY3G,UAAU,CAAChB,KAAK;gDAC/DyK,cACEtH,OAAOyG,MAAM,GAAGjC,0BACd,KAAC9K;oDACC8J,MAAK;oDACLb,SAAQ;oDACR8B,OAAM;oDACNd,SAAS,IAAMxB,UAAU;4DAAExE,MAAM;4DAAMqD,MAAM;wDAAK;8DAEjD;;gDAIPuG,YAAW;gDACXC,aAAa9H,WAAW8H,WAAW;gDACnCC,qBAAqB/H,WAAW+H,mBAAmB;gDACnDC,WAAW;gDACX,0DAA0D;gDAC1DC,uBAAuBpC,KAAKoC,qBAAqB;gDACjDC,+BAA+BrC,KAAKqC,6BAA6B;gDACjEC,WAAWtC,KAAKsC,SAAS;gDACzBC,mBAAmBvC,KAAKuC,iBAAiB;;;;;;;;;;0BASrD,KAAC5L;gBACCyB,MAAMuE,OAAOvE,IAAI;gBACjBoK,SAAS,IAAM5F,UAAU,CAAC6F,OAAU,aAAKA;4BAAMrK,MAAM;;gBACrDK,QAAQA;gBACRC,KAAKE;gBACLkC,OAAOA;gBACPD,OAAOA;gBACPE,YAAYA;gBACZU,MAAMkB,OAAOlB,IAAI;gBACjBiH,MAAM;oBAAE/H;oBAAWgI,YAAYjI,WAAW;gBAAQ;;;;AAI1D;AACAnC,aAAaqK,WAAW,GAAG;AAE3B,eAAerK,aAAY"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/tasks-section.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (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 * http://www.apache.org/licenses/LICENSE-2.0\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'use client'\n\nimport {\n type ConsolePluginPageProps,\n CRM_COLLECTIONS,\n type CrmViewFilterClause,\n findOrgMember,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { ListTable } from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport { useCrmSavedView } from '../hooks/use-crm-saved-view'\nimport { useCrmScope } from '../hooks/use-crm-scope'\nimport { useCrmViewGrid } from '../hooks/use-crm-view-grid'\nimport { CRM_LIST_SLOTS, CrmColumnOrderProvider } from './crm-column-menu'\nimport CrmViewsControl from './crm-views-control'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useFirestore, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Button,\n Checkbox,\n Stack,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n} from '@mui/material'\nimport type { GridColDef } from '@mui/x-data-grid'\nimport { deleteField, doc, serverTimestamp, updateDoc } from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useCrmRecordNames } from '../hooks/use-crm-record-names'\nimport { type CrmTaskRow, useCrmTaskList, useNowMs } from '../hooks/use-crm-tasks'\nimport { useOrgMemberDirectory } from '../hooks/use-org-member-directory'\nimport { downloadTextFile } from '../model/contacts-csv'\nimport { crmRoutes } from '../model/crm-routes'\nimport { refreshCrmNextActivity } from '../model/next-activity-api'\nimport { completeCrmTask } from '../model/task-api'\nimport { crmTaskCallScope } from '../model/task-routes'\nimport { type TaskCsvOptions, tasksCsv } from '../model/tasks-csv'\nimport {\n CRM_TASK_KIND_LABELS,\n CRM_TASK_KINDS,\n CRM_TASK_PRIORITIES,\n CRM_TASK_PRIORITY_LABELS,\n CRM_TASK_VIEWS,\n type CrmTaskView,\n TASK_LIST_QUERY_FIELDS,\n} from '../model/task-views'\nimport type { ListFilterField } from '@aglyn/shared-ui-jsx/const/list-filter'\nimport { listFilterGridColumns } from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { TABLE_PAGE_SIZE_DEFAULT } from '@aglyn/shared-ui-jsx/const/table-pagination'\nimport ListQueryNotices, {\n listQueryRefusals,\n} from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport { useListGridFilter } from '@aglyn/shared-ui-jsx/hooks/use-list-grid-filter'\nimport ListFilterChips from '@aglyn/shared-ui-jsx/components/list-filter-chips.component'\nimport { CrmListToolbar } from './crm-list-toolbar'\nimport {\n TaskDueText,\n TaskKindCell,\n TaskPriorityChip,\n TaskRecordLink,\n} from './task-cells'\nimport TaskEditDrawer from './task-edit-drawer'\nimport TasksCalendar from './tasks-calendar'\nimport { TaskImportButton } from './task-import-drawer'\nimport TaskSnoozeMenu from './task-snooze-menu'\nimport TasksBulkBar from './tasks-bulk-bar'\n\n/** What an empty view is headed, by view — \"nothing overdue\" is good news. */\n/*\n * What the tasks grid's panel offers (AGL-3313). `view` is the task view\n * the query's base answers — a hidden column, since it is no field of a\n * task — and Kind, Priority and Assignee are predicates on the same query\n * (AGL-3321).\n */\nconst TASK_FILTER_FIELDS: readonly ListFilterField[] = [\n { column: 'view', kind: 'exact', path: 'view', operators: ['equals'] },\n ...TASK_LIST_QUERY_FIELDS,\n]\nconst TASK_FILTER_HEADERS: Readonly<Record<string, string>> = {\n view: 'Show',\n kind: 'Kind',\n priority: 'Priority',\n assigneeUid: 'Assignee',\n}\n/** The filter-only `view` column never shows. */\nconst TASK_HIDDEN_COLUMNS: Readonly<Record<string, boolean>> = { view: false }\n/** How many tasks the month view reads: one page, sized for a month of work. */\nconst CALENDAR_PAGE_SIZE = 200\n/** No `view` clause is \"My tasks\", which the section opened on before views existed. */\nconst TASK_VIEW_DEFAULT: CrmViewFilterClause = { field: 'view', op: 'equals', value: 'mine' }\nconst EMPTY_LABEL: Record<CrmTaskView, string> = {\n mine: 'Nothing is assigned to you',\n overdue: 'Nothing is overdue',\n today: 'Nothing is due today',\n upcoming: 'Nothing is scheduled beyond today',\n open: 'No open tasks',\n done: 'No completed tasks yet',\n}\n\n/** The one sentence under it, by view. */\nconst EMPTY_COPY: Record<CrmTaskView, string> = {\n mine: 'Tasks you create are yours unless you hand them to someone.',\n overdue: 'Every dated task is on or ahead of schedule.',\n today: 'Nothing on your calendar day is owed to anyone in the CRM.',\n upcoming: 'A task with a due date past today would be listed here.',\n open: 'A task is a call, an email, a meeting or a to-do owed to a contact, a company or a deal.',\n done: 'Tasks ticked off on their record, or here, are kept for the history.',\n}\n\n/**\n * `/crm/tasks` — what the team owes the people in the CRM (AGL-2599).\n *\n * Six views over `orgs/{orgId}/crmTasks`, each a bounded listener on one of\n * the collection's indexes, chosen by a segmented control. A task hangs off\n * a contact, a company or a deal, but it is listed HERE because \"what is due\n * today\" is a question about the team's day and not about any one record;\n * the record pages carry their own `RecordTasksCard` for the other\n * direction.\n *\n * Completing goes through `crm/task-complete`, because completing fires the\n * `taskCompleted` host event and only the server can run a workflow.\n * Reopening is client-direct: undoing a tick has no side effect beyond the\n * document, and the rules gate it like any other CRM write.\n *\n * The rows are selectable, and a selection raises `TasksBulkBar` over the\n * list — Complete and Assign through their routes, the due date and the\n * delete as batched writes (AGL-2621). Export CSV beside the view control\n * writes the view through `tasksCsv()`, naming the assignee and the linked\n * records; the bar writes the same file over the selection.\n */\nexport function TasksSection(props: ConsolePluginPageProps) {\n const { hostId, org, basePath = '' } = props\n const orgRecord = org as Record<string, unknown> | undefined\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const nowMs = useNowMs()\n const routes = useMemo(() => crmRoutes(basePath), [basePath])\n // The viewing group a linked contact is named through, or `null` at the\n // organization level, where each is named through its own holder.\n const { consentGroup } = useCrmScope({ hostId, org: orgRecord })\n const groupId = consentGroup?.groupId ?? null\n\n /*\n * Which of the six task views is open is the saved VIEW'S (AGL-2617): a\n * saved view of tasks holds the task view beside the columns and the\n * sort, and the toggle below writes into it. Unset reads as \"My tasks\",\n * which is what the section opened on before views existed.\n */\n const views = useCrmSavedView({ section: 'tasks', hostId, org: orgRecord, basePath })\n const view: CrmTaskView = useMemo(() => {\n const value = views.state.filters.find((clause) => clause.field === 'view')?.value\n return CRM_TASK_VIEWS.some((option) => option.id === value)\n ? (value as CrmTaskView)\n : 'mine'\n }, [views.state.filters])\n /*\n * The grid's own Filters panel and quick search edit the view's clauses\n * (AGL-3313). \"Show\" is the task view the query's base answers — the\n * hidden `view` column, as the toggle stored it, with none meaning \"My\n * tasks\" — and Kind, Priority, Assignee and the search word are on the\n * same query (AGL-3321).\n */\n const clauses = useMemo(\n () =>\n views.state.filters.some((clause) => clause.field === 'view')\n ? views.state.filters\n : [TASK_VIEW_DEFAULT, ...views.state.filters],\n [views.state.filters],\n )\n const setClauses = useCallback(\n (next: CrmViewFilterClause[]) =>\n views.setFilters(\n next.filter(\n (clause) => !(clause.field === 'view' && clause.value === TASK_VIEW_DEFAULT.value),\n ),\n ),\n [views.setFilters],\n )\n const gridFilter = useListGridFilter({\n clauses,\n onChange: setClauses,\n selectFields: ['view', 'kind', 'priority', 'assigneeUid'],\n })\n const queryClauses = useMemo(\n () => clauses.filter((clause) => clause.field !== 'view'),\n [clauses],\n )\n const list = useCrmTaskList({\n hostId,\n org: orgRecord,\n view,\n uid: user?.uid,\n nowMs,\n clauses: queryClauses,\n search: gridFilter.searchWords,\n })\n const { tasks, status, fromCache, scope, orgId, readTokens } = list\n const directory = useOrgMemberDirectory(orgId)\n const filterOptions = useMemo(\n () => ({\n view: CRM_TASK_VIEWS.map((option) => ({ value: option.id, label: option.label })),\n kind: CRM_TASK_KINDS.map((kind) => ({ value: kind, label: CRM_TASK_KIND_LABELS[kind] })),\n priority: CRM_TASK_PRIORITIES.map((priority) => ({\n value: priority,\n label: CRM_TASK_PRIORITY_LABELS[priority],\n })),\n assigneeUid: directory.members.map((member) => ({\n value: member.uid,\n label: member.label,\n })),\n }),\n [directory.members],\n )\n // What the query could not hold, said above the list rather than matched in memory.\n const refused = useMemo(\n () =>\n listQueryRefusals(list.plan.refused, {\n fields: TASK_FILTER_FIELDS,\n headers: TASK_FILTER_HEADERS,\n options: filterOptions,\n }),\n [list.plan.refused, filterOptions],\n )\n const filtered = queryClauses.length > 0 || gridFilter.searchWords.some((word) => word.trim())\n\n /*\n * Every record a task names, not only the one its \"For\" cell shows: the\n * export writes the contact, the company and the deal each by name, and\n * a task that names two would otherwise carry an id in one column.\n */\n const linked = useMemo(\n () =>\n tasks.flatMap((task) => [\n ...(task.contactId ? [{ kind: 'contact' as const, id: task.contactId }] : []),\n ...(task.companyId ? [{ kind: 'company' as const, id: task.companyId }] : []),\n ...(task.dealId ? [{ kind: 'deal' as const, id: task.dealId }] : []),\n ]),\n [tasks],\n )\n const nameOf = useCrmRecordNames({ orgId, groupId, org: orgRecord, records: linked })\n\n const [selectedIds, setSelectedIds] = useState<string[]>([])\n // A view, a filter or a page is a different set of rows; a selection made\n // on the last one would be a count over rows no longer on screen.\n useEffect(() => setSelectedIds([]), [view, list.plan, list.page])\n const csvOptions: TaskCsvOptions = useMemo(\n () => ({\n assigneeEmail: (uid) => {\n const member = findOrgMember(directory.members, uid)\n return member?.email || member?.label || uid\n },\n recordName: nameOf,\n }),\n [directory.members, nameOf],\n )\n const handleExport = useCallback(() => {\n downloadTextFile('tasks.csv', 'text/csv', tasksCsv(tasks, csvOptions))\n }, [tasks, csvOptions])\n\n /*\n * List or month (AGL-2662). A layout choice over the SAME rows and the\n * same view — switching does not narrow anything and costs no read, so\n * it is a toggle rather than another saved view.\n */\n const [layout, setLayout] = useState<'list' | 'calendar'>('list')\n /*\n * The month draws one query page, so it asks for a month's worth: the\n * calendar's page is {@link CALENDAR_PAGE_SIZE} tasks of the same view and\n * filters, and it says when the view holds more. The list's own page size\n * comes back with the list.\n */\n const { setPage: setListPage, setPageSize: setListPageSize } = list\n useEffect(() => {\n setListPage(0)\n setListPageSize(layout === 'calendar' ? CALENDAR_PAGE_SIZE : TABLE_PAGE_SIZE_DEFAULT)\n }, [layout, setListPage, setListPageSize])\n const [drawer, setDrawer] = useState<{ open: boolean; task: CrmTaskRow | null }>({\n open: false,\n task: null,\n })\n const [busyId, setBusyId] = useState<string | null>(null)\n\n /*\n * Tick or untick. The two directions are two different writes on purpose\n * — see the module comment — and the row is disabled while either is in\n * flight so a double-click cannot complete a task and reopen it in the\n * same breath.\n */\n const toggleDone = useCallback(\n async (task: CrmTaskRow) => {\n if (!scope || busyId) return\n setBusyId(task.$id)\n try {\n if (task.status === 'done') {\n await updateDoc(\n doc(firestore, scope[0], scope[1], CRM_COLLECTIONS.tasks, task.$id),\n {\n status: 'open',\n completedAtMs: null,\n completedByUid: deleteField(),\n updatedAt: serverTimestamp(),\n },\n )\n enqueueSnackbar('Task reopened', { variant: 'success' })\n // A client-direct write: the records it names are told (AGL-2661).\n await refreshCrmNextActivity(user, crmTaskCallScope(hostId, orgId), [task])\n } else {\n // The route runs as the mounted site, which hears the event, or\n // at the organization level as the org — the org variant, which\n // emits on the task's own site, or nowhere for an org task.\n const callScope = crmTaskCallScope(hostId, orgId)\n if (!callScope) return\n await completeCrmTask(user, { ...callScope, taskId: task.$id })\n enqueueSnackbar('Task completed', { variant: 'success' })\n }\n } catch (cause) {\n enqueueSnackbar(\n cause instanceof Error ? cause.message : 'The task could not be updated.',\n { variant: 'warning' },\n )\n } finally {\n setBusyId(null)\n }\n },\n [scope, busyId, firestore, user, hostId, orgId, enqueueSnackbar],\n )\n\n const columns: GridColDef[] = useMemo(\n () => [\n {\n field: 'status',\n headerName: '',\n width: 56,\n sortable: false,\n filterable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Checkbox\n size=\"small\"\n checked={row.status === 'done'}\n disabled={busyId === row.$id}\n onClick={(event) => {\n event.stopPropagation()\n void toggleDone(row)\n }}\n slotProps={{\n input: {\n 'aria-label':\n row.status === 'done'\n ? `Reopen \"${row.title}\"`\n : `Complete \"${row.title}\"`,\n },\n }}\n />\n ),\n },\n {\n field: 'title',\n headerName: 'Task',\n flex: 2,\n minWidth: 220,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Stack sx={{ justifyContent: 'center', height: '100%', minWidth: 0 }}>\n <Typography\n variant=\"body2\"\n noWrap\n sx={{\n textDecoration: row.status === 'done' ? 'line-through' : undefined,\n color: row.status === 'done' ? 'text.secondary' : undefined,\n }}\n >\n {row.title}\n </Typography>\n {row.notes ? (\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {row.notes}\n </Typography>\n ) : null}\n </Stack>\n ),\n },\n {\n field: 'kind',\n headerName: 'Kind',\n width: 120,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => <TaskKindCell kind={row.kind} />,\n },\n {\n field: 'priority',\n headerName: 'Priority',\n width: 110,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <TaskPriorityChip priority={row.priority} />\n ),\n },\n {\n field: 'dueAtMs',\n headerName: 'Due',\n width: 260,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Stack direction=\"row\" spacing={0.5} sx={{ alignItems: 'center', height: '100%' }}>\n <TaskDueText task={row} nowMs={nowMs} />\n {row.status === 'done' || !scope ? null : (\n <TaskSnoozeMenu\n dueAtMs={row.dueAtMs}\n remindAtMs={row.remindAtMs}\n target={{\n write: {\n scope,\n taskId: row.$id,\n call: crmTaskCallScope(hostId, orgId),\n links: row,\n },\n }}\n disabled={busyId === row.$id}\n />\n )}\n </Stack>\n ),\n },\n {\n field: 'assigneeUid',\n headerName: 'Assignee',\n flex: 1,\n minWidth: 140,\n sortable: false,\n valueGetter: (_value: unknown, row: CrmTaskRow) =>\n directory.nameOf(row.assigneeUid),\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Typography variant=\"body2\" color={row.assigneeUid ? undefined : 'text.secondary'}>\n {row.assigneeUid ? directory.nameOf(row.assigneeUid) : 'Unassigned'}\n </Typography>\n ),\n },\n {\n field: 'record',\n headerName: 'For',\n flex: 1,\n minWidth: 160,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <TaskRecordLink task={row} routes={routes} nameOf={nameOf} />\n ),\n },\n ],\n [busyId, toggleDone, nowMs, directory, routes, nameOf, scope],\n )\n /* The column and sort models are the view's (AGL-2617). */\n const filterColumns = useMemo(\n () => listFilterGridColumns(columns, TASK_FILTER_FIELDS, filterOptions, TASK_FILTER_HEADERS),\n [columns, filterOptions],\n )\n const grid = useCrmViewGrid(views, filterColumns, TASK_HIDDEN_COLUMNS)\n\n return (\n <>\n <CardDisplay\n header={'Tasks'}\n help={pluginDocsHelp('crmTasks', {\n anchor: '#the-tasks-page',\n excerpt:\n 'Calls, emails, meetings and to-dos, each linked to the contact, ' +\n 'company or deal it is for. Overdue and today are read off the ' +\n 'due date as you look.',\n })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n action: (\n <Button\n size=\"small\"\n variant=\"contained\"\n color=\"primary\"\n onClick={() => setDrawer({ open: true, task: null })}\n >\n {'New task'}\n </Button>\n ),\n }}\n >\n <Stack spacing={2}>\n {/*\n The saved view, and the clauses narrowing it as chips — \"Show\"\n among them — set in the grid's own Filters panel (AGL-3313).\n */}\n <CrmListToolbar label=\"Task filters\">\n <CrmViewsControl controller={views} allLabel=\"All tasks\" />\n <ListFilterChips\n fields={TASK_FILTER_FIELDS}\n headers={TASK_FILTER_HEADERS}\n clauses={clauses}\n onChange={setClauses}\n options={filterOptions}\n marksServed={false}\n />\n <ToggleButtonGroup\n exclusive\n size=\"small\"\n color=\"primary\"\n value={layout}\n onChange={(_event, next) => {\n if (next) setLayout(next as 'list' | 'calendar')\n }}\n aria-label=\"Task layout\"\n >\n <ToggleButton value=\"list\">{'List'}</ToggleButton>\n <ToggleButton value=\"calendar\">{'Calendar'}</ToggleButton>\n </ToggleButtonGroup>\n <Stack sx={{ flex: 1 }} />\n <TaskImportButton hostId={hostId} />\n <Button size=\"small\" onClick={handleExport} disabled={!tasks.length}>\n {'Export CSV'}\n </Button>\n </CrmListToolbar>\n <ListQueryNotices refused={refused} notices={list.plan.notices} />\n {status === 'error' ? (\n <Typography variant=\"body2\" color=\"error\">\n {'The tasks could not be loaded. Reload to try again.'}\n </Typography>\n ) : (\n <>\n {/*\n The calendar draws the same rows, so there is no bulk bar\n over it: a selection is a list gesture, and a month grid\n offers nowhere to make one.\n */}\n {layout === 'calendar' ? (\n <TasksCalendar\n tasks={tasks}\n truncated={list.hasMore}\n onOpen={(task) => setDrawer({ open: true, task })}\n />\n ) : (\n <>\n <TasksBulkBar\n hostId={hostId}\n scope={scope}\n rows={tasks}\n selected={selectedIds}\n onSelectedChange={setSelectedIds}\n directory={directory}\n csv={csvOptions}\n />\n <CrmColumnOrderProvider value={grid.columnOrder}>\n <ListTable\n rows={tasks}\n columns={grid.columns}\n slots={CRM_LIST_SLOTS}\n selectable={{ selected: selectedIds, onChange: setSelectedIds }}\n loading={status === 'loading'}\n onOpen={(id) => {\n const found = tasks.find((row) => row.$id === id)\n if (found) setDrawer({ open: true, task: found })\n }}\n /*\n * The panel and the search are the grid's; the section\n * answers them, the view through the query (AGL-3313). An\n * empty view is said inside the grid rather than instead of\n * it, so its toolbar stays to choose another view.\n */\n noRowsLabel={filtered ? 'No tasks match these filters' : EMPTY_LABEL[view]}\n noRowsDescription={filtered ? undefined : EMPTY_COPY[view]}\n noRowsAction={\n filtered ? undefined : (\n <Button\n size=\"small\"\n variant=\"contained\"\n color=\"primary\"\n onClick={() => setDrawer({ open: true, task: null })}\n >\n {'New task'}\n </Button>\n )\n }\n filterMode=\"server\"\n filterModel={gridFilter.filterModel}\n onFilterModelChange={gridFilter.onFilterModelChange}\n quickFilter\n // The view orders the query (due soonest, or Done most\n // recently due), so the grid sorts nothing itself: a\n // sort over one page would reorder ten rows.\n sortingMode=\"server\"\n disableColumnSorting\n // Columns are the view's, controlled (AGL-2617).\n columnVisibilityModel={grid.columnVisibilityModel}\n onColumnVisibilityModelChange={grid.onColumnVisibilityModelChange}\n // Paged by the footer below, so the grid must not also slice.\n hideFooter\n />\n </CrmColumnOrderProvider>\n <ListPagination\n page={list.page}\n pageSize={list.pageSize}\n rowCount={tasks.length}\n hasMore={list.hasMore}\n onPageChange={list.setPage}\n onPageSizeChange={list.setPageSize}\n />\n </>\n )}\n </>\n )}\n </Stack>\n </CardDisplay>\n <TaskEditDrawer\n open={drawer.open}\n onClose={() => setDrawer((prev) => ({ ...prev, open: false }))}\n hostId={hostId}\n org={orgRecord}\n orgId={orgId}\n scope={scope}\n readTokens={readTokens}\n task={drawer.task}\n seed={{ fromCache, unreadable: status === 'error' }}\n />\n </>\n )\n}\nTasksSection.displayName = 'TasksSection'\n\nexport default TasksSection\n"],"names":["CRM_COLLECTIONS","findOrgMember","pluginDocsHelp","CardDisplay","ListTable","useCrmSavedView","useCrmScope","useCrmViewGrid","CRM_LIST_SLOTS","CrmColumnOrderProvider","CrmViewsControl","useSnackbar","useFirestore","useUser","Button","Checkbox","Stack","ToggleButton","ToggleButtonGroup","Typography","deleteField","doc","serverTimestamp","updateDoc","useCallback","useEffect","useMemo","useState","useCrmRecordNames","useCrmTaskList","useNowMs","useOrgMemberDirectory","downloadTextFile","crmRoutes","refreshCrmNextActivity","completeCrmTask","crmTaskCallScope","tasksCsv","CRM_TASK_KIND_LABELS","CRM_TASK_KINDS","CRM_TASK_PRIORITIES","CRM_TASK_PRIORITY_LABELS","CRM_TASK_VIEWS","TASK_LIST_QUERY_FIELDS","listFilterGridColumns","ListPagination","TABLE_PAGE_SIZE_DEFAULT","ListQueryNotices","listQueryRefusals","useListGridFilter","ListFilterChips","CrmListToolbar","TaskDueText","TaskKindCell","TaskPriorityChip","TaskRecordLink","TaskEditDrawer","TasksCalendar","TaskImportButton","TaskSnoozeMenu","TasksBulkBar","TASK_FILTER_FIELDS","column","kind","path","operators","TASK_FILTER_HEADERS","view","priority","assigneeUid","TASK_HIDDEN_COLUMNS","CALENDAR_PAGE_SIZE","TASK_VIEW_DEFAULT","field","op","value","EMPTY_LABEL","mine","overdue","today","upcoming","open","done","EMPTY_COPY","TasksSection","props","hostId","org","basePath","orgRecord","firestore","data","user","enqueueSnackbar","nowMs","routes","consentGroup","groupId","views","section","state","filters","find","clause","some","option","id","clauses","setClauses","next","setFilters","filter","gridFilter","onChange","selectFields","queryClauses","list","uid","search","searchWords","tasks","status","fromCache","scope","orgId","readTokens","directory","filterOptions","map","label","members","member","refused","plan","fields","headers","options","filtered","length","word","trim","linked","flatMap","task","contactId","companyId","dealId","nameOf","records","selectedIds","setSelectedIds","page","csvOptions","assigneeEmail","email","recordName","handleExport","layout","setLayout","setPage","setListPage","setPageSize","setListPageSize","drawer","setDrawer","busyId","setBusyId","toggleDone","$id","completedAtMs","completedByUid","updatedAt","variant","callScope","taskId","cause","Error","message","columns","headerName","width","sortable","filterable","renderCell","row","size","checked","disabled","onClick","event","stopPropagation","slotProps","input","title","flex","minWidth","sx","justifyContent","height","noWrap","textDecoration","undefined","color","notes","direction","spacing","alignItems","dueAtMs","remindAtMs","target","write","call","links","valueGetter","_value","filterColumns","grid","header","help","anchor","excerpt","contentGutterX","contentGutterY","HeaderProps","action","controller","allLabel","marksServed","exclusive","_event","aria-label","notices","truncated","hasMore","onOpen","rows","selected","onSelectedChange","csv","columnOrder","slots","selectable","loading","found","noRowsLabel","noRowsDescription","noRowsAction","filterMode","filterModel","onFilterModelChange","quickFilter","sortingMode","disableColumnSorting","columnVisibilityModel","onColumnVisibilityModelChange","hideFooter","pageSize","rowCount","onPageChange","onPageSizeChange","onClose","prev","seed","unreadable","displayName"],"mappings":"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"}
@@ -15,4 +15,17 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  import type { ListFilterField } from '@aglyn/shared-ui-jsx/const/list-filter';
18
+ import type { ListQueryDeclaration, ListQuerySort } from '@aglyn/shared-ui-jsx/const/list-query-plan';
18
19
  export declare const COMPANY_LIST_FILTER_FIELDS: readonly ListFilterField[];
20
+ /**
21
+ * A collaborator's search (see `prefixSearch` in `useCrmListQuery`): the
22
+ * start of the name, beside the scope clause — the prefix range the
23
+ * `(field, nameLower)` composites already serve.
24
+ */
25
+ export declare const COMPANY_PREFIX_SEARCH: {
26
+ field: ListFilterField;
27
+ notice: string;
28
+ };
29
+ /** The list's orders: newest change first, and by name under a prefix. */
30
+ export declare const COMPANY_LIST_SORTS: readonly ListQuerySort[];
31
+ export declare const COMPANY_LIST_DECLARATION: ListQueryDeclaration;