@aglyn/plugins-crm 1.0.0-beta.186 → 1.0.0-beta.188
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/companies-section.js +6 -6
- package/src/lib/components/companies-section.js.map +1 -1
- package/src/lib/components/contacts-section.js +7 -7
- package/src/lib/components/contacts-section.js.map +1 -1
- package/src/lib/components/deals-section.js +75 -23
- package/src/lib/components/deals-section.js.map +1 -1
- package/src/lib/components/leads-section.js +6 -6
- package/src/lib/components/leads-section.js.map +1 -1
- package/src/lib/components/tasks-section.js +7 -7
- package/src/lib/components/tasks-section.js.map +1 -1
- package/src/lib/hooks/use-deals.d.ts +21 -0
- package/src/lib/hooks/use-deals.js +34 -0
- package/src/lib/hooks/use-deals.js.map +1 -1
- package/src/lib/model/lead-filters.d.ts +4 -4
- package/src/lib/model/lead-filters.js +5 -5
- package/src/lib/model/lead-filters.js.map +1 -1
- package/src/lib/components/crm-filter-bar.d.ts +0 -55
- package/src/lib/components/crm-filter-bar.js +0 -93
- package/src/lib/components/crm-filter-bar.js.map +0 -1
- package/src/lib/hooks/use-crm-grid-filter.d.ts +0 -77
- package/src/lib/hooks/use-crm-grid-filter.js +0 -143
- package/src/lib/hooks/use-crm-grid-filter.js.map +0 -1
- package/src/lib/model/crm-grid-filter.d.ts +0 -64
- package/src/lib/model/crm-grid-filter.js +0 -144
- package/src/lib/model/crm-grid-filter.js.map +0 -1
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2026 Aglyn LLC
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/ 'use client';
|
|
17
|
-
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
|
-
import { useCallback, useMemo, useState } from "react";
|
|
19
|
-
import { crmPlainCodec, crmSelectCodec, crmUpsertClause } from "../model/crm-grid-filter.js";
|
|
20
|
-
/**
|
|
21
|
-
* The grid's Filters panel and quick search, bound to a list's view clauses
|
|
22
|
-
* (AGL-3313). See `model/crm-grid-filter.ts` for the shape both sides keep.
|
|
23
|
-
*
|
|
24
|
-
* ## One field, one clause; the panel edits one at a time
|
|
25
|
-
*
|
|
26
|
-
* The free DataGrid's panel holds a single item, while a saved view
|
|
27
|
-
* holds several clauses. So each FIELD holds one clause, and the panel is a
|
|
28
|
-
* window onto whichever field was last filtered: setting a value writes
|
|
29
|
-
* that field's clause, clearing it or deleting the row removes it, and
|
|
30
|
-
* choosing another column in the panel moves the window without touching
|
|
31
|
-
* the clause the reader just set. Filtering Lead source and then Status is
|
|
32
|
-
* therefore both, which is what a reader who does it means; the chips over
|
|
33
|
-
* the grid (`CrmFilterBar`) show every clause and remove any of them.
|
|
34
|
-
*
|
|
35
|
-
* ## The list answers, never the grid
|
|
36
|
-
*
|
|
37
|
-
* Every list passes `filterMode="server"`: the grid holds one page, or a
|
|
38
|
-
* window the query already narrowed, so a filter the grid ran itself would
|
|
39
|
-
* answer "no match" for a row on the next page. The list reads the clauses
|
|
40
|
-
* — onto its query where it can, over its loaded rows where it cannot —
|
|
41
|
-
* and the quick search's words, and hands the grid the rows that answer.
|
|
42
|
-
*/ export function useCrmGridFilter(options) {
|
|
43
|
-
var _ref, _ref1;
|
|
44
|
-
var _options_search, _options_search1;
|
|
45
|
-
const { clauses, onChange, selectFields = [], codecs = {}, single = false, keepAlongside } = options;
|
|
46
|
-
const codecFor = useCallback((field)=>{
|
|
47
|
-
var _codecs_field;
|
|
48
|
-
return (_codecs_field = codecs[field]) != null ? _codecs_field : selectFields.includes(field) ? crmSelectCodec : crmPlainCodec;
|
|
49
|
-
}, [
|
|
50
|
-
codecs,
|
|
51
|
-
selectFields
|
|
52
|
-
]);
|
|
53
|
-
/** The field the panel shows, once the reader has pointed it anywhere. */ const [focus, setFocus] = useState(null);
|
|
54
|
-
/** The panel's row while it holds no value yet — a column chosen, a value not. */ const [pending, setPending] = useState(null);
|
|
55
|
-
const [ownWords, setOwnWords] = useState([]);
|
|
56
|
-
const searchWords = (_ref = (_options_search = options.search) == null ? void 0 : _options_search.words) != null ? _ref : ownWords;
|
|
57
|
-
const setSearchWords = (_ref1 = (_options_search1 = options.search) == null ? void 0 : _options_search1.onChange) != null ? _ref1 : setOwnWords;
|
|
58
|
-
/** Whatever the panel last pointed at, else the newest clause it can show. */ const shownField = useMemo(()=>{
|
|
59
|
-
if (focus) return focus;
|
|
60
|
-
for(let at = clauses.length - 1; at >= 0; at -= 1){
|
|
61
|
-
if (codecFor(clauses[at].field).toItem(clauses[at])) return clauses[at].field;
|
|
62
|
-
}
|
|
63
|
-
return null;
|
|
64
|
-
}, [
|
|
65
|
-
focus,
|
|
66
|
-
clauses,
|
|
67
|
-
codecFor
|
|
68
|
-
]);
|
|
69
|
-
const filterModel = useMemo(()=>{
|
|
70
|
-
const clause = shownField ? clauses.find((entry)=>entry.field === shownField) : undefined;
|
|
71
|
-
const shown = clause ? codecFor(clause.field).toItem(clause) : null;
|
|
72
|
-
const item = pending && pending.field === shownField ? pending : clause && shown ? _extends({
|
|
73
|
-
id: 'crm',
|
|
74
|
-
field: clause.field
|
|
75
|
-
}, shown) : null;
|
|
76
|
-
return {
|
|
77
|
-
items: item ? [
|
|
78
|
-
item
|
|
79
|
-
] : [],
|
|
80
|
-
quickFilterValues: searchWords
|
|
81
|
-
};
|
|
82
|
-
}, [
|
|
83
|
-
shownField,
|
|
84
|
-
clauses,
|
|
85
|
-
codecFor,
|
|
86
|
-
pending,
|
|
87
|
-
searchWords
|
|
88
|
-
]);
|
|
89
|
-
const onFilterModelChange = useCallback((model)=>{
|
|
90
|
-
var _model_quickFilterValues;
|
|
91
|
-
const words = ((_model_quickFilterValues = model.quickFilterValues) != null ? _model_quickFilterValues : []).map((word)=>String(word));
|
|
92
|
-
if (words.join(' ') !== searchWords.join(' ')) setSearchWords(words);
|
|
93
|
-
const item = model.items[0];
|
|
94
|
-
// The row deleted: the field it showed is no longer filtered.
|
|
95
|
-
if (!item) {
|
|
96
|
-
if (shownField && clauses.some((clause)=>clause.field === shownField)) {
|
|
97
|
-
onChange(crmUpsertClause(clauses, shownField, null));
|
|
98
|
-
}
|
|
99
|
-
setPending(null);
|
|
100
|
-
setFocus(null);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
const field = String(item.field);
|
|
104
|
-
const moved = field !== shownField;
|
|
105
|
-
setFocus(field);
|
|
106
|
-
const clause = codecFor(field).toClause(item);
|
|
107
|
-
if (!clause) {
|
|
108
|
-
// No value yet. A value cleared on the field already shown removes
|
|
109
|
-
// its clause; a column just chosen leaves the last one standing.
|
|
110
|
-
setPending(_extends({}, item, {
|
|
111
|
-
id: 'crm'
|
|
112
|
-
}));
|
|
113
|
-
if (!moved && clauses.some((entry)=>entry.field === field)) {
|
|
114
|
-
onChange(crmUpsertClause(clauses, field, null));
|
|
115
|
-
}
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
setPending(null);
|
|
119
|
-
// A clause that stands alongside the served one is added beside it;
|
|
120
|
-
// any other replaces whatever the query was serving.
|
|
121
|
-
const base = single && !(keepAlongside == null ? void 0 : keepAlongside(clause)) ? clauses.filter((entry)=>entry.field === field || (keepAlongside == null ? void 0 : keepAlongside(entry))) : clauses;
|
|
122
|
-
const next = crmUpsertClause(base, field, clause);
|
|
123
|
-
const same = next.length === clauses.length && next.every((entry, at)=>entry.field === clauses[at].field && entry.op === clauses[at].op && entry.value === clauses[at].value);
|
|
124
|
-
if (!same) onChange(next);
|
|
125
|
-
}, [
|
|
126
|
-
searchWords,
|
|
127
|
-
setSearchWords,
|
|
128
|
-
shownField,
|
|
129
|
-
clauses,
|
|
130
|
-
onChange,
|
|
131
|
-
codecFor,
|
|
132
|
-
single,
|
|
133
|
-
keepAlongside
|
|
134
|
-
]);
|
|
135
|
-
return {
|
|
136
|
-
filterModel,
|
|
137
|
-
onFilterModelChange,
|
|
138
|
-
searchWords
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
export default useCrmGridFilter;
|
|
142
|
-
|
|
143
|
-
//# sourceMappingURL=use-crm-grid-filter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-crm-grid-filter.ts"],"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\n'use client'\n\nimport type { CrmViewFilterClause } from '@aglyn/aglyn'\nimport type { GridFilterItem, GridFilterModel } from '@mui/x-data-grid'\nimport { useCallback, useMemo, useState } from 'react'\nimport {\n type CrmGridFilterCodec,\n crmPlainCodec,\n crmSelectCodec,\n crmUpsertClause,\n} from '../model/crm-grid-filter'\n\nexport interface CrmGridFilterOptions {\n /** The clauses the list is narrowed by — the saved view's working filters. */\n clauses: readonly CrmViewFilterClause[]\n onChange: (clauses: CrmViewFilterClause[]) => void\n /** Fields whose values are picked, which the panel shows as a select. */\n selectFields?: readonly string[]\n /** A field whose stored clauses predate the panel, translated its own way. */\n codecs?: Readonly<Record<string, CrmGridFilterCodec>>\n /**\n * The query serves ONE clause, so the panel's replaces every other — a\n * server-paged list, which has no loaded window to narrow further.\n * `keepAlongside` names the clauses that do narrow the loaded page and so\n * may stand beside it (\"No next activity\").\n */\n single?: boolean\n keepAlongside?: (clause: CrmViewFilterClause) => boolean\n /**\n * The quick search's words, held by the list when it needs them before\n * the grid's columns exist; the hook holds them itself otherwise.\n */\n search?: { words: string[]; onChange: (words: string[]) => void }\n}\n\n/** What the grid is handed, and what the list filters its rows by. */\nexport interface CrmGridFilter {\n /** Controlled: the panel's one item, and the quick search's words. */\n filterModel: GridFilterModel\n onFilterModelChange: (model: GridFilterModel) => void\n /** The quick search's words, for the list to match its rows against. */\n searchWords: string[]\n}\n\n/**\n * The grid's Filters panel and quick search, bound to a list's view clauses\n * (AGL-3313). See `model/crm-grid-filter.ts` for the shape both sides keep.\n *\n * ## One field, one clause; the panel edits one at a time\n *\n * The free DataGrid's panel holds a single item, while a saved view\n * holds several clauses. So each FIELD holds one clause, and the panel is a\n * window onto whichever field was last filtered: setting a value writes\n * that field's clause, clearing it or deleting the row removes it, and\n * choosing another column in the panel moves the window without touching\n * the clause the reader just set. Filtering Lead source and then Status is\n * therefore both, which is what a reader who does it means; the chips over\n * the grid (`CrmFilterBar`) show every clause and remove any of them.\n *\n * ## The list answers, never the grid\n *\n * Every list passes `filterMode=\"server\"`: the grid holds one page, or a\n * window the query already narrowed, so a filter the grid ran itself would\n * answer \"no match\" for a row on the next page. The list reads the clauses\n * — onto its query where it can, over its loaded rows where it cannot —\n * and the quick search's words, and hands the grid the rows that answer.\n */\nexport function useCrmGridFilter(options: CrmGridFilterOptions): CrmGridFilter {\n const { clauses, onChange, selectFields = [], codecs = {}, single = false, keepAlongside } =\n options\n\n const codecFor = useCallback(\n (field: string): CrmGridFilterCodec =>\n codecs[field] ?? (selectFields.includes(field) ? crmSelectCodec : crmPlainCodec),\n [codecs, selectFields],\n )\n\n /** The field the panel shows, once the reader has pointed it anywhere. */\n const [focus, setFocus] = useState<string | null>(null)\n /** The panel's row while it holds no value yet — a column chosen, a value not. */\n const [pending, setPending] = useState<GridFilterItem | null>(null)\n const [ownWords, setOwnWords] = useState<string[]>([])\n const searchWords = options.search?.words ?? ownWords\n const setSearchWords = options.search?.onChange ?? setOwnWords\n\n /** Whatever the panel last pointed at, else the newest clause it can show. */\n const shownField = useMemo(() => {\n if (focus) return focus\n for (let at = clauses.length - 1; at >= 0; at -= 1) {\n if (codecFor(clauses[at].field).toItem(clauses[at])) return clauses[at].field\n }\n return null\n }, [focus, clauses, codecFor])\n\n const filterModel = useMemo<GridFilterModel>(() => {\n const clause = shownField\n ? clauses.find((entry) => entry.field === shownField)\n : undefined\n const shown = clause ? codecFor(clause.field).toItem(clause) : null\n const item: GridFilterItem | null =\n pending && pending.field === shownField\n ? pending\n : clause && shown\n ? { id: 'crm', field: clause.field, ...shown }\n : null\n return { items: item ? [item] : [], quickFilterValues: searchWords }\n }, [shownField, clauses, codecFor, pending, searchWords])\n\n const onFilterModelChange = useCallback(\n (model: GridFilterModel) => {\n const words = (model.quickFilterValues ?? []).map((word) => String(word))\n if (words.join(' ') !== searchWords.join(' ')) setSearchWords(words)\n\n const item = model.items[0]\n // The row deleted: the field it showed is no longer filtered.\n if (!item) {\n if (shownField && clauses.some((clause) => clause.field === shownField)) {\n onChange(crmUpsertClause(clauses, shownField, null))\n }\n setPending(null)\n setFocus(null)\n return\n }\n const field = String(item.field)\n const moved = field !== shownField\n setFocus(field)\n const clause = codecFor(field).toClause(item)\n if (!clause) {\n // No value yet. A value cleared on the field already shown removes\n // its clause; a column just chosen leaves the last one standing.\n setPending({ ...item, id: 'crm' })\n if (!moved && clauses.some((entry) => entry.field === field)) {\n onChange(crmUpsertClause(clauses, field, null))\n }\n return\n }\n setPending(null)\n // A clause that stands alongside the served one is added beside it;\n // any other replaces whatever the query was serving.\n const base =\n single && !keepAlongside?.(clause)\n ? clauses.filter((entry) => entry.field === field || keepAlongside?.(entry))\n : clauses\n const next = crmUpsertClause(base, field, clause)\n const same =\n next.length === clauses.length &&\n next.every(\n (entry, at) =>\n entry.field === clauses[at].field &&\n entry.op === clauses[at].op &&\n entry.value === clauses[at].value,\n )\n if (!same) onChange(next)\n },\n [searchWords, setSearchWords, shownField, clauses, onChange, codecFor, single, keepAlongside],\n )\n\n return { filterModel, onFilterModelChange, searchWords }\n}\n\nexport default useCrmGridFilter\n"],"names":["useCallback","useMemo","useState","crmPlainCodec","crmSelectCodec","crmUpsertClause","useCrmGridFilter","options","clauses","onChange","selectFields","codecs","single","keepAlongside","codecFor","field","includes","focus","setFocus","pending","setPending","ownWords","setOwnWords","searchWords","search","words","setSearchWords","shownField","at","length","toItem","filterModel","clause","find","entry","undefined","shown","item","id","items","quickFilterValues","onFilterModelChange","model","map","word","String","join","some","moved","toClause","base","filter","next","same","every","op","value"],"mappings":"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"}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2026 Aglyn LLC
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/
|
|
17
|
-
import type { CrmViewFilterClause } from '@aglyn/aglyn';
|
|
18
|
-
import { type ListFilterField } from '@aglyn/shared-ui-jsx/const/list-filter';
|
|
19
|
-
import { type GridColDef, type GridFilterItem } from '@mui/x-data-grid';
|
|
20
|
-
/** A choice for a field whose value is picked rather than typed. */
|
|
21
|
-
export interface CrmFilterOption {
|
|
22
|
-
value: string;
|
|
23
|
-
label: string;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* How one field's stored clause and the panel's item translate. A field
|
|
27
|
-
* with choices uses {@link crmSelectCodec}; a typed one, {@link crmPlainCodec}.
|
|
28
|
-
* A list whose clauses predate the panel supplies its own.
|
|
29
|
-
*/
|
|
30
|
-
export interface CrmGridFilterCodec {
|
|
31
|
-
toItem: (clause: CrmViewFilterClause) => Pick<GridFilterItem, 'operator' | 'value'> | null;
|
|
32
|
-
toClause: (item: GridFilterItem) => CrmViewFilterClause | null;
|
|
33
|
-
}
|
|
34
|
-
/** A typed field: the stored operator IS the grid's. */
|
|
35
|
-
export declare const crmPlainCodec: CrmGridFilterCodec;
|
|
36
|
-
/** A picked field: `equals` shows as `is`, and `isAnyOf` holds a comma list. */
|
|
37
|
-
export declare const crmSelectCodec: CrmGridFilterCodec;
|
|
38
|
-
/** The select operators a field's allowed clause operators map to. */
|
|
39
|
-
export declare function crmSelectOperators(allowed: readonly string[]): import("@mui/x-data-grid").GridFilterOperator<any, any, any, import("@mui/x-data-grid").GridFilterInputValueProps>[];
|
|
40
|
-
/**
|
|
41
|
-
* The list's columns, each made filterable exactly as far as its field is
|
|
42
|
-
* declared, and every declared field that is not a column added as a
|
|
43
|
-
* permanently hidden one — the panel lists columns, so a field with none
|
|
44
|
-
* could not be reached (`hiddenFilterColumns`).
|
|
45
|
-
*
|
|
46
|
-
* A field with choices becomes a `singleSelect` over them, whatever the
|
|
47
|
-
* column rendered before; one without keeps the grammar's operators; a
|
|
48
|
-
* column no field declares offers no filter, because the list, not the
|
|
49
|
-
* grid, answers every filter and would have nothing to answer it with.
|
|
50
|
-
*/
|
|
51
|
-
export declare function crmFilterColumns(columns: readonly GridColDef[], fields: readonly ListFilterField[], options?: Readonly<Record<string, readonly CrmFilterOption[]>>, headers?: Readonly<Record<string, string>>): GridColDef[];
|
|
52
|
-
/**
|
|
53
|
-
* Whether a row answers a quick search: every whitespace-separated word
|
|
54
|
-
* appears, case-insensitively, in SOME of the row's searched values. A
|
|
55
|
-
* blank search matches every row, so an emptied box is the list unfiltered.
|
|
56
|
-
* An array value (tags) is searched member by member.
|
|
57
|
-
*/
|
|
58
|
-
export declare function crmRowMatchesSearch(row: object, paths: readonly string[], words: readonly string[]): boolean;
|
|
59
|
-
/**
|
|
60
|
-
* The clauses with one field's clause set: replaced in place where the field
|
|
61
|
-
* already had one, appended where it did not, removed when `next` is null.
|
|
62
|
-
* A field holds ONE clause, which is what the panel edits.
|
|
63
|
-
*/
|
|
64
|
-
export declare function crmUpsertClause(clauses: readonly CrmViewFilterClause[], field: string, next: CrmViewFilterClause | null): CrmViewFilterClause[];
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2026 Aglyn LLC
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
17
|
-
import { gridFilterRequests, hiddenFilterColumns, listFilterColumn, listFilterOperators } from "@aglyn/shared-ui-jsx/const/list-filter";
|
|
18
|
-
import { getGridSingleSelectOperators } from "@mui/x-data-grid";
|
|
19
|
-
/** The grid operator each stored select operator shows as. */ const SELECT_TO_GRID = {
|
|
20
|
-
equals: 'is',
|
|
21
|
-
doesNotEqual: 'not',
|
|
22
|
-
isAnyOf: 'isAnyOf'
|
|
23
|
-
};
|
|
24
|
-
const SELECT_FROM_GRID = {
|
|
25
|
-
is: 'equals',
|
|
26
|
-
not: 'doesNotEqual',
|
|
27
|
-
isAnyOf: 'isAnyOf'
|
|
28
|
-
};
|
|
29
|
-
/** The panel's item as a clause, through the grammar's one notion of "usable". */ const plainClause = (item)=>{
|
|
30
|
-
var _gridFilterRequests_;
|
|
31
|
-
return (_gridFilterRequests_ = gridFilterRequests({
|
|
32
|
-
items: [
|
|
33
|
-
item
|
|
34
|
-
]
|
|
35
|
-
})[0]) != null ? _gridFilterRequests_ : null;
|
|
36
|
-
};
|
|
37
|
-
/** A typed field: the stored operator IS the grid's. */ export const crmPlainCodec = {
|
|
38
|
-
toItem: (clause)=>({
|
|
39
|
-
operator: clause.op,
|
|
40
|
-
value: clause.value === '' ? undefined : clause.value
|
|
41
|
-
}),
|
|
42
|
-
toClause: plainClause
|
|
43
|
-
};
|
|
44
|
-
/** A picked field: `equals` shows as `is`, and `isAnyOf` holds a comma list. */ export const crmSelectCodec = {
|
|
45
|
-
toItem: (clause)=>{
|
|
46
|
-
const operator = SELECT_TO_GRID[clause.op];
|
|
47
|
-
if (!operator) return null;
|
|
48
|
-
return {
|
|
49
|
-
operator,
|
|
50
|
-
value: operator === 'isAnyOf' ? clause.value.split(',').map((entry)=>entry.trim()).filter(Boolean) : clause.value
|
|
51
|
-
};
|
|
52
|
-
},
|
|
53
|
-
toClause: (item)=>{
|
|
54
|
-
const op = SELECT_FROM_GRID[String(item.operator)];
|
|
55
|
-
const request = op ? plainClause(item) : null;
|
|
56
|
-
return request && op ? _extends({}, request, {
|
|
57
|
-
op
|
|
58
|
-
}) : null;
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
/** The select operators a field's allowed clause operators map to. */ export function crmSelectOperators(allowed) {
|
|
62
|
-
const shown = allowed.map((op)=>SELECT_TO_GRID[op]).filter(Boolean);
|
|
63
|
-
return getGridSingleSelectOperators().filter((operator)=>shown.includes(operator.value));
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* The list's columns, each made filterable exactly as far as its field is
|
|
67
|
-
* declared, and every declared field that is not a column added as a
|
|
68
|
-
* permanently hidden one — the panel lists columns, so a field with none
|
|
69
|
-
* could not be reached (`hiddenFilterColumns`).
|
|
70
|
-
*
|
|
71
|
-
* A field with choices becomes a `singleSelect` over them, whatever the
|
|
72
|
-
* column rendered before; one without keeps the grammar's operators; a
|
|
73
|
-
* column no field declares offers no filter, because the list, not the
|
|
74
|
-
* grid, answers every filter and would have nothing to answer it with.
|
|
75
|
-
*/ export function crmFilterColumns(columns, fields, options = {}, headers = {}) {
|
|
76
|
-
const selectProps = (field)=>{
|
|
77
|
-
var _options_field_column;
|
|
78
|
-
const choices = (_options_field_column = options[field.column]) != null ? _options_field_column : [];
|
|
79
|
-
const operators = crmSelectOperators(listFilterOperators(field));
|
|
80
|
-
return {
|
|
81
|
-
type: 'singleSelect',
|
|
82
|
-
valueOptions: choices.map((choice)=>({
|
|
83
|
-
value: choice.value,
|
|
84
|
-
label: choice.label
|
|
85
|
-
})),
|
|
86
|
-
filterable: choices.length > 0 && operators.length > 0,
|
|
87
|
-
filterOperators: operators
|
|
88
|
-
};
|
|
89
|
-
};
|
|
90
|
-
const shown = columns.map((column)=>{
|
|
91
|
-
if (column.filterable === false && column.hideable === false) return column;
|
|
92
|
-
const field = fields.find((entry)=>entry.column === column.field);
|
|
93
|
-
if (!field) return _extends({}, column, {
|
|
94
|
-
filterable: false
|
|
95
|
-
});
|
|
96
|
-
if (options[field.column]) return _extends({}, column, selectProps(field));
|
|
97
|
-
return _extends({}, column, listFilterColumn(fields, field.column));
|
|
98
|
-
});
|
|
99
|
-
const present = columns.map((column)=>column.field);
|
|
100
|
-
const hidden = hiddenFilterColumns(fields, present, headers).map((column)=>{
|
|
101
|
-
const field = fields.find((entry)=>entry.column === column.field);
|
|
102
|
-
return field && options[field.column] ? _extends({}, column, selectProps(field)) : column;
|
|
103
|
-
});
|
|
104
|
-
return [
|
|
105
|
-
...shown,
|
|
106
|
-
...hidden
|
|
107
|
-
];
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Whether a row answers a quick search: every whitespace-separated word
|
|
111
|
-
* appears, case-insensitively, in SOME of the row's searched values. A
|
|
112
|
-
* blank search matches every row, so an emptied box is the list unfiltered.
|
|
113
|
-
* An array value (tags) is searched member by member.
|
|
114
|
-
*/ export function crmRowMatchesSearch(row, paths, words) {
|
|
115
|
-
const asked = words.map((word)=>word.trim().toLowerCase()).filter(Boolean);
|
|
116
|
-
if (!asked.length) return true;
|
|
117
|
-
const values = paths.flatMap((path)=>{
|
|
118
|
-
const value = path.split('.').reduce((at, key)=>at == null ? undefined : at[key], row);
|
|
119
|
-
return Array.isArray(value) ? value : [
|
|
120
|
-
value
|
|
121
|
-
];
|
|
122
|
-
}).filter((value)=>typeof value === 'string' || typeof value === 'number').map((value)=>String(value).toLowerCase()).filter(Boolean);
|
|
123
|
-
return asked.every((word)=>values.some((value)=>value.includes(word)));
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* The clauses with one field's clause set: replaced in place where the field
|
|
127
|
-
* already had one, appended where it did not, removed when `next` is null.
|
|
128
|
-
* A field holds ONE clause, which is what the panel edits.
|
|
129
|
-
*/ export function crmUpsertClause(clauses, field, next) {
|
|
130
|
-
const at = clauses.findIndex((clause)=>clause.field === field);
|
|
131
|
-
const rest = clauses.filter((clause)=>clause.field !== field);
|
|
132
|
-
if (!next) return rest;
|
|
133
|
-
if (at === -1) return [
|
|
134
|
-
...rest,
|
|
135
|
-
next
|
|
136
|
-
];
|
|
137
|
-
return [
|
|
138
|
-
...rest.slice(0, at),
|
|
139
|
-
next,
|
|
140
|
-
...rest.slice(at)
|
|
141
|
-
];
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
//# sourceMappingURL=crm-grid-filter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/model/crm-grid-filter.ts"],"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\nimport type { CrmViewFilterClause } from '@aglyn/aglyn'\nimport {\n gridFilterRequests,\n hiddenFilterColumns,\n type ListFilterField,\n listFilterColumn,\n listFilterOperators,\n} from '@aglyn/shared-ui-jsx/const/list-filter'\nimport {\n getGridSingleSelectOperators,\n type GridColDef,\n type GridFilterItem,\n} from '@mui/x-data-grid'\n\n/*\n * ONE path from a CRM list's saved-view clauses to the data grid's own\n * Filters panel and quick search, and back (AGL-3313).\n *\n * Every CRM list stores what it is narrowed by as view clauses —\n * `{ field, op, value }`, the shape saved views have held since AGL-2617 —\n * and every one of them now edits those clauses through the grid's toolbar\n * rather than a control of its own. What a list declares is its fields,\n * as the `ListFilterField` grammar the console's other paged lists speak\n * (the content entries, the staff lists), plus the choices of the fields\n * whose values are picked rather than typed. The grid then offers each as a\n * typed column: a `singleSelect` with its choices where there are choices,\n * the operators the grammar allows otherwise.\n *\n * The clauses keep their stored shape, so a view saved with the old\n * dropdowns reads unchanged: the panel shows `equals` as the select's `is`\n * and writes `is` back as `equals`, and a list whose clauses were stored in\n * some other shape (Leads' campaign `contains`, its lead source `isEmpty`)\n * says so with a codec.\n */\n\n/** A choice for a field whose value is picked rather than typed. */\nexport interface CrmFilterOption {\n value: string\n label: string\n}\n\n/** The grid operator each stored select operator shows as. */\nconst SELECT_TO_GRID: Readonly<Record<string, string>> = {\n equals: 'is',\n doesNotEqual: 'not',\n isAnyOf: 'isAnyOf',\n}\nconst SELECT_FROM_GRID: Readonly<Record<string, string>> = {\n is: 'equals',\n not: 'doesNotEqual',\n isAnyOf: 'isAnyOf',\n}\n\n/**\n * How one field's stored clause and the panel's item translate. A field\n * with choices uses {@link crmSelectCodec}; a typed one, {@link crmPlainCodec}.\n * A list whose clauses predate the panel supplies its own.\n */\nexport interface CrmGridFilterCodec {\n toItem: (clause: CrmViewFilterClause) => Pick<GridFilterItem, 'operator' | 'value'> | null\n toClause: (item: GridFilterItem) => CrmViewFilterClause | null\n}\n\n/** The panel's item as a clause, through the grammar's one notion of \"usable\". */\nconst plainClause = (item: GridFilterItem): CrmViewFilterClause | null =>\n gridFilterRequests({ items: [item] })[0] ?? null\n\n/** A typed field: the stored operator IS the grid's. */\nexport const crmPlainCodec: CrmGridFilterCodec = {\n toItem: (clause) => ({\n operator: clause.op,\n value: clause.value === '' ? undefined : clause.value,\n }),\n toClause: plainClause,\n}\n\n/** A picked field: `equals` shows as `is`, and `isAnyOf` holds a comma list. */\nexport const crmSelectCodec: CrmGridFilterCodec = {\n toItem: (clause) => {\n const operator = SELECT_TO_GRID[clause.op]\n if (!operator) return null\n return {\n operator,\n value:\n operator === 'isAnyOf'\n ? clause.value.split(',').map((entry) => entry.trim()).filter(Boolean)\n : clause.value,\n }\n },\n toClause: (item) => {\n const op = SELECT_FROM_GRID[String(item.operator)]\n const request = op ? plainClause(item) : null\n return request && op ? { ...request, op } : null\n },\n}\n\n/** The select operators a field's allowed clause operators map to. */\nexport function crmSelectOperators(allowed: readonly string[]) {\n const shown = allowed.map((op) => SELECT_TO_GRID[op]).filter(Boolean)\n return getGridSingleSelectOperators().filter((operator) =>\n shown.includes(operator.value),\n )\n}\n\n/**\n * The list's columns, each made filterable exactly as far as its field is\n * declared, and every declared field that is not a column added as a\n * permanently hidden one — the panel lists columns, so a field with none\n * could not be reached (`hiddenFilterColumns`).\n *\n * A field with choices becomes a `singleSelect` over them, whatever the\n * column rendered before; one without keeps the grammar's operators; a\n * column no field declares offers no filter, because the list, not the\n * grid, answers every filter and would have nothing to answer it with.\n */\nexport function crmFilterColumns(\n columns: readonly GridColDef[],\n fields: readonly ListFilterField[],\n options: Readonly<Record<string, readonly CrmFilterOption[]>> = {},\n headers: Readonly<Record<string, string>> = {},\n): GridColDef[] {\n const selectProps = (field: ListFilterField) => {\n const choices = options[field.column] ?? []\n const operators = crmSelectOperators(listFilterOperators(field))\n return {\n type: 'singleSelect' as const,\n valueOptions: choices.map((choice) => ({ value: choice.value, label: choice.label })),\n filterable: choices.length > 0 && operators.length > 0,\n filterOperators: operators,\n }\n }\n const shown = columns.map((column): GridColDef => {\n if (column.filterable === false && column.hideable === false) return column\n const field = fields.find((entry) => entry.column === column.field)\n if (!field) return { ...column, filterable: false }\n if (options[field.column]) return { ...column, ...selectProps(field) } as GridColDef\n return { ...column, ...listFilterColumn(fields, field.column) }\n })\n const present = columns.map((column) => column.field)\n const hidden = hiddenFilterColumns(fields, present, headers).map(\n (column): GridColDef => {\n const field = fields.find((entry) => entry.column === column.field)\n return field && options[field.column]\n ? ({ ...column, ...selectProps(field) } as GridColDef)\n : column\n },\n )\n return [...shown, ...hidden]\n}\n\n/**\n * Whether a row answers a quick search: every whitespace-separated word\n * appears, case-insensitively, in SOME of the row's searched values. A\n * blank search matches every row, so an emptied box is the list unfiltered.\n * An array value (tags) is searched member by member.\n */\nexport function crmRowMatchesSearch(\n row: object,\n paths: readonly string[],\n words: readonly string[],\n): boolean {\n const asked = words.map((word) => word.trim().toLowerCase()).filter(Boolean)\n if (!asked.length) return true\n const values = paths\n .flatMap((path) => {\n const value = path\n .split('.')\n .reduce<unknown>(\n (at, key) => (at == null ? undefined : (at as Record<string, unknown>)[key]),\n row,\n )\n return Array.isArray(value) ? value : [value]\n })\n .filter((value): value is string | number => typeof value === 'string' || typeof value === 'number')\n .map((value) => String(value).toLowerCase())\n .filter(Boolean)\n return asked.every((word) => values.some((value) => value.includes(word)))\n}\n\n/**\n * The clauses with one field's clause set: replaced in place where the field\n * already had one, appended where it did not, removed when `next` is null.\n * A field holds ONE clause, which is what the panel edits.\n */\nexport function crmUpsertClause(\n clauses: readonly CrmViewFilterClause[],\n field: string,\n next: CrmViewFilterClause | null,\n): CrmViewFilterClause[] {\n const at = clauses.findIndex((clause) => clause.field === field)\n const rest = clauses.filter((clause) => clause.field !== field)\n if (!next) return rest\n if (at === -1) return [...rest, next]\n return [...rest.slice(0, at), next, ...rest.slice(at)]\n}\n"],"names":["gridFilterRequests","hiddenFilterColumns","listFilterColumn","listFilterOperators","getGridSingleSelectOperators","SELECT_TO_GRID","equals","doesNotEqual","isAnyOf","SELECT_FROM_GRID","is","not","plainClause","item","items","crmPlainCodec","toItem","clause","operator","op","value","undefined","toClause","crmSelectCodec","split","map","entry","trim","filter","Boolean","String","request","crmSelectOperators","allowed","shown","includes","crmFilterColumns","columns","fields","options","headers","selectProps","field","choices","column","operators","type","valueOptions","choice","label","filterable","length","filterOperators","hideable","find","present","hidden","crmRowMatchesSearch","row","paths","words","asked","word","toLowerCase","values","flatMap","path","reduce","at","key","Array","isArray","every","some","crmUpsertClause","clauses","next","findIndex","rest","slice"],"mappings":"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"}
|