@aglyn/plugins-crm 1.0.0-beta.200 → 1.0.0-beta.202
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.
- package/package.json +13 -13
- package/src/lib/components/activity-list.d.ts +36 -5
- package/src/lib/components/activity-list.js +159 -137
- package/src/lib/components/activity-list.js.map +1 -1
- package/src/lib/components/activity-timeline.d.ts +84 -0
- package/src/lib/components/activity-timeline.js +224 -0
- package/src/lib/components/activity-timeline.js.map +1 -0
- package/src/lib/components/company-properties-card.js +53 -36
- package/src/lib/components/company-properties-card.js.map +1 -1
- package/src/lib/components/contact-associations-card.d.ts +3 -2
- package/src/lib/components/contact-associations-card.js +12 -12
- package/src/lib/components/contact-associations-card.js.map +1 -1
- package/src/lib/components/contact-detail-page.d.ts +4 -3
- package/src/lib/components/contact-detail-page.js +4 -10
- package/src/lib/components/contact-detail-page.js.map +1 -1
- package/src/lib/components/contact-properties-card.d.ts +21 -4
- package/src/lib/components/contact-properties-card.js +129 -29
- package/src/lib/components/contact-properties-card.js.map +1 -1
- package/src/lib/components/contact-timeline-card.d.ts +12 -6
- package/src/lib/components/contact-timeline-card.js +132 -174
- package/src/lib/components/contact-timeline-card.js.map +1 -1
- package/src/lib/components/contacts-section.js +197 -198
- package/src/lib/components/contacts-section.js.map +1 -1
- package/src/lib/components/crm-email-state-chip.js +4 -1
- package/src/lib/components/crm-email-state-chip.js.map +1 -1
- package/src/lib/components/deal-products-card.js +15 -13
- package/src/lib/components/deal-products-card.js.map +1 -1
- package/src/lib/components/deal-properties-card.js +7 -0
- package/src/lib/components/deal-properties-card.js.map +1 -1
- package/src/lib/components/deal-stage-card.js +31 -29
- package/src/lib/components/deal-stage-card.js.map +1 -1
- package/src/lib/components/deals-section.js +9 -14
- package/src/lib/components/deals-section.js.map +1 -1
- package/src/lib/components/fields-section.d.ts +4 -0
- package/src/lib/components/fields-section.js +368 -154
- package/src/lib/components/fields-section.js.map +1 -1
- package/src/lib/components/form-contact-fields-card.js +24 -20
- package/src/lib/components/form-contact-fields-card.js.map +1 -1
- package/src/lib/components/lead-campaigns-card.d.ts +1 -1
- package/src/lib/components/lead-campaigns-card.js +32 -35
- package/src/lib/components/lead-campaigns-card.js.map +1 -1
- package/src/lib/components/lead-properties-card.d.ts +14 -6
- package/src/lib/components/lead-properties-card.js +317 -313
- package/src/lib/components/lead-properties-card.js.map +1 -1
- package/src/lib/components/lead-surfaces-note.js +13 -2
- package/src/lib/components/lead-surfaces-note.js.map +1 -1
- package/src/lib/components/linked-deals-card.js +12 -10
- package/src/lib/components/linked-deals-card.js.map +1 -1
- package/src/lib/components/recent-activity-feed.d.ts +12 -8
- package/src/lib/components/recent-activity-feed.js +54 -29
- package/src/lib/components/recent-activity-feed.js.map +1 -1
- package/src/lib/components/record-activity-card.d.ts +4 -2
- package/src/lib/components/record-activity-card.js +29 -11
- package/src/lib/components/record-activity-card.js.map +1 -1
- package/src/lib/components/reports/activity-card.js +18 -12
- package/src/lib/components/reports/activity-card.js.map +1 -1
- package/src/lib/components/reports/lead-funnel-card.js +47 -37
- package/src/lib/components/reports/lead-funnel-card.js.map +1 -1
- package/src/lib/components/reports/pipeline-card.js +22 -16
- package/src/lib/components/reports/pipeline-card.js.map +1 -1
- package/src/lib/components/reports/report-export.d.ts +4 -11
- package/src/lib/components/reports/report-export.js +16 -33
- package/src/lib/components/reports/report-export.js.map +1 -1
- package/src/lib/components/reports/source-conversion-card.js +18 -12
- package/src/lib/components/reports/source-conversion-card.js.map +1 -1
- package/src/lib/components/reports/tasks-card.js +35 -25
- package/src/lib/components/reports/tasks-card.js.map +1 -1
- package/src/lib/components/tasks-section.js +23 -23
- package/src/lib/components/tasks-section.js.map +1 -1
- package/src/lib/constants/field-list-query.d.ts +23 -0
- package/src/lib/constants/field-list-query.js +80 -0
- package/src/lib/constants/field-list-query.js.map +1 -0
- package/src/lib/model/lead-filters.d.ts +1 -1
- package/src/lib/server/capture-contact.js +7 -5
- package/src/lib/server/capture-contact.js.map +1 -1
- package/src/lib/components/contact-custom-fields-card.d.ts +0 -39
- package/src/lib/components/contact-custom-fields-card.js +0 -204
- package/src/lib/components/contact-custom-fields-card.js.map +0 -1
|
@@ -16,19 +16,27 @@
|
|
|
16
16
|
*/ 'use client';
|
|
17
17
|
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
18
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
19
|
-
import { CONTACT_FIELD_TYPE_LABELS, createResourceUid, CRM_COLLECTIONS, CRM_FIELD_OBJECT_LABELS, CRM_FIELD_OBJECTS, isCrmFieldObject, newResourceScopeFields, ORG_SCOPE_TOKEN, pluginDocsHelp } from "@aglyn/aglyn";
|
|
19
|
+
import { CONTACT_FIELD_TYPE_LABELS, CONTACT_FIELD_TYPES, CONTACT_FIELDS_MAX_PER_ORG, createResourceUid, CRM_COLLECTIONS, crmFieldListFields, CRM_FIELD_OBJECT_LABELS, CRM_FIELD_OBJECTS, isCrmFieldObject, newResourceScopeFields, ORG_SCOPE_TOKEN, pluginDocsHelp } from "@aglyn/aglyn";
|
|
20
20
|
import EmptyStateComponent from "@aglyn/shared-ui-jsx/components/empty-state.component";
|
|
21
|
+
import ListFilterChips from "@aglyn/shared-ui-jsx/components/list-filter-chips.component";
|
|
22
|
+
import ListQueryNotices, { listQueryRefusals } from "@aglyn/shared-ui-jsx/components/list-query-notices.component";
|
|
23
|
+
import { ListRowActions, ListTable, listActionsColumn } from "@aglyn/shared-ui-jsx/components/list-table.component";
|
|
21
24
|
import { mdiArchiveArrowUpOutline, mdiArchiveOutline, mdiArrowDown, mdiArrowUp, mdiDeleteOutline, mdiPencilOutline } from "@aglyn/shared-data-mdi";
|
|
22
25
|
import { CardDisplay, MdiIcon, SrOnly, useConfirmationContext } from "@aglyn/shared-ui-jsx";
|
|
23
|
-
import
|
|
24
|
-
import {
|
|
26
|
+
import { listFilterGridColumns } from "@aglyn/shared-ui-jsx/const/list-grid-filter";
|
|
27
|
+
import { planListQuery } from "@aglyn/shared-ui-jsx/const/list-query-plan";
|
|
28
|
+
import { useListGridFilter } from "@aglyn/shared-ui-jsx/hooks/use-list-grid-filter";
|
|
29
|
+
import { nameSearchNormalizers } from "@aglyn/aglyn/app-utils/name-search";
|
|
25
30
|
import { useSnackbar } from "@aglyn/shared-ui-snackstack";
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
31
|
+
import { ceilingedWindow } from "@aglyn/tenant-feature-instance/hooks/host-collection-queries";
|
|
32
|
+
import { listQueryConstraints } from "@aglyn/tenant-feature-instance/hooks/use-list-query";
|
|
33
|
+
import { useFirestore, useFirestoreCollection, useUser, writeGuardedBySeed } from "@aglyn/tenant-feature-instance";
|
|
34
|
+
import { Button, Chip, IconButton, Stack, Tab, Tabs, Tooltip, Typography } from "@mui/material";
|
|
35
|
+
import { collection, deleteDoc, doc, limit, query, setDoc, updateDoc, writeBatch } from "firebase/firestore";
|
|
36
|
+
import { useCallback, useMemo, useState } from "react";
|
|
30
37
|
import { useContactFieldDefinitions } from "../hooks/use-contact-field-definitions.js";
|
|
31
38
|
import { useCrmScope } from "../hooks/use-crm-scope.js";
|
|
39
|
+
import { CRM_FIELD_LIST_QUERY, crmFieldListBase } from "../constants/field-list-query.js";
|
|
32
40
|
import ContactFieldDrawer from "./contact-field-drawer.js";
|
|
33
41
|
import { LeadSourceValuesCard } from "./lead-source-values-card.js";
|
|
34
42
|
import { recomputeAllCrmNextActivity } from "../model/next-activity-api.js";
|
|
@@ -45,6 +53,322 @@ import { crmTaskCallScope } from "../model/task-routes.js";
|
|
|
45
53
|
deal: 'deal',
|
|
46
54
|
lead: 'lead'
|
|
47
55
|
};
|
|
56
|
+
/** What the grid's Filters panel offers: the type and whether it is required, on the query. */ const FIELD_FILTER_FIELDS = CRM_FIELD_LIST_QUERY.fields;
|
|
57
|
+
const FIELD_FILTER_HEADERS = {
|
|
58
|
+
type: 'Type',
|
|
59
|
+
required: 'Required'
|
|
60
|
+
};
|
|
61
|
+
const FIELD_FILTER_OPTIONS = {
|
|
62
|
+
type: CONTACT_FIELD_TYPES.map((type)=>({
|
|
63
|
+
value: type,
|
|
64
|
+
label: CONTACT_FIELD_TYPE_LABELS[type]
|
|
65
|
+
})),
|
|
66
|
+
required: [
|
|
67
|
+
{
|
|
68
|
+
value: 'true',
|
|
69
|
+
label: 'Required'
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
value: 'false',
|
|
73
|
+
label: 'Optional'
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
};
|
|
77
|
+
/** Why the arrows are off while the list is not in its stored order. */ export const FIELD_REORDER_LOCKED_REASON = 'Clear sorting and filters to reorder';
|
|
78
|
+
const typeLabel = (type)=>{
|
|
79
|
+
var _CONTACT_FIELD_TYPE_LABELS_type;
|
|
80
|
+
return (_CONTACT_FIELD_TYPE_LABELS_type = CONTACT_FIELD_TYPE_LABELS[type]) != null ? _CONTACT_FIELD_TYPE_LABELS_type : String(type != null ? type : '');
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* One tab's field definitions in the console's list table (AGL-3335): the
|
|
84
|
+
* toolbar's columns, filters, export and search, sorting by Field, Key and
|
|
85
|
+
* Type, and the shared footer.
|
|
86
|
+
*
|
|
87
|
+
* ## Order is data, not a sort
|
|
88
|
+
*
|
|
89
|
+
* The stored `order` is where each field appears on every record and form,
|
|
90
|
+
* so the arrows that move it are kept, and are live only while the table
|
|
91
|
+
* shows that order: no sort, no filter and no search. Under any of them the
|
|
92
|
+
* row above a field on screen is not the field above it in the stored
|
|
93
|
+
* order, and a move would land somewhere the reader cannot see; the arrows
|
|
94
|
+
* say so rather than disappear.
|
|
95
|
+
*
|
|
96
|
+
* The panel and the search are asked of Firestore (AGL-3321): a clause or
|
|
97
|
+
* a search word reads the tab's definitions that match it
|
|
98
|
+
* (`CRM_FIELD_LIST_QUERY`), and never narrows the rows already on screen.
|
|
99
|
+
* That answer is every match, at most `CONTACT_FIELDS_MAX_PER_ORG`, so the
|
|
100
|
+
* grid sorts and pages it whole; a read that reaches the ceiling says so.
|
|
101
|
+
*/ function FieldsTable(props) {
|
|
102
|
+
const { orgId, object, definitions, busyId, onMove, rowActions } = props;
|
|
103
|
+
const firestore = useFirestore();
|
|
104
|
+
const gridFilter = useListGridFilter({
|
|
105
|
+
selectFields: [
|
|
106
|
+
'type',
|
|
107
|
+
'required'
|
|
108
|
+
]
|
|
109
|
+
});
|
|
110
|
+
const [sortModel, setSortModel] = useState([]);
|
|
111
|
+
const searching = gridFilter.searchWords.some((word)=>word.trim() !== '');
|
|
112
|
+
const reorderLocked = sortModel.length > 0 || gridFilter.clauses.length > 0 || searching;
|
|
113
|
+
const narrowed = gridFilter.clauses.length > 0 || searching;
|
|
114
|
+
const plan = useMemo(()=>planListQuery(CRM_FIELD_LIST_QUERY, {
|
|
115
|
+
clauses: gridFilter.clauses,
|
|
116
|
+
search: gridFilter.searchWords,
|
|
117
|
+
base: crmFieldListBase(object)
|
|
118
|
+
}, nameSearchNormalizers), // The words are a new array each render; their text is their identity.
|
|
119
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
120
|
+
[
|
|
121
|
+
object,
|
|
122
|
+
gridFilter.clauses,
|
|
123
|
+
gridFilter.searchWords.join(' ')
|
|
124
|
+
]);
|
|
125
|
+
const planKey = JSON.stringify({
|
|
126
|
+
filters: plan.filters,
|
|
127
|
+
orderBy: plan.orderBy
|
|
128
|
+
});
|
|
129
|
+
/*
|
|
130
|
+
* Read only while something narrows the tab. Unnarrowed, the table is the
|
|
131
|
+
* shared definitions read every CRM surface already holds, in its stored
|
|
132
|
+
* order — the same fields, with no second read.
|
|
133
|
+
*/ const matched = useFirestoreCollection(()=>narrowed && orgId ? query(collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.contactFields), ...listQueryConstraints(plan), limit(CONTACT_FIELDS_MAX_PER_ORG + 1)) : null, [
|
|
134
|
+
firestore,
|
|
135
|
+
orgId,
|
|
136
|
+
narrowed,
|
|
137
|
+
planKey
|
|
138
|
+
], {
|
|
139
|
+
idField: '$id'
|
|
140
|
+
});
|
|
141
|
+
const answer = useMemo(()=>ceilingedWindow(matched.data, CONTACT_FIELDS_MAX_PER_ORG), [
|
|
142
|
+
matched.data
|
|
143
|
+
]);
|
|
144
|
+
const positions = useMemo(()=>new Map(definitions.map((definition, position)=>[
|
|
145
|
+
definition.$id,
|
|
146
|
+
position
|
|
147
|
+
])), [
|
|
148
|
+
definitions
|
|
149
|
+
]);
|
|
150
|
+
const rows = useMemo(()=>{
|
|
151
|
+
const shown = narrowed ? [
|
|
152
|
+
...answer.rows
|
|
153
|
+
].sort((a, b)=>{
|
|
154
|
+
var _positions_get, _positions_get1;
|
|
155
|
+
return ((_positions_get = positions.get(a.$id)) != null ? _positions_get : Number.MAX_SAFE_INTEGER) - ((_positions_get1 = positions.get(b.$id)) != null ? _positions_get1 : Number.MAX_SAFE_INTEGER);
|
|
156
|
+
}) : definitions;
|
|
157
|
+
return shown.map((definition)=>{
|
|
158
|
+
var _positions_get;
|
|
159
|
+
return {
|
|
160
|
+
$id: definition.$id,
|
|
161
|
+
label: definition.label,
|
|
162
|
+
key: definition.key,
|
|
163
|
+
type: definition.type,
|
|
164
|
+
required: definition.required ? 'true' : 'false',
|
|
165
|
+
position: (_positions_get = positions.get(definition.$id)) != null ? _positions_get : 0,
|
|
166
|
+
definition
|
|
167
|
+
};
|
|
168
|
+
});
|
|
169
|
+
}, [
|
|
170
|
+
narrowed,
|
|
171
|
+
answer.rows,
|
|
172
|
+
definitions,
|
|
173
|
+
positions
|
|
174
|
+
]);
|
|
175
|
+
const refused = useMemo(()=>listQueryRefusals(plan.refused, {
|
|
176
|
+
fields: FIELD_FILTER_FIELDS,
|
|
177
|
+
headers: FIELD_FILTER_HEADERS,
|
|
178
|
+
options: FIELD_FILTER_OPTIONS
|
|
179
|
+
}), [
|
|
180
|
+
plan.refused
|
|
181
|
+
]);
|
|
182
|
+
const columns = useMemo(()=>listFilterGridColumns([
|
|
183
|
+
{
|
|
184
|
+
field: 'position',
|
|
185
|
+
headerName: 'Order',
|
|
186
|
+
width: 132,
|
|
187
|
+
sortable: false,
|
|
188
|
+
filterable: false,
|
|
189
|
+
hideable: false,
|
|
190
|
+
disableColumnMenu: true,
|
|
191
|
+
renderCell: ({ row })=>{
|
|
192
|
+
const arrows = /*#__PURE__*/ _jsxs(Stack, {
|
|
193
|
+
direction: "row",
|
|
194
|
+
spacing: 0,
|
|
195
|
+
sx: {
|
|
196
|
+
alignItems: 'center'
|
|
197
|
+
},
|
|
198
|
+
children: [
|
|
199
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
200
|
+
variant: "body2",
|
|
201
|
+
color: "text.secondary",
|
|
202
|
+
sx: {
|
|
203
|
+
minWidth: 24,
|
|
204
|
+
textAlign: 'right',
|
|
205
|
+
mr: 0.5
|
|
206
|
+
},
|
|
207
|
+
children: row.position + 1
|
|
208
|
+
}),
|
|
209
|
+
/*#__PURE__*/ _jsxs(IconButton, {
|
|
210
|
+
size: "small",
|
|
211
|
+
disabled: reorderLocked || row.position === 0 || Boolean(busyId),
|
|
212
|
+
onClick: ()=>onMove(row.definition, -1),
|
|
213
|
+
children: [
|
|
214
|
+
/*#__PURE__*/ _jsx(MdiIcon, {
|
|
215
|
+
path: mdiArrowUp.path,
|
|
216
|
+
size: 0.7
|
|
217
|
+
}),
|
|
218
|
+
/*#__PURE__*/ _jsx(SrOnly, {
|
|
219
|
+
children: `Move ${row.label} up`
|
|
220
|
+
})
|
|
221
|
+
]
|
|
222
|
+
}),
|
|
223
|
+
/*#__PURE__*/ _jsxs(IconButton, {
|
|
224
|
+
size: "small",
|
|
225
|
+
disabled: reorderLocked || row.position === definitions.length - 1 || Boolean(busyId),
|
|
226
|
+
onClick: ()=>onMove(row.definition, 1),
|
|
227
|
+
children: [
|
|
228
|
+
/*#__PURE__*/ _jsx(MdiIcon, {
|
|
229
|
+
path: mdiArrowDown.path,
|
|
230
|
+
size: 0.7
|
|
231
|
+
}),
|
|
232
|
+
/*#__PURE__*/ _jsx(SrOnly, {
|
|
233
|
+
children: `Move ${row.label} down`
|
|
234
|
+
})
|
|
235
|
+
]
|
|
236
|
+
})
|
|
237
|
+
]
|
|
238
|
+
});
|
|
239
|
+
return reorderLocked ? /*#__PURE__*/ _jsx(Tooltip, {
|
|
240
|
+
title: FIELD_REORDER_LOCKED_REASON,
|
|
241
|
+
children: /*#__PURE__*/ _jsx("span", {
|
|
242
|
+
children: arrows
|
|
243
|
+
})
|
|
244
|
+
}) : arrows;
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
field: 'label',
|
|
249
|
+
headerName: 'Field',
|
|
250
|
+
flex: 1,
|
|
251
|
+
minWidth: 180,
|
|
252
|
+
renderCell: ({ row })=>/*#__PURE__*/ _jsxs(Stack, {
|
|
253
|
+
direction: "row",
|
|
254
|
+
spacing: 1,
|
|
255
|
+
sx: {
|
|
256
|
+
flexWrap: 'wrap',
|
|
257
|
+
alignItems: 'center'
|
|
258
|
+
},
|
|
259
|
+
children: [
|
|
260
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
261
|
+
variant: "body2",
|
|
262
|
+
children: row.label
|
|
263
|
+
}),
|
|
264
|
+
row.definition.retiredAt ? /*#__PURE__*/ _jsx(Chip, {
|
|
265
|
+
size: "small",
|
|
266
|
+
variant: "outlined",
|
|
267
|
+
color: "warning",
|
|
268
|
+
label: "Retired"
|
|
269
|
+
}) : null
|
|
270
|
+
]
|
|
271
|
+
})
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
field: 'key',
|
|
275
|
+
headerName: 'Key',
|
|
276
|
+
flex: 1,
|
|
277
|
+
minWidth: 160,
|
|
278
|
+
renderCell: ({ row })=>/*#__PURE__*/ _jsx(Typography, {
|
|
279
|
+
variant: "body2",
|
|
280
|
+
color: "text.secondary",
|
|
281
|
+
sx: {
|
|
282
|
+
fontFamily: 'monospace'
|
|
283
|
+
},
|
|
284
|
+
children: row.key
|
|
285
|
+
})
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
field: 'type',
|
|
289
|
+
headerName: 'Type',
|
|
290
|
+
width: 170,
|
|
291
|
+
// By what the type reads as, not by its stored key.
|
|
292
|
+
sortComparator: (a, b)=>typeLabel(a).localeCompare(typeLabel(b)),
|
|
293
|
+
renderCell: ({ row })=>{
|
|
294
|
+
var _row_definition_options;
|
|
295
|
+
return /*#__PURE__*/ _jsxs(Typography, {
|
|
296
|
+
variant: "body2",
|
|
297
|
+
children: [
|
|
298
|
+
typeLabel(row.type),
|
|
299
|
+
row.definition.type === 'select' && ((_row_definition_options = row.definition.options) == null ? void 0 : _row_definition_options.length) ? ` · ${row.definition.options.length} choices` : ''
|
|
300
|
+
]
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
field: 'required',
|
|
306
|
+
headerName: 'Required',
|
|
307
|
+
width: 120,
|
|
308
|
+
sortable: false,
|
|
309
|
+
renderCell: ({ row })=>/*#__PURE__*/ _jsx(Typography, {
|
|
310
|
+
variant: "body2",
|
|
311
|
+
color: "text.secondary",
|
|
312
|
+
children: row.required === 'true' ? 'Yes' : '—'
|
|
313
|
+
})
|
|
314
|
+
},
|
|
315
|
+
listActionsColumn((row)=>/*#__PURE__*/ _jsx(ListRowActions, {
|
|
316
|
+
label: row.label,
|
|
317
|
+
items: rowActions(row.definition)
|
|
318
|
+
}), {
|
|
319
|
+
width: 72
|
|
320
|
+
})
|
|
321
|
+
], FIELD_FILTER_FIELDS, FIELD_FILTER_OPTIONS, FIELD_FILTER_HEADERS), [
|
|
322
|
+
reorderLocked,
|
|
323
|
+
busyId,
|
|
324
|
+
onMove,
|
|
325
|
+
rowActions,
|
|
326
|
+
definitions.length
|
|
327
|
+
]);
|
|
328
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
329
|
+
spacing: 1,
|
|
330
|
+
children: [
|
|
331
|
+
/*#__PURE__*/ _jsx(ListFilterChips, {
|
|
332
|
+
fields: FIELD_FILTER_FIELDS,
|
|
333
|
+
headers: FIELD_FILTER_HEADERS,
|
|
334
|
+
clauses: gridFilter.clauses,
|
|
335
|
+
onChange: gridFilter.setClauses,
|
|
336
|
+
options: FIELD_FILTER_OPTIONS,
|
|
337
|
+
marksServed: false
|
|
338
|
+
}),
|
|
339
|
+
/*#__PURE__*/ _jsx(ListQueryNotices, {
|
|
340
|
+
refused: refused,
|
|
341
|
+
notices: plan.notices
|
|
342
|
+
}),
|
|
343
|
+
narrowed && answer.truncated ? /*#__PURE__*/ _jsx(Typography, {
|
|
344
|
+
variant: "caption",
|
|
345
|
+
color: "text.secondary",
|
|
346
|
+
children: `Showing the first ${CONTACT_FIELDS_MAX_PER_ORG} matching fields.`
|
|
347
|
+
}) : null,
|
|
348
|
+
/*#__PURE__*/ _jsx(ListTable, {
|
|
349
|
+
"aria-label": "Fields",
|
|
350
|
+
rows: rows,
|
|
351
|
+
loading: narrowed && matched.status === 'loading',
|
|
352
|
+
columns: columns,
|
|
353
|
+
sortModel: sortModel,
|
|
354
|
+
onSortModelChange: setSortModel,
|
|
355
|
+
// Firestore narrowed the rows above; the grid only draws them.
|
|
356
|
+
filterMode: "server",
|
|
357
|
+
filterModel: gridFilter.filterModel,
|
|
358
|
+
onFilterModelChange: gridFilter.onFilterModelChange,
|
|
359
|
+
quickFilter: true,
|
|
360
|
+
noRowsLabel: "No fields match these filters",
|
|
361
|
+
getRowClassName: ({ row })=>row.definition.retiredAt ? 'field-retired' : '',
|
|
362
|
+
sx: {
|
|
363
|
+
'& .field-retired': {
|
|
364
|
+
opacity: 0.6
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
})
|
|
368
|
+
]
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
FieldsTable.displayName = 'FieldsTable';
|
|
48
372
|
/**
|
|
49
373
|
* `/crm/fields` — the custom fields a holder keeps on a person (AGL-2601),
|
|
50
374
|
* since AGL-2661 on a company and a deal too, and since AGL-3272 on a lead:
|
|
@@ -63,6 +387,8 @@ import { crmTaskCallScope } from "../model/task-routes.js";
|
|
|
63
387
|
* rename is a new field and a retire.
|
|
64
388
|
* - Order is a stored `order` on each document, moved with the arrows here,
|
|
65
389
|
* and every reader sorts by it — the profile card, the columns, an export.
|
|
390
|
+
* The list table sorts, filters and searches a tab too (AGL-3335), and
|
|
391
|
+
* the arrows wait while it does — see `FieldsTable`.
|
|
66
392
|
*
|
|
67
393
|
* ## What is NOT on this page
|
|
68
394
|
*
|
|
@@ -179,8 +505,10 @@ import { crmTaskCallScope } from "../model/task-routes.js";
|
|
|
179
505
|
label: draft.label
|
|
180
506
|
}, editing.type === 'select' ? {
|
|
181
507
|
options: draft.options
|
|
182
|
-
} : {}, {
|
|
183
|
-
|
|
508
|
+
} : {}, crmFieldListFields(_extends({}, editing, {
|
|
509
|
+
label: draft.label,
|
|
510
|
+
required: draft.required
|
|
511
|
+
})), {
|
|
184
512
|
updatedAt: now
|
|
185
513
|
}));
|
|
186
514
|
});
|
|
@@ -205,9 +533,13 @@ import { crmTaskCallScope } from "../model/task-routes.js";
|
|
|
205
533
|
} : {}, {
|
|
206
534
|
required: draft.required,
|
|
207
535
|
order,
|
|
208
|
-
retiredAt: null
|
|
209
|
-
|
|
210
|
-
|
|
536
|
+
retiredAt: null
|
|
537
|
+
}, crmFieldListFields({
|
|
538
|
+
key: draft.key,
|
|
539
|
+
label: draft.label,
|
|
540
|
+
required: draft.required,
|
|
541
|
+
object
|
|
542
|
+
}), {
|
|
211
543
|
hostId: createHostId
|
|
212
544
|
}, newResourceScopeFields([
|
|
213
545
|
ORG_SCOPE_TOKEN
|
|
@@ -382,7 +714,10 @@ import { crmTaskCallScope } from "../model/task-routes.js";
|
|
|
382
714
|
enqueueSnackbar,
|
|
383
715
|
noun
|
|
384
716
|
]);
|
|
385
|
-
|
|
717
|
+
/*
|
|
718
|
+
* Stable across renders, as the table's columns are built from them: a
|
|
719
|
+
* fresh function each render would rebuild every column on every render.
|
|
720
|
+
*/ const rowActions = useCallback((definition)=>[
|
|
386
721
|
{
|
|
387
722
|
key: 'edit',
|
|
388
723
|
label: 'Edit field',
|
|
@@ -418,7 +753,15 @@ import { crmTaskCallScope } from "../model/task-routes.js";
|
|
|
418
753
|
onClick: ()=>void handleDelete(definition)
|
|
419
754
|
}
|
|
420
755
|
] : []
|
|
421
|
-
]
|
|
756
|
+
], [
|
|
757
|
+
openEdit,
|
|
758
|
+
toggleRetired,
|
|
759
|
+
handleDelete,
|
|
760
|
+
busyId
|
|
761
|
+
]);
|
|
762
|
+
const onMove = useCallback((definition, direction)=>void move(definition, direction), [
|
|
763
|
+
move
|
|
764
|
+
]);
|
|
422
765
|
return /*#__PURE__*/ _jsxs(CardDisplay, {
|
|
423
766
|
header: 'Fields',
|
|
424
767
|
help: pluginDocsHelp('contactFields', {
|
|
@@ -481,146 +824,17 @@ import { crmTaskCallScope } from "../model/task-routes.js";
|
|
|
481
824
|
onClick: openCreate,
|
|
482
825
|
children: 'New field'
|
|
483
826
|
}) : undefined
|
|
484
|
-
}) :
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
}),
|
|
496
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
497
|
-
children: 'Field'
|
|
498
|
-
}),
|
|
499
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
500
|
-
children: 'Key'
|
|
501
|
-
}),
|
|
502
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
503
|
-
children: 'Type'
|
|
504
|
-
}),
|
|
505
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
506
|
-
children: 'Required'
|
|
507
|
-
}),
|
|
508
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
509
|
-
align: "right"
|
|
510
|
-
})
|
|
511
|
-
]
|
|
512
|
-
})
|
|
513
|
-
}),
|
|
514
|
-
/*#__PURE__*/ _jsx(TableBody, {
|
|
515
|
-
children: definitions.map((definition, index)=>{
|
|
516
|
-
var _CONTACT_FIELD_TYPE_LABELS_definition_type;
|
|
517
|
-
var _definition_options;
|
|
518
|
-
return /*#__PURE__*/ _jsxs(TableRow, {
|
|
519
|
-
hover: true,
|
|
520
|
-
sx: definition.retiredAt ? {
|
|
521
|
-
opacity: 0.6
|
|
522
|
-
} : undefined,
|
|
523
|
-
children: [
|
|
524
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
525
|
-
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
526
|
-
direction: "row",
|
|
527
|
-
spacing: 0,
|
|
528
|
-
children: [
|
|
529
|
-
/*#__PURE__*/ _jsxs(IconButton, {
|
|
530
|
-
size: "small",
|
|
531
|
-
disabled: index === 0 || Boolean(busyId),
|
|
532
|
-
onClick: ()=>void move(definition, -1),
|
|
533
|
-
children: [
|
|
534
|
-
/*#__PURE__*/ _jsx(MdiIcon, {
|
|
535
|
-
path: mdiArrowUp.path,
|
|
536
|
-
size: 0.7
|
|
537
|
-
}),
|
|
538
|
-
/*#__PURE__*/ _jsx(SrOnly, {
|
|
539
|
-
children: `Move ${definition.label} up`
|
|
540
|
-
})
|
|
541
|
-
]
|
|
542
|
-
}),
|
|
543
|
-
/*#__PURE__*/ _jsxs(IconButton, {
|
|
544
|
-
size: "small",
|
|
545
|
-
disabled: index === definitions.length - 1 || Boolean(busyId),
|
|
546
|
-
onClick: ()=>void move(definition, 1),
|
|
547
|
-
children: [
|
|
548
|
-
/*#__PURE__*/ _jsx(MdiIcon, {
|
|
549
|
-
path: mdiArrowDown.path,
|
|
550
|
-
size: 0.7
|
|
551
|
-
}),
|
|
552
|
-
/*#__PURE__*/ _jsx(SrOnly, {
|
|
553
|
-
children: `Move ${definition.label} down`
|
|
554
|
-
})
|
|
555
|
-
]
|
|
556
|
-
})
|
|
557
|
-
]
|
|
558
|
-
})
|
|
559
|
-
}),
|
|
560
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
561
|
-
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
562
|
-
direction: "row",
|
|
563
|
-
spacing: 1,
|
|
564
|
-
sx: {
|
|
565
|
-
flexWrap: 'wrap',
|
|
566
|
-
alignItems: 'center'
|
|
567
|
-
},
|
|
568
|
-
children: [
|
|
569
|
-
/*#__PURE__*/ _jsx(Typography, {
|
|
570
|
-
variant: "body2",
|
|
571
|
-
children: definition.label
|
|
572
|
-
}),
|
|
573
|
-
definition.retiredAt ? /*#__PURE__*/ _jsx(Chip, {
|
|
574
|
-
size: "small",
|
|
575
|
-
variant: "outlined",
|
|
576
|
-
color: "warning",
|
|
577
|
-
label: "Retired"
|
|
578
|
-
}) : null
|
|
579
|
-
]
|
|
580
|
-
})
|
|
581
|
-
}),
|
|
582
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
583
|
-
children: /*#__PURE__*/ _jsx(Typography, {
|
|
584
|
-
variant: "body2",
|
|
585
|
-
color: "text.secondary",
|
|
586
|
-
sx: {
|
|
587
|
-
fontFamily: 'monospace'
|
|
588
|
-
},
|
|
589
|
-
children: definition.key
|
|
590
|
-
})
|
|
591
|
-
}),
|
|
592
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
593
|
-
children: /*#__PURE__*/ _jsxs(Typography, {
|
|
594
|
-
variant: "body2",
|
|
595
|
-
children: [
|
|
596
|
-
(_CONTACT_FIELD_TYPE_LABELS_definition_type = CONTACT_FIELD_TYPE_LABELS[definition.type]) != null ? _CONTACT_FIELD_TYPE_LABELS_definition_type : definition.type,
|
|
597
|
-
definition.type === 'select' && ((_definition_options = definition.options) == null ? void 0 : _definition_options.length) ? ` · ${definition.options.length} choices` : ''
|
|
598
|
-
]
|
|
599
|
-
})
|
|
600
|
-
}),
|
|
601
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
602
|
-
children: /*#__PURE__*/ _jsx(Typography, {
|
|
603
|
-
variant: "body2",
|
|
604
|
-
color: "text.secondary",
|
|
605
|
-
children: definition.required ? 'Yes' : '—'
|
|
606
|
-
})
|
|
607
|
-
}),
|
|
608
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
609
|
-
align: "right",
|
|
610
|
-
sx: {
|
|
611
|
-
width: 56
|
|
612
|
-
},
|
|
613
|
-
children: /*#__PURE__*/ _jsx(RowActionsMenu, {
|
|
614
|
-
label: definition.label,
|
|
615
|
-
items: rowActions(definition)
|
|
616
|
-
})
|
|
617
|
-
})
|
|
618
|
-
]
|
|
619
|
-
}, definition.$id);
|
|
620
|
-
})
|
|
621
|
-
})
|
|
622
|
-
]
|
|
623
|
-
}),
|
|
827
|
+
}) : /*
|
|
828
|
+
Keyed by the tab, so a sort, a filter or a search made on one
|
|
829
|
+
record's fields does not follow the reader onto another's.
|
|
830
|
+
*/ /*#__PURE__*/ _jsx(FieldsTable, {
|
|
831
|
+
orgId: orgId,
|
|
832
|
+
object: object,
|
|
833
|
+
definitions: definitions,
|
|
834
|
+
busyId: busyId,
|
|
835
|
+
onMove: onMove,
|
|
836
|
+
rowActions: rowActions
|
|
837
|
+
}, object),
|
|
624
838
|
definitions.length ? /*#__PURE__*/ _jsx(Typography, {
|
|
625
839
|
variant: "caption",
|
|
626
840
|
color: "text.secondary",
|