@servicetitan/dte-pdf-editor 1.48.0 → 1.50.0
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/dist/components/field-config-panel/field-sidebar.d.ts.map +1 -1
- package/dist/components/field-config-panel/field-sidebar.js +42 -6
- package/dist/components/field-config-panel/field-sidebar.js.map +1 -1
- package/dist/components/field-config-panel/formula-modal.d.ts.map +1 -1
- package/dist/components/field-config-panel/formula-modal.js +55 -2
- package/dist/components/field-config-panel/formula-modal.js.map +1 -1
- package/dist/components/field-config-panel/formula-workspace.d.ts +1 -0
- package/dist/components/field-config-panel/formula-workspace.d.ts.map +1 -1
- package/dist/components/field-config-panel/formula-workspace.js +3 -3
- package/dist/components/field-config-panel/formula-workspace.js.map +1 -1
- package/dist/components/field-sidebar/data-model-field-type-list.d.ts.map +1 -1
- package/dist/components/field-sidebar/data-model-field-type-list.js +2 -1
- package/dist/components/field-sidebar/data-model-field-type-list.js.map +1 -1
- package/dist/components/field-sidebar/field-type.d.ts +1 -0
- package/dist/components/field-sidebar/field-type.d.ts.map +1 -1
- package/dist/components/field-sidebar/field-type.js +3 -3
- package/dist/components/field-sidebar/field-type.js.map +1 -1
- package/dist/components/field-sidebar/form-fields-type-list.d.ts.map +1 -1
- package/dist/components/field-sidebar/form-fields-type-list.js +2 -1
- package/dist/components/field-sidebar/form-fields-type-list.js.map +1 -1
- package/dist/components/pdf-view/pdf-view-data-model.d.ts.map +1 -1
- package/dist/components/pdf-view/pdf-view-data-model.js +8 -2
- package/dist/components/pdf-view/pdf-view-data-model.js.map +1 -1
- package/dist/interface/types.d.ts +1 -0
- package/dist/interface/types.d.ts.map +1 -1
- package/dist/interface/types.js.map +1 -1
- package/dist/utils/data-model/extract-fields.utils.d.ts.map +1 -1
- package/dist/utils/data-model/extract-fields.utils.js +4 -2
- package/dist/utils/data-model/extract-fields.utils.js.map +1 -1
- package/dist/utils/shared/index.d.ts +2 -0
- package/dist/utils/shared/index.d.ts.map +1 -1
- package/dist/utils/shared/index.js +2 -0
- package/dist/utils/shared/index.js.map +1 -1
- package/dist/utils/shared/sample-data.utils.d.ts +3 -0
- package/dist/utils/shared/sample-data.utils.d.ts.map +1 -0
- package/dist/utils/shared/sample-data.utils.js +20 -0
- package/dist/utils/shared/sample-data.utils.js.map +1 -0
- package/dist/utils/shared/schema.utils.d.ts +7 -0
- package/dist/utils/shared/schema.utils.d.ts.map +1 -0
- package/dist/utils/shared/schema.utils.js +9 -0
- package/dist/utils/shared/schema.utils.js.map +1 -0
- package/package.json +1 -1
- package/src/components/field-config-panel/field-sidebar.tsx +71 -7
- package/src/components/field-config-panel/formula-modal.tsx +61 -0
- package/src/components/field-config-panel/formula-workspace.tsx +8 -0
- package/src/components/field-sidebar/data-model-field-type-list.tsx +6 -1
- package/src/components/field-sidebar/field-type.tsx +16 -3
- package/src/components/field-sidebar/form-fields-type-list.tsx +5 -0
- package/src/components/pdf-view/pdf-view-data-model.tsx +13 -2
- package/src/interface/types.ts +1 -0
- package/src/styles/formula-modal.css +10 -0
- package/src/utils/data-model/extract-fields.utils.ts +2 -0
- package/src/utils/shared/index.ts +2 -0
- package/src/utils/shared/sample-data.utils.ts +29 -0
- package/src/utils/shared/schema.utils.ts +8 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-fields.utils.js","sourceRoot":"","sources":["../../../src/utils/data-model/extract-fields.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,aAAa,GAOhB,MAAM,uBAAuB,CAAC;AAE/B,SAAS,oBAAoB,CAAC,IAAgB;IAC1C,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC;AAClC,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAgB;IACxC,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;AAChC,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAgB;IACxC,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,OAAO,QAAQ,CAAC;IACpB,CAAC;IACD,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,MAAM,CAAC;IAClB,CAAC;IACD,OAAO,SAAS,CAAC;AACrB,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAgB;;IAC3C,OAAO,CAAA,MAAA,IAAI,CAAC,OAAO,0CAAE,qBAAqB,MAAK,IAAI,CAAC;AACxD,CAAC;AAQD;;;GAGG;AACH,MAAM,kBAAkB,GAAG,QAAQ,CAAC;AAEpC,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAC7C,SAAuB,EACvB,OAAqC,EAChB,EAAE;IACvB,MAAM,yBAAyB,GAAG,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,yBAAyB,MAAK,IAAI,CAAC;IAC9E,MAAM,MAAM,GAA0B,EAAE,CAAC;IACzC,MAAM,cAAc,GAAsB,EAAE,CAAC;IAE7C,IAAI,CAAC,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU,CAAA,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;;QAC5C,MAAM,QAAQ,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAE3C,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;YACpD,MAAM,MAAM,GAAsB,EAAE,CAAC;YACrC,sBAAsB,CAClB,QAAQ,CAAC,UAAU,EACnB,GAAG,EACH,MAAM,EACN,GAAG,EACH,yBAAyB,CAC5B,CAAC;YAEF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpB,MAAM,CAAC,IAAI,CAAC;oBACR,SAAS,EAAE,MAAA,QAAQ,CAAC,KAAK,mCAAI,GAAG;oBAChC,MAAM;iBACT,CAAC,CAAC;YACP,CAAC;QACL,CAAC;aAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YACrD,yDAAyD;QAC7D,CAAC;aAAM,CAAC;YACJ,+EAA+E;YAC/E,MAAM,OAAO,GAAI,QAA8B,CAAC,IAAI,CAAC;YACrD,MAAM,MAAM,GACR,QAAQ,CAAC,IAAI,KAAK,QAAQ;gBAC1B,oBAAoB,CAAC,QAAQ,CAAC;gBAC9B,kBAAkB,CAAC,QAAQ,CAAC;gBAC5B,OAAO,KAAK,SAAS,CAAC;YAC1B,MAAM,YAAY,GAAG,CAAC,yBAAyB,IAAI,qBAAqB,CAAC,QAAQ,CAAC,CAAC;YACnF,IAAI,MAAM,IAAI,YAAY,EAAE,CAAC;gBACzB,cAAc,CAAC,IAAI,CAAC;oBAChB,KAAK,EAAE,MAAA,QAAQ,CAAC,KAAK,mCAAI,GAAG;oBAC5B,IAAI,EAAE,aAAa,CAAC,SAAS;oBAC7B,IAAI,EAAE,GAAG;oBACT,SAAS,EAAE,kBAAkB,CAAC,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"extract-fields.utils.js","sourceRoot":"","sources":["../../../src/utils/data-model/extract-fields.utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample-data.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/shared/sample-data.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAWxD,eAAO,MAAM,kBAAkB,GAC3B,YAAY,OAAO,EACnB,eAAe,eAAe,KAC/B,MAAM,GAAG,MAAM,GAAG,IAcpB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const DEFAULT_NUMBER_SAMPLE = 350;
|
|
2
|
+
const toPrimitiveSample = (value) => {
|
|
3
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
4
|
+
return value;
|
|
5
|
+
}
|
|
6
|
+
return undefined;
|
|
7
|
+
};
|
|
8
|
+
export const getFieldSampleData = (sampleData, fieldSubType) => {
|
|
9
|
+
const primitiveSample = toPrimitiveSample(sampleData);
|
|
10
|
+
if (fieldSubType === 'date') {
|
|
11
|
+
const candidate = primitiveSample !== undefined ? new Date(primitiveSample) : new Date();
|
|
12
|
+
const source = Number.isNaN(candidate.getTime()) ? new Date() : candidate;
|
|
13
|
+
return source.toISOString().slice(0, 10);
|
|
14
|
+
}
|
|
15
|
+
if (fieldSubType === 'number') {
|
|
16
|
+
return primitiveSample !== null && primitiveSample !== void 0 ? primitiveSample : DEFAULT_NUMBER_SAMPLE;
|
|
17
|
+
}
|
|
18
|
+
return primitiveSample !== null && primitiveSample !== void 0 ? primitiveSample : null;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=sample-data.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample-data.utils.js","sourceRoot":"","sources":["../../../src/utils/shared/sample-data.utils.ts"],"names":[],"mappings":"AAEA,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAElC,MAAM,iBAAiB,GAAG,CAAC,KAAc,EAA+B,EAAE;IACtE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACzD,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,SAAS,CAAC;AACrB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAC9B,UAAmB,EACnB,YAA8B,EACR,EAAE;IACxB,MAAM,eAAe,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAEtD,IAAI,YAAY,KAAK,MAAM,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;QACzF,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1E,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,eAAe,aAAf,eAAe,cAAf,eAAe,GAAI,qBAAqB,CAAC;IACpD,CAAC;IAED,OAAO,eAAe,aAAf,eAAe,cAAf,eAAe,GAAI,IAAI,CAAC;AACnC,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React/HTML equivalent of the Nunjucks `nl2br` filter used by Unlayer's
|
|
3
|
+
* `{{ field | safe | nl2br }}` template. Replaces every `\r\n` or `\n` with `<br />\n`,
|
|
4
|
+
* keeping the original newline so the rendered HTML source still wraps in dev tools.
|
|
5
|
+
*/
|
|
6
|
+
export declare const nl2br: (value: string) => string;
|
|
7
|
+
//# sourceMappingURL=schema.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/shared/schema.utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG,MAErC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React/HTML equivalent of the Nunjucks `nl2br` filter used by Unlayer's
|
|
3
|
+
* `{{ field | safe | nl2br }}` template. Replaces every `\r\n` or `\n` with `<br />\n`,
|
|
4
|
+
* keeping the original newline so the rendered HTML source still wraps in dev tools.
|
|
5
|
+
*/
|
|
6
|
+
export const nl2br = (value) => {
|
|
7
|
+
return value.replace(/\r\n|\n/g, '<br />\n');
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=schema.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.utils.js","sourceRoot":"","sources":["../../../src/utils/shared/schema.utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAa,EAAU,EAAE;IAC3C,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AACjD,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { Button, Flex, Text } from '@servicetitan/anvil2';
|
|
1
|
+
import { Button, Flex, SearchField, Text } from '@servicetitan/anvil2';
|
|
2
2
|
import IconArrowBack from '@servicetitan/anvil2/assets/icons/material/round/keyboard_arrow_left.svg';
|
|
3
3
|
import IconArrowForward from '@servicetitan/anvil2/assets/icons/material/round/keyboard_arrow_right.svg';
|
|
4
4
|
import { FC, Fragment, useMemo, useState } from 'react';
|
|
5
5
|
import { FieldTypeOption, FormFieldsByFormIdI, FormInfo } from '../../interface/types';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
formFieldInfosToCalculationOptions,
|
|
8
|
+
getFieldSampleData,
|
|
9
|
+
parseFormFieldKey,
|
|
10
|
+
} from '../../utils';
|
|
7
11
|
|
|
8
12
|
interface FieldSidebarProps {
|
|
9
13
|
fillableOptions: FieldTypeOption[];
|
|
@@ -31,15 +35,23 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
|
|
|
31
35
|
selectedPaths,
|
|
32
36
|
}) => {
|
|
33
37
|
const [selectedFormId, setSelectedFormId] = useState<number | null>(null);
|
|
38
|
+
const [topSearchValue, setTopSearchValue] = useState('');
|
|
39
|
+
const [formFieldsSearchValue, setFormFieldsSearchValue] = useState('');
|
|
34
40
|
|
|
35
41
|
const onFormClick = (formId: number) => {
|
|
36
42
|
setSelectedFormId(formId);
|
|
43
|
+
setFormFieldsSearchValue('');
|
|
37
44
|
const loaded = formFieldsByFormId[formId];
|
|
38
45
|
if (!loaded?.length) {
|
|
39
46
|
onRequestFormFields(formId);
|
|
40
47
|
}
|
|
41
48
|
};
|
|
42
49
|
|
|
50
|
+
const onBackToList = () => {
|
|
51
|
+
setSelectedFormId(null);
|
|
52
|
+
setFormFieldsSearchValue('');
|
|
53
|
+
};
|
|
54
|
+
|
|
43
55
|
const isFormFieldsLoading = selectedFormId != null && formulaLoadingFormId === selectedFormId;
|
|
44
56
|
|
|
45
57
|
const selectedForm = useMemo(
|
|
@@ -57,6 +69,36 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
|
|
|
57
69
|
);
|
|
58
70
|
}, [selectedFormId, formFieldsByFormId, selectedForm?.name]);
|
|
59
71
|
|
|
72
|
+
const filteredForms = useMemo(() => {
|
|
73
|
+
const query = topSearchValue.trim().toLowerCase();
|
|
74
|
+
if (!query) {
|
|
75
|
+
return forms;
|
|
76
|
+
}
|
|
77
|
+
return forms.filter(form => form.name.toLowerCase().includes(query));
|
|
78
|
+
}, [forms, topSearchValue]);
|
|
79
|
+
|
|
80
|
+
const filteredMergeTagOptions = useMemo(() => {
|
|
81
|
+
const query = topSearchValue.trim().toLowerCase();
|
|
82
|
+
if (!query) {
|
|
83
|
+
return mergeTagOptions;
|
|
84
|
+
}
|
|
85
|
+
return mergeTagOptions.filter(option => {
|
|
86
|
+
const label = (option.label ?? option.path ?? '').toLowerCase();
|
|
87
|
+
return label.includes(query);
|
|
88
|
+
});
|
|
89
|
+
}, [mergeTagOptions, topSearchValue]);
|
|
90
|
+
|
|
91
|
+
const filteredCalcOptions = useMemo(() => {
|
|
92
|
+
const query = formFieldsSearchValue.trim().toLowerCase();
|
|
93
|
+
if (!query) {
|
|
94
|
+
return calcOptions;
|
|
95
|
+
}
|
|
96
|
+
return calcOptions.filter(option => {
|
|
97
|
+
const label = (option.label ?? option.path ?? '').toLowerCase();
|
|
98
|
+
return label.includes(query);
|
|
99
|
+
});
|
|
100
|
+
}, [calcOptions, formFieldsSearchValue]);
|
|
101
|
+
|
|
60
102
|
const formIdsReferencedInFormula = useMemo(() => {
|
|
61
103
|
const ids = new Set<number>();
|
|
62
104
|
for (const path of selectedPaths) {
|
|
@@ -75,7 +117,14 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
|
|
|
75
117
|
className={`dte-formula-sidebar-slide-track${selectedFormId ? ' --detail' : ''}`}
|
|
76
118
|
>
|
|
77
119
|
<div className="dte-formula-sidebar-slide-panel">
|
|
78
|
-
|
|
120
|
+
<SearchField
|
|
121
|
+
placeholder="Search"
|
|
122
|
+
size="small"
|
|
123
|
+
style={{ marginLeft: '4px', marginTop: '18px' }}
|
|
124
|
+
value={topSearchValue}
|
|
125
|
+
onChange={e => setTopSearchValue(e.target.value ?? '')}
|
|
126
|
+
/>
|
|
127
|
+
{filteredForms.length > 0 && (
|
|
79
128
|
<div className="dte-formula-sidebar-forms-heading">
|
|
80
129
|
<Text variant="headline" el="h6" size="small">
|
|
81
130
|
Forms
|
|
@@ -85,7 +134,7 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
|
|
|
85
134
|
role="listbox"
|
|
86
135
|
aria-label="Forms"
|
|
87
136
|
>
|
|
88
|
-
{
|
|
137
|
+
{filteredForms.map(form => (
|
|
89
138
|
<li
|
|
90
139
|
key={form.id}
|
|
91
140
|
role="option"
|
|
@@ -122,7 +171,7 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
|
|
|
122
171
|
/>
|
|
123
172
|
<FieldOptionList
|
|
124
173
|
title="Merge tags"
|
|
125
|
-
options={
|
|
174
|
+
options={filteredMergeTagOptions}
|
|
126
175
|
highlightElementPath={highlightElementPath}
|
|
127
176
|
selectedPaths={selectedPaths}
|
|
128
177
|
onHover={onHover}
|
|
@@ -138,7 +187,7 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
|
|
|
138
187
|
size="small"
|
|
139
188
|
icon={IconArrowBack}
|
|
140
189
|
title={selectedForm?.name ?? 'Form fields'}
|
|
141
|
-
onClick={
|
|
190
|
+
onClick={onBackToList}
|
|
142
191
|
>
|
|
143
192
|
<Text
|
|
144
193
|
size="medium"
|
|
@@ -148,11 +197,18 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
|
|
|
148
197
|
{selectedForm?.name ?? 'Form fields'}
|
|
149
198
|
</Text>
|
|
150
199
|
</Button>
|
|
200
|
+
<SearchField
|
|
201
|
+
style={{ margin: '4px' }}
|
|
202
|
+
placeholder="Search"
|
|
203
|
+
size="small"
|
|
204
|
+
value={formFieldsSearchValue}
|
|
205
|
+
onChange={e => setFormFieldsSearchValue(e.target.value ?? '')}
|
|
206
|
+
/>
|
|
151
207
|
|
|
152
208
|
<FieldOptionList
|
|
153
209
|
title=""
|
|
154
210
|
isLoading={isFormFieldsLoading}
|
|
155
|
-
options={
|
|
211
|
+
options={filteredCalcOptions}
|
|
156
212
|
highlightElementPath={highlightElementPath}
|
|
157
213
|
selectedPaths={selectedPaths}
|
|
158
214
|
onHover={onHover}
|
|
@@ -228,6 +284,14 @@ const FieldOptionList: FC<FieldOptionListProps> = ({
|
|
|
228
284
|
<span className="dte-text-ellipsis" title={opt.label ?? opt.path}>
|
|
229
285
|
{opt.label ?? opt.path}
|
|
230
286
|
</span>
|
|
287
|
+
<Text
|
|
288
|
+
size="small"
|
|
289
|
+
subdued
|
|
290
|
+
style={{ fontSize: '12px', marginTop: '-2px' }}
|
|
291
|
+
className="ellipsis"
|
|
292
|
+
>
|
|
293
|
+
e.g. {getFieldSampleData(opt.sampleData, opt.fieldType)}
|
|
294
|
+
</Text>
|
|
231
295
|
</li>
|
|
232
296
|
))}
|
|
233
297
|
</ul>
|
|
@@ -11,13 +11,17 @@ import { useFormulaEditor } from '../../hooks';
|
|
|
11
11
|
import {
|
|
12
12
|
CalculatedFieldFormat,
|
|
13
13
|
DataModelFieldGroup,
|
|
14
|
+
DataModelValues,
|
|
14
15
|
FieldTypeOption,
|
|
15
16
|
FormFieldsByFormIdI,
|
|
16
17
|
FormInfo,
|
|
17
18
|
StructuredFormula,
|
|
18
19
|
} from '../../interface/types';
|
|
19
20
|
import {
|
|
21
|
+
evaluateFormula,
|
|
22
|
+
formatCalculatedResult,
|
|
20
23
|
formFieldInfosToCalculationOptions,
|
|
24
|
+
getFieldSampleData,
|
|
21
25
|
parseExpression,
|
|
22
26
|
tokenizeExpression,
|
|
23
27
|
tokensToExpression,
|
|
@@ -46,6 +50,20 @@ function getValidPathsSet(groups: DataModelFieldGroup[]): Set<string> {
|
|
|
46
50
|
return set;
|
|
47
51
|
}
|
|
48
52
|
|
|
53
|
+
function setSampleValueAtPath(target: DataModelValues, path: string, value: unknown): void {
|
|
54
|
+
const keys = path.split('.');
|
|
55
|
+
let cursor: DataModelValues = target;
|
|
56
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
57
|
+
const key = keys[i];
|
|
58
|
+
const next = cursor[key];
|
|
59
|
+
if (next === null || typeof next !== 'object') {
|
|
60
|
+
cursor[key] = {};
|
|
61
|
+
}
|
|
62
|
+
cursor = cursor[key];
|
|
63
|
+
}
|
|
64
|
+
cursor[keys[keys.length - 1]] = value;
|
|
65
|
+
}
|
|
66
|
+
|
|
49
67
|
export interface FormulaModalProps {
|
|
50
68
|
initialFormula: StructuredFormula | undefined;
|
|
51
69
|
initialFormat?: CalculatedFieldFormat;
|
|
@@ -197,6 +215,48 @@ export const FormulaModal: FC<FormulaModalProps> = ({
|
|
|
197
215
|
return errors;
|
|
198
216
|
}, [formulaEditor.draftExpression, validPaths]);
|
|
199
217
|
|
|
218
|
+
const optionByPath = useMemo(() => {
|
|
219
|
+
const map = new Map<string, FieldTypeOption>();
|
|
220
|
+
for (const opt of allFields) {
|
|
221
|
+
if (opt.path) {
|
|
222
|
+
map.set(opt.path, opt);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
for (const opt of fillableFieldsFromDocument) {
|
|
226
|
+
if (opt.path) {
|
|
227
|
+
map.set(opt.path, opt);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
for (const opt of formCalculationOptions) {
|
|
231
|
+
if (opt.path) {
|
|
232
|
+
map.set(opt.path, opt);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return map;
|
|
236
|
+
}, [allFields, fillableFieldsFromDocument, formCalculationOptions]);
|
|
237
|
+
|
|
238
|
+
const previewValue = useMemo(() => {
|
|
239
|
+
if (parsedTokens.length === 0 || !formulaValidation.valid) {
|
|
240
|
+
return '';
|
|
241
|
+
}
|
|
242
|
+
const sampleData: DataModelValues = {};
|
|
243
|
+
for (const token of parsedTokens) {
|
|
244
|
+
if (token.type !== 'field') {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
const option = optionByPath.get(token.path);
|
|
248
|
+
const sample = getFieldSampleData(option?.sampleData, token.fieldType);
|
|
249
|
+
if (sample !== null) {
|
|
250
|
+
setSampleValueAtPath(sampleData, token.path, sample);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
const computed = evaluateFormula({ tokens: parsedTokens }, sampleData);
|
|
254
|
+
if (computed === null) {
|
|
255
|
+
return '';
|
|
256
|
+
}
|
|
257
|
+
return formatCalculatedResult(computed, format);
|
|
258
|
+
}, [parsedTokens, formulaValidation.valid, optionByPath, format]);
|
|
259
|
+
|
|
200
260
|
const handleClose = useCallback(() => {
|
|
201
261
|
onClose();
|
|
202
262
|
}, [onClose]);
|
|
@@ -243,6 +303,7 @@ export const FormulaModal: FC<FormulaModalProps> = ({
|
|
|
243
303
|
isInvalid={isInvalid && formulaEditor.isDirty}
|
|
244
304
|
validationError={validationError}
|
|
245
305
|
format={format}
|
|
306
|
+
previewValue={previewValue}
|
|
246
307
|
onResultTypeChange={nextType => {
|
|
247
308
|
if (nextType === 'date') {
|
|
248
309
|
setFormat(DEFAULT_DATE_CALCULATED_FORMAT);
|
|
@@ -30,6 +30,7 @@ interface FormulaWorkspaceProps {
|
|
|
30
30
|
onRemoveField: (fieldIndex: number) => void;
|
|
31
31
|
onResultTypeChange: (nextType: CalculatedFieldFormat['resultType']) => void;
|
|
32
32
|
onToggleAdvanced: () => void;
|
|
33
|
+
previewValue: string;
|
|
33
34
|
setFormat: Dispatch<SetStateAction<CalculatedFieldFormat>>;
|
|
34
35
|
validationError: string;
|
|
35
36
|
}
|
|
@@ -50,6 +51,7 @@ export const FormulaWorkspace: FC<FormulaWorkspaceProps> = ({
|
|
|
50
51
|
onRemoveField,
|
|
51
52
|
onResultTypeChange,
|
|
52
53
|
onToggleAdvanced,
|
|
54
|
+
previewValue,
|
|
53
55
|
setFormat,
|
|
54
56
|
validationError,
|
|
55
57
|
}) => {
|
|
@@ -74,6 +76,12 @@ export const FormulaWorkspace: FC<FormulaWorkspaceProps> = ({
|
|
|
74
76
|
|
|
75
77
|
return (
|
|
76
78
|
<Flex direction="column" flex={1} gap={2} style={{ padding: '12px' }}>
|
|
79
|
+
<Flex direction="column" gap={1}>
|
|
80
|
+
<Text variant="body" size="small">
|
|
81
|
+
Preview (uses demo sample data)
|
|
82
|
+
</Text>
|
|
83
|
+
<div className="dte-formula-preview">{previewValue ?? ' '}</div>
|
|
84
|
+
</Flex>
|
|
77
85
|
<Text variant="body" size="small">
|
|
78
86
|
Click a field on the left to add it. Use +, -,{' '}
|
|
79
87
|
{disabledOperators?.has('*') ? '' : '*, /, and '}parentheses to build formulas.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Flex, SearchField, Text } from '@servicetitan/anvil2';
|
|
2
2
|
import { FC, Fragment, useMemo, useState } from 'react';
|
|
3
3
|
import { DataModelFieldGroup, FieldTypeOption } from '../../interface/types';
|
|
4
|
+
import { getFieldSampleData } from '../../utils';
|
|
4
5
|
import { FieldType } from './field-type';
|
|
5
6
|
|
|
6
7
|
interface DataModelFieldTypeListProps {
|
|
@@ -51,9 +52,13 @@ export const DataModelFieldTypeList: FC<DataModelFieldTypeListProps> = ({
|
|
|
51
52
|
return (
|
|
52
53
|
<FieldType
|
|
53
54
|
key={key}
|
|
54
|
-
label={fieldOption.label}
|
|
55
55
|
onDragEnd={onDragEnd}
|
|
56
56
|
onDragStart={() => onDragStart(fieldOption)}
|
|
57
|
+
label={fieldOption.label}
|
|
58
|
+
sampleData={getFieldSampleData(
|
|
59
|
+
fieldOption.sampleData,
|
|
60
|
+
fieldOption.fieldType,
|
|
61
|
+
)}
|
|
57
62
|
/>
|
|
58
63
|
);
|
|
59
64
|
})}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { Icon, Text } from '@servicetitan/anvil2';
|
|
1
|
+
import { Flex, Icon, Text } from '@servicetitan/anvil2';
|
|
2
2
|
import IconDragIndicator from '@servicetitan/anvil2/assets/icons/material/round/drag_indicator.svg';
|
|
3
3
|
import { FC } from 'react';
|
|
4
4
|
|
|
5
5
|
interface FieldTypeProps {
|
|
6
6
|
label: string;
|
|
7
|
+
sampleData?: string | number | null;
|
|
7
8
|
onDragEnd(): void;
|
|
8
9
|
onDragStart(): void;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
export const FieldType: FC<FieldTypeProps> = ({ label, onDragEnd, onDragStart }) => {
|
|
12
|
+
export const FieldType: FC<FieldTypeProps> = ({ label, onDragEnd, onDragStart, sampleData }) => {
|
|
12
13
|
return (
|
|
13
14
|
<div
|
|
14
15
|
draggable
|
|
@@ -22,7 +23,19 @@ export const FieldType: FC<FieldTypeProps> = ({ label, onDragEnd, onDragStart })
|
|
|
22
23
|
className="dte-field-type-item"
|
|
23
24
|
>
|
|
24
25
|
<Icon svg={IconDragIndicator} size="medium" />
|
|
25
|
-
<
|
|
26
|
+
<Flex direction="column" style={{ overflow: 'hidden' }}>
|
|
27
|
+
<Text size="small">{label}</Text>
|
|
28
|
+
{sampleData && (
|
|
29
|
+
<Text
|
|
30
|
+
size="small"
|
|
31
|
+
subdued
|
|
32
|
+
style={{ fontSize: '12px', marginTop: '-2px' }}
|
|
33
|
+
className="ellipsis"
|
|
34
|
+
>
|
|
35
|
+
e.g. {sampleData}
|
|
36
|
+
</Text>
|
|
37
|
+
)}
|
|
38
|
+
</Flex>
|
|
26
39
|
</div>
|
|
27
40
|
);
|
|
28
41
|
};
|
|
@@ -4,6 +4,7 @@ import IconArrowForward from '@servicetitan/anvil2/assets/icons/material/round/k
|
|
|
4
4
|
import { Stack } from '@servicetitan/design-system';
|
|
5
5
|
import { FC, Fragment } from 'react';
|
|
6
6
|
import { FieldTypeOption, FormInfo } from '../../interface/types';
|
|
7
|
+
import { getFieldSampleData } from '../../utils';
|
|
7
8
|
import { FieldType } from './field-type';
|
|
8
9
|
|
|
9
10
|
export interface FormFieldsTypeListProps {
|
|
@@ -97,6 +98,10 @@ export const FormFieldsTypeList: FC<FormFieldsTypeListProps> = ({
|
|
|
97
98
|
<FieldType
|
|
98
99
|
key={option.path}
|
|
99
100
|
label={option.label}
|
|
101
|
+
sampleData={getFieldSampleData(
|
|
102
|
+
option.sampleData,
|
|
103
|
+
option.fieldType,
|
|
104
|
+
)}
|
|
100
105
|
onDragEnd={onDragEnd}
|
|
101
106
|
onDragStart={() => onDragStart(option)}
|
|
102
107
|
/>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
2
|
import { DataModelValues, PdfField } from '../../interface/types';
|
|
3
|
-
import { resolvePdfDataValues } from '../../utils';
|
|
3
|
+
import { nl2br, resolvePdfDataValues } from '../../utils';
|
|
4
4
|
|
|
5
5
|
interface PdfViewDataModelProps {
|
|
6
6
|
field: PdfField;
|
|
@@ -9,5 +9,16 @@ interface PdfViewDataModelProps {
|
|
|
9
9
|
|
|
10
10
|
export const PdfViewDataModel: FC<PdfViewDataModelProps> = ({ data, field }) => {
|
|
11
11
|
const resolvedValue = field.path ? resolvePdfDataValues(data, field.path) : '';
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* Mirrors Unlayer's `{{ field | safe | nl2br }}` as
|
|
15
|
+
* conversion. The `__html` key and `dangerouslySetInnerHTML` are mandated by React's API.
|
|
16
|
+
*/
|
|
17
|
+
return (
|
|
18
|
+
<div
|
|
19
|
+
className="dte-pdf-field-value"
|
|
20
|
+
// eslint-disable-next-line react/no-danger, @typescript-eslint/naming-convention
|
|
21
|
+
dangerouslySetInnerHTML={{ __html: nl2br(resolvedValue ?? '') }}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
13
24
|
};
|
package/src/interface/types.ts
CHANGED
|
@@ -116,6 +116,16 @@
|
|
|
116
116
|
white-space: pre-wrap;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
.dte-formula-preview {
|
|
120
|
+
padding: var(--spacing-1) var(--spacing-2);
|
|
121
|
+
border: 1px solid var(--border-color);
|
|
122
|
+
border-radius: 4px;
|
|
123
|
+
height: 20px;
|
|
124
|
+
background-color: var(--color-neutral-10, #f5f6f7);
|
|
125
|
+
font-size: var(--typescale-2);
|
|
126
|
+
line-height: var(--base-line-height);
|
|
127
|
+
}
|
|
128
|
+
|
|
119
129
|
.dte-formula-editor:focus {
|
|
120
130
|
border-color: var(--border-color-active);
|
|
121
131
|
box-shadow: 0 0 0 1px var(--border-color-active);
|
|
@@ -91,6 +91,7 @@ export const extractGroupedFieldsFromDataModel = (
|
|
|
91
91
|
type: FieldTypeEnum.dataModel,
|
|
92
92
|
path: key,
|
|
93
93
|
fieldType: getSchemaFieldType(property),
|
|
94
|
+
sampleData: property?.options?.sampleData,
|
|
94
95
|
});
|
|
95
96
|
}
|
|
96
97
|
}
|
|
@@ -132,6 +133,7 @@ const extractFieldsRecursive = (
|
|
|
132
133
|
type: FieldTypeEnum.dataModel,
|
|
133
134
|
path: currentPath,
|
|
134
135
|
fieldType: getSchemaFieldType(fieldProperty),
|
|
136
|
+
sampleData: fieldProperty.options?.sampleData,
|
|
135
137
|
});
|
|
136
138
|
} else if (fieldProperty.type === 'object' && fieldProperty.properties) {
|
|
137
139
|
extractFieldsRecursive(
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { PdfFieldSubType } from '../../interface/types';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_NUMBER_SAMPLE = 350;
|
|
4
|
+
|
|
5
|
+
const toPrimitiveSample = (value: unknown): string | number | undefined => {
|
|
6
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
return undefined;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const getFieldSampleData = (
|
|
13
|
+
sampleData: unknown,
|
|
14
|
+
fieldSubType?: PdfFieldSubType,
|
|
15
|
+
): string | number | null => {
|
|
16
|
+
const primitiveSample = toPrimitiveSample(sampleData);
|
|
17
|
+
|
|
18
|
+
if (fieldSubType === 'date') {
|
|
19
|
+
const candidate = primitiveSample !== undefined ? new Date(primitiveSample) : new Date();
|
|
20
|
+
const source = Number.isNaN(candidate.getTime()) ? new Date() : candidate;
|
|
21
|
+
return source.toISOString().slice(0, 10);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (fieldSubType === 'number') {
|
|
25
|
+
return primitiveSample ?? DEFAULT_NUMBER_SAMPLE;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return primitiveSample ?? null;
|
|
29
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React/HTML equivalent of the Nunjucks `nl2br` filter used by Unlayer's
|
|
3
|
+
* `{{ field | safe | nl2br }}` template. Replaces every `\r\n` or `\n` with `<br />\n`,
|
|
4
|
+
* keeping the original newline so the rendered HTML source still wraps in dev tools.
|
|
5
|
+
*/
|
|
6
|
+
export const nl2br = (value: string): string => {
|
|
7
|
+
return value.replace(/\r\n|\n/g, '<br />\n');
|
|
8
|
+
};
|