@bpmn-io/form-js-viewer 1.25.0 → 1.26.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/index.cjs +171 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +171 -62
- package/dist/index.es.js.map +1 -1
- package/dist/types/core/FieldFactory.d.ts +10 -3
- package/dist/types/core/Validator.d.ts +2 -1
- package/dist/types/render/components/form-fields/DocumentPreview.d.ts +4 -0
- package/dist/types/render/components/form-fields/FilePicker.d.ts +1 -0
- package/dist/types/render/components/form-fields/Table.d.ts +3 -0
- package/package.json +6 -2
package/dist/index.es.js
CHANGED
|
@@ -16,6 +16,46 @@ import { parseExpression, parseUnaryTests, evaluate, unaryTest } from '@bpmn-io/
|
|
|
16
16
|
import { evaluate as evaluate$1, parseToSimpleTree } from 'feelers';
|
|
17
17
|
import { marked } from 'marked';
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* @typedef { {
|
|
21
|
+
* [key: string]: string;
|
|
22
|
+
* } } TranslateReplacements
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A simple translation stub to be used for multi-language support
|
|
27
|
+
* in diagrams. Can be easily replaced with a more sophisticated
|
|
28
|
+
* solution.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
*
|
|
32
|
+
* ```javascript
|
|
33
|
+
* // use it inside any diagram component by injecting `translate`.
|
|
34
|
+
*
|
|
35
|
+
* function MyService(translate) {
|
|
36
|
+
* alert(translate('HELLO {you}', { you: 'You!' }));
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @param {string} template to interpolate
|
|
41
|
+
* @param {TranslateReplacements} [replacements] a map with substitutes
|
|
42
|
+
*
|
|
43
|
+
* @return {string} the translated string
|
|
44
|
+
*/
|
|
45
|
+
function translate(template, replacements) {
|
|
46
|
+
replacements = replacements || {};
|
|
47
|
+
return template.replace(/{([^}]+)}/g, function (_, key) {
|
|
48
|
+
return replacements[key] || '{' + key + '}';
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @type { import('didi').ModuleDeclaration }
|
|
54
|
+
*/
|
|
55
|
+
var TranslateModule = {
|
|
56
|
+
translate: ['value', translate]
|
|
57
|
+
};
|
|
58
|
+
|
|
19
59
|
const getFlavouredFeelVariableNames = (feelString, feelFlavour = 'expression', options = {}) => {
|
|
20
60
|
const {
|
|
21
61
|
depth = 0,
|
|
@@ -3047,6 +3087,7 @@ function Datetime(props) {
|
|
|
3047
3087
|
const {
|
|
3048
3088
|
formId
|
|
3049
3089
|
} = useContext(FormContext);
|
|
3090
|
+
const translate = useService('translate');
|
|
3050
3091
|
|
|
3051
3092
|
/** @type {import("preact").RefObject<HTMLDivElement>} */
|
|
3052
3093
|
const dateTimeGroupRef = useRef();
|
|
@@ -3137,8 +3178,8 @@ function Datetime(props) {
|
|
|
3137
3178
|
const allErrors = useMemo(() => {
|
|
3138
3179
|
if (required || subtype !== DATETIME_SUBTYPES.DATETIME) return errors;
|
|
3139
3180
|
const isOnlyOneFieldSet = isValidDate(dateTime.date) && !isValidTime(dateTime.time) || !isValidDate(dateTime.date) && isValidTime(dateTime.time);
|
|
3140
|
-
return isOnlyOneFieldSet ? ['Date and time must both be entered.', ...errors] : errors;
|
|
3141
|
-
}, [required, subtype, dateTime, errors]);
|
|
3181
|
+
return isOnlyOneFieldSet ? [translate('Date and time must both be entered.'), ...errors] : errors;
|
|
3182
|
+
}, [required, subtype, dateTime, errors, translate]);
|
|
3142
3183
|
const setDate = useCallback(date => {
|
|
3143
3184
|
setDateTimeUpdateRequest(prev => prev ? {
|
|
3144
3185
|
...prev,
|
|
@@ -3300,6 +3341,7 @@ function IFrame(props) {
|
|
|
3300
3341
|
const evaluatedLabel = useSingleLineTemplateEvaluation(label, {
|
|
3301
3342
|
debug: true
|
|
3302
3343
|
});
|
|
3344
|
+
const translate = useService('translate');
|
|
3303
3345
|
const [sandbox, allow] = useSecurityAttributesMap(security);
|
|
3304
3346
|
const [iframeRefresh, setIframeRefresh] = useState(0);
|
|
3305
3347
|
|
|
@@ -3316,7 +3358,7 @@ function IFrame(props) {
|
|
|
3316
3358
|
htmlFor: domId,
|
|
3317
3359
|
label: evaluatedLabel
|
|
3318
3360
|
}), !evaluatedUrl && jsx(IFramePlaceholder, {
|
|
3319
|
-
text:
|
|
3361
|
+
text: translate('No content to show.')
|
|
3320
3362
|
}), evaluatedUrl && safeUrl && jsx("iframe", {
|
|
3321
3363
|
src: safeUrl,
|
|
3322
3364
|
title: evaluatedLabel,
|
|
@@ -3326,7 +3368,7 @@ function IFrame(props) {
|
|
|
3326
3368
|
sandbox: sandbox,
|
|
3327
3369
|
allow
|
|
3328
3370
|
}, 'iframe-' + iframeRefresh), evaluatedUrl && !safeUrl && jsx(IFramePlaceholder, {
|
|
3329
|
-
text: "External content couldn't be loaded."
|
|
3371
|
+
text: translate("External content couldn't be loaded.")
|
|
3330
3372
|
})]
|
|
3331
3373
|
});
|
|
3332
3374
|
}
|
|
@@ -3914,6 +3956,7 @@ function Numberfield(props) {
|
|
|
3914
3956
|
const {
|
|
3915
3957
|
required
|
|
3916
3958
|
} = validate;
|
|
3959
|
+
const translate = useService('translate');
|
|
3917
3960
|
|
|
3918
3961
|
/** @type {import("preact").RefObject<HTMLInputElement>} */
|
|
3919
3962
|
const inputRef = useRef();
|
|
@@ -4087,7 +4130,7 @@ function Numberfield(props) {
|
|
|
4087
4130
|
children: [jsx("button", {
|
|
4088
4131
|
type: "button",
|
|
4089
4132
|
class: "fjs-number-arrow-up",
|
|
4090
|
-
"aria-label":
|
|
4133
|
+
"aria-label": translate('Increment'),
|
|
4091
4134
|
onClick: () => increment(),
|
|
4092
4135
|
tabIndex: -1,
|
|
4093
4136
|
children: jsx(SvgAngelUp, {})
|
|
@@ -4096,7 +4139,7 @@ function Numberfield(props) {
|
|
|
4096
4139
|
}), jsx("button", {
|
|
4097
4140
|
type: "button",
|
|
4098
4141
|
class: "fjs-number-arrow-down",
|
|
4099
|
-
"aria-label":
|
|
4142
|
+
"aria-label": translate('Decrement'),
|
|
4100
4143
|
onClick: () => decrement(),
|
|
4101
4144
|
tabIndex: -1,
|
|
4102
4145
|
children: jsx(SvgAngelDown, {})
|
|
@@ -4779,6 +4822,7 @@ function Taglist(props) {
|
|
|
4779
4822
|
/** @type {import("preact").RefObject<HTMLInputElement>} */
|
|
4780
4823
|
const inputRef = useRef();
|
|
4781
4824
|
const eventBus = useService('eventBus');
|
|
4825
|
+
const translate = useService('translate');
|
|
4782
4826
|
const {
|
|
4783
4827
|
loadState,
|
|
4784
4828
|
options
|
|
@@ -4912,7 +4956,7 @@ function Taglist(props) {
|
|
|
4912
4956
|
htmlFor: domId
|
|
4913
4957
|
}), !disabled && !readonly && !!values.length && jsx(SkipLink, {
|
|
4914
4958
|
className: "fjs-taglist-skip-link",
|
|
4915
|
-
label:
|
|
4959
|
+
label: translate('Skip to search'),
|
|
4916
4960
|
onSkip: onSkipToSearch
|
|
4917
4961
|
}), jsxs("div", {
|
|
4918
4962
|
class: classNames('fjs-taglist', {
|
|
@@ -4933,7 +4977,7 @@ function Taglist(props) {
|
|
|
4933
4977
|
children: getLabelCorrelation(entry)
|
|
4934
4978
|
}), !disabled && !readonly && jsx("button", {
|
|
4935
4979
|
type: "button",
|
|
4936
|
-
title:
|
|
4980
|
+
title: translate('Remove tag'),
|
|
4937
4981
|
class: "fjs-taglist-tag-remove",
|
|
4938
4982
|
onFocus: onElementFocus,
|
|
4939
4983
|
onBlur: onElementBlur,
|
|
@@ -4951,7 +4995,7 @@ function Taglist(props) {
|
|
|
4951
4995
|
onChange: onInputChange,
|
|
4952
4996
|
type: "text",
|
|
4953
4997
|
value: filter,
|
|
4954
|
-
placeholder: disabled || readonly ? undefined : 'Search',
|
|
4998
|
+
placeholder: disabled || readonly ? undefined : translate('Search'),
|
|
4955
4999
|
autoComplete: "off",
|
|
4956
5000
|
onKeyDown: onInputKeyDown,
|
|
4957
5001
|
onMouseDown: () => setIsEscapeClose(false),
|
|
@@ -4967,7 +5011,7 @@ function Taglist(props) {
|
|
|
4967
5011
|
values: filteredOptions,
|
|
4968
5012
|
getLabel: option => option.label,
|
|
4969
5013
|
onValueSelected: option => selectValue(option.value),
|
|
4970
|
-
emptyListMessage: hasOptionsLeft ? 'No results' : 'All values selected',
|
|
5014
|
+
emptyListMessage: hasOptionsLeft ? translate('No results') : translate('All values selected'),
|
|
4971
5015
|
listenerElement: inputRef.current
|
|
4972
5016
|
})
|
|
4973
5017
|
}), jsx(Description, {
|
|
@@ -5570,6 +5614,8 @@ var SvgCaretRight = function SvgCaretRight(props) {
|
|
|
5570
5614
|
const type$2 = 'table';
|
|
5571
5615
|
|
|
5572
5616
|
/**
|
|
5617
|
+
* @typedef { import('diagram-js/lib/i18n/translate/translate').default } Translate
|
|
5618
|
+
*
|
|
5573
5619
|
* @typedef {('asc'|'desc')} Direction
|
|
5574
5620
|
*
|
|
5575
5621
|
* @typedef Sorting
|
|
@@ -5619,6 +5665,7 @@ function Table(props) {
|
|
|
5619
5665
|
const chunkedData = isNumber(rowCount) ? chunk(sortedData, rowCount) : [sortedData];
|
|
5620
5666
|
const [currentPage, setCurrentPage] = useState(0);
|
|
5621
5667
|
const currentChunk = chunkedData[currentPage] || [];
|
|
5668
|
+
const translate = useService('translate');
|
|
5622
5669
|
useEffect(() => {
|
|
5623
5670
|
setCurrentPage(0);
|
|
5624
5671
|
}, [rowCount, sortBy]);
|
|
@@ -5650,7 +5697,7 @@ function Table(props) {
|
|
|
5650
5697
|
class: classNames('fjs-table-middle-container', {
|
|
5651
5698
|
'fjs-table-empty': evaluatedColumns.length === 0
|
|
5652
5699
|
}),
|
|
5653
|
-
children: [evaluatedColumns.length === 0 ? 'Nothing to show.' : jsx("div", {
|
|
5700
|
+
children: [evaluatedColumns.length === 0 ? translate('Nothing to show.') : jsx("div", {
|
|
5654
5701
|
class: "fjs-table-inner-container",
|
|
5655
5702
|
children: jsxs("table", {
|
|
5656
5703
|
class: "fjs-table",
|
|
@@ -5675,7 +5722,7 @@ function Table(props) {
|
|
|
5675
5722
|
toggleSortBy(key);
|
|
5676
5723
|
}
|
|
5677
5724
|
},
|
|
5678
|
-
"aria-label": getHeaderAriaLabel(sortBy, key, displayLabel),
|
|
5725
|
+
"aria-label": getHeaderAriaLabel(sortBy, key, displayLabel, translate),
|
|
5679
5726
|
children: jsxs("span", {
|
|
5680
5727
|
class: "fjs-table-th-label",
|
|
5681
5728
|
children: [displayLabel, sortBy !== null && sortBy.key === key ? jsx(Fragment, {
|
|
@@ -5696,7 +5743,7 @@ function Table(props) {
|
|
|
5696
5743
|
children: jsx("td", {
|
|
5697
5744
|
class: "fjs-table-td",
|
|
5698
5745
|
colSpan: evaluatedColumns.length,
|
|
5699
|
-
children:
|
|
5746
|
+
children: translate('Nothing to show.')
|
|
5700
5747
|
})
|
|
5701
5748
|
})
|
|
5702
5749
|
}) : jsx("tbody", {
|
|
@@ -5712,9 +5759,13 @@ function Table(props) {
|
|
|
5712
5759
|
})
|
|
5713
5760
|
}), isNumber(rowCount) && chunkedData.length > 1 && evaluatedColumns.length > 0 ? jsxs("nav", {
|
|
5714
5761
|
class: "fjs-table-nav",
|
|
5715
|
-
children: [
|
|
5762
|
+
children: [jsx("span", {
|
|
5716
5763
|
class: "fjs-table-nav-label",
|
|
5717
|
-
children:
|
|
5764
|
+
children: translate('{page} of {total}', {
|
|
5765
|
+
// stringify: see Validator.js
|
|
5766
|
+
page: (currentPage + 1).toString(),
|
|
5767
|
+
total: chunkedData.length.toString()
|
|
5768
|
+
})
|
|
5718
5769
|
}), jsx("button", {
|
|
5719
5770
|
type: "button",
|
|
5720
5771
|
class: "fjs-table-nav-button",
|
|
@@ -5722,7 +5773,7 @@ function Table(props) {
|
|
|
5722
5773
|
setCurrentPage(page => Math.max(page - 1, 0));
|
|
5723
5774
|
},
|
|
5724
5775
|
disabled: currentPage === 0,
|
|
5725
|
-
"aria-label":
|
|
5776
|
+
"aria-label": translate('Previous page'),
|
|
5726
5777
|
children: jsx(SvgCaretLeft, {})
|
|
5727
5778
|
}), jsx("button", {
|
|
5728
5779
|
type: "button",
|
|
@@ -5731,7 +5782,7 @@ function Table(props) {
|
|
|
5731
5782
|
setCurrentPage(page => Math.min(page + 1, chunkedData.length - 1));
|
|
5732
5783
|
},
|
|
5733
5784
|
disabled: currentPage >= chunkedData.length - 1,
|
|
5734
|
-
"aria-label":
|
|
5785
|
+
"aria-label": translate('Next page'),
|
|
5735
5786
|
children: jsx(SvgCaretRight, {})
|
|
5736
5787
|
})]
|
|
5737
5788
|
}) : null]
|
|
@@ -5881,15 +5932,20 @@ function sortByColumn(array, key, direction) {
|
|
|
5881
5932
|
* @param {null|Sorting} sortBy
|
|
5882
5933
|
* @param {string} key
|
|
5883
5934
|
* @param {string} label
|
|
5935
|
+
* @param {Translate} translate
|
|
5884
5936
|
*/
|
|
5885
|
-
function getHeaderAriaLabel(sortBy, key, label) {
|
|
5937
|
+
function getHeaderAriaLabel(sortBy, key, label, translate) {
|
|
5886
5938
|
if (sortBy === null || sortBy.key !== key) {
|
|
5887
|
-
return
|
|
5939
|
+
return translate('Click to sort by {value} descending', {
|
|
5940
|
+
value: label
|
|
5941
|
+
});
|
|
5888
5942
|
}
|
|
5889
5943
|
if (sortBy.direction === 'asc') {
|
|
5890
|
-
return 'Click to remove sorting';
|
|
5944
|
+
return translate('Click to remove sorting');
|
|
5891
5945
|
}
|
|
5892
|
-
return
|
|
5946
|
+
return translate('Click to sort by {value} ascending', {
|
|
5947
|
+
value: label
|
|
5948
|
+
});
|
|
5893
5949
|
}
|
|
5894
5950
|
|
|
5895
5951
|
/**
|
|
@@ -5960,6 +6016,7 @@ function FilePicker(props) {
|
|
|
5960
6016
|
const errorMessageId = `${domId}-error-message`;
|
|
5961
6017
|
/** @type {File[]} */
|
|
5962
6018
|
const selectedFiles = fileRegistry === null ? EMPTY_ARRAY$1 : fileRegistry.getFiles(filesKey);
|
|
6019
|
+
const translate = useService('translate');
|
|
5963
6020
|
useEffect(() => {
|
|
5964
6021
|
if (filesKey && fileRegistry !== null && !fileRegistry.hasKey(filesKey)) {
|
|
5965
6022
|
onChange({
|
|
@@ -6030,7 +6087,7 @@ function FilePicker(props) {
|
|
|
6030
6087
|
children: "Browse"
|
|
6031
6088
|
}), jsx("span", {
|
|
6032
6089
|
className: "fjs-form-field-label",
|
|
6033
|
-
children: getSelectedFilesLabel(selectedFiles)
|
|
6090
|
+
children: getSelectedFilesLabel(selectedFiles, translate)
|
|
6034
6091
|
})]
|
|
6035
6092
|
}), jsx(Errors, {
|
|
6036
6093
|
id: errorMessageId,
|
|
@@ -6053,16 +6110,19 @@ FilePicker.config = {
|
|
|
6053
6110
|
|
|
6054
6111
|
/**
|
|
6055
6112
|
* @param {File[]} files
|
|
6113
|
+
* @param {Translate} translate
|
|
6056
6114
|
* @returns {string}
|
|
6057
6115
|
*/
|
|
6058
|
-
function getSelectedFilesLabel(files) {
|
|
6116
|
+
function getSelectedFilesLabel(files, translate) {
|
|
6059
6117
|
if (files.length === 0) {
|
|
6060
|
-
return 'No files selected';
|
|
6118
|
+
return translate('No files selected');
|
|
6061
6119
|
}
|
|
6062
6120
|
if (files.length === 1) {
|
|
6063
6121
|
return files[0].name;
|
|
6064
6122
|
}
|
|
6065
|
-
return
|
|
6123
|
+
return translate('{value} files selected', {
|
|
6124
|
+
value: files.length.toString()
|
|
6125
|
+
});
|
|
6066
6126
|
}
|
|
6067
6127
|
|
|
6068
6128
|
var _path$4;
|
|
@@ -6085,6 +6145,10 @@ var SvgDownload = function SvgDownload(props) {
|
|
|
6085
6145
|
|
|
6086
6146
|
const type = 'documentPreview';
|
|
6087
6147
|
|
|
6148
|
+
/**
|
|
6149
|
+
* @typedef { import('diagram-js/lib/i18n/translate/translate').default } Translate
|
|
6150
|
+
*/
|
|
6151
|
+
|
|
6088
6152
|
/**
|
|
6089
6153
|
* @typedef DocumentEndpointBuilder
|
|
6090
6154
|
* @property {(document: DocumentMetadata) => string} [buildUrl]
|
|
@@ -6130,6 +6194,7 @@ function DocumentPreview(props) {
|
|
|
6130
6194
|
const evaluatedLabel = useSingleLineTemplateEvaluation(label, {
|
|
6131
6195
|
debug: true
|
|
6132
6196
|
});
|
|
6197
|
+
const translate = useService('translate');
|
|
6133
6198
|
return jsxs("div", {
|
|
6134
6199
|
class: formFieldClasses(type),
|
|
6135
6200
|
children: [jsx(Label, {
|
|
@@ -6155,7 +6220,7 @@ function DocumentPreview(props) {
|
|
|
6155
6220
|
id: errorMessageId,
|
|
6156
6221
|
errors: getErrors({
|
|
6157
6222
|
dataSource
|
|
6158
|
-
})
|
|
6223
|
+
}, translate)
|
|
6159
6224
|
})]
|
|
6160
6225
|
});
|
|
6161
6226
|
}
|
|
@@ -6177,15 +6242,16 @@ DocumentPreview.config = {
|
|
|
6177
6242
|
* @property {string|undefined} dataSource
|
|
6178
6243
|
*
|
|
6179
6244
|
* @param {GetErrorOptions} options
|
|
6245
|
+
* @param {Translate} translate
|
|
6180
6246
|
* @returns {string[]}
|
|
6181
6247
|
*/
|
|
6182
|
-
function getErrors(options) {
|
|
6248
|
+
function getErrors(options, translate) {
|
|
6183
6249
|
const {
|
|
6184
6250
|
dataSource
|
|
6185
6251
|
} = options;
|
|
6186
6252
|
let errors = [];
|
|
6187
6253
|
if (!isString(dataSource) || dataSource.length < 1) {
|
|
6188
|
-
errors.push('Document reference is not defined.');
|
|
6254
|
+
errors.push(translate('Document reference is not defined.'));
|
|
6189
6255
|
}
|
|
6190
6256
|
return errors;
|
|
6191
6257
|
}
|
|
@@ -6238,6 +6304,7 @@ function PdfRenderer(props) {
|
|
|
6238
6304
|
/** @type {ReturnType<typeof import("preact/hooks").useState<null | string>>} */
|
|
6239
6305
|
const [pdfObjectUrl, setPdfObjectUrl] = useState(null);
|
|
6240
6306
|
const [hasError, setHasError] = useState(false);
|
|
6307
|
+
const translate = useService('translate');
|
|
6241
6308
|
useEffect(() => {
|
|
6242
6309
|
/** @type {null | string} */
|
|
6243
6310
|
let objectUrl = null;
|
|
@@ -6271,7 +6338,7 @@ function PdfRenderer(props) {
|
|
|
6271
6338
|
class: `fjs-${type}-pdf-viewer`
|
|
6272
6339
|
}) : null, hasError ? jsx(Errors, {
|
|
6273
6340
|
id: errorMessageId,
|
|
6274
|
-
errors: ['Unable to download document']
|
|
6341
|
+
errors: [translate('Unable to download document')]
|
|
6275
6342
|
}) : null]
|
|
6276
6343
|
});
|
|
6277
6344
|
}
|
|
@@ -6351,9 +6418,10 @@ function DocumentRenderer(props) {
|
|
|
6351
6418
|
const isInViewport = useInViewport(ref);
|
|
6352
6419
|
const onError = useCallback(() => setHasError(true), []);
|
|
6353
6420
|
const requestInit = useMemo(() => getDocumentRequestInit(documentEndpointBuilder, documentMetadata), [documentEndpointBuilder, documentMetadata]);
|
|
6421
|
+
const translate = useService('translate');
|
|
6354
6422
|
const singleDocumentContainerClassName = `fjs-${type}-single-document-container`;
|
|
6355
6423
|
const errorMessageId = `${domId}-error-message`;
|
|
6356
|
-
const errorMessage = 'Unable to download document';
|
|
6424
|
+
const errorMessage = translate('Unable to download document');
|
|
6357
6425
|
const isContentTypePresent = typeof metadata.contentType === 'string';
|
|
6358
6426
|
if (isContentTypePresent && metadata.contentType.toLowerCase().startsWith('image/') && isInViewport) {
|
|
6359
6427
|
return jsxs("div", {
|
|
@@ -6431,6 +6499,7 @@ function DownloadButton(props) {
|
|
|
6431
6499
|
onDownloadError,
|
|
6432
6500
|
requestInit
|
|
6433
6501
|
} = props;
|
|
6502
|
+
const translate = useService('translate');
|
|
6434
6503
|
const handleDownload = async () => {
|
|
6435
6504
|
try {
|
|
6436
6505
|
const response = await fetch(endpoint, requestInit);
|
|
@@ -6453,7 +6522,9 @@ function DownloadButton(props) {
|
|
|
6453
6522
|
type: "button",
|
|
6454
6523
|
onClick: handleDownload,
|
|
6455
6524
|
class: classNames(`fjs-${type}-download-button`),
|
|
6456
|
-
"aria-label":
|
|
6525
|
+
"aria-label": translate('Download {fileName}', {
|
|
6526
|
+
fileName
|
|
6527
|
+
}),
|
|
6457
6528
|
children: jsx(SvgDownload, {})
|
|
6458
6529
|
});
|
|
6459
6530
|
}
|
|
@@ -7799,6 +7870,7 @@ class RepeatRenderManager {
|
|
|
7799
7870
|
const {
|
|
7800
7871
|
data
|
|
7801
7872
|
} = this._form._getState();
|
|
7873
|
+
const translate = useService('translate');
|
|
7802
7874
|
const dataPath = this._pathRegistry.getValuePath(repeaterField, {
|
|
7803
7875
|
indexes
|
|
7804
7876
|
});
|
|
@@ -7855,16 +7927,18 @@ class RepeatRenderManager {
|
|
|
7855
7927
|
ref: addButtonRef,
|
|
7856
7928
|
onClick: onAddItem,
|
|
7857
7929
|
children: jsxs(Fragment, {
|
|
7858
|
-
children: [jsx(SvgAdd, {}), " ", 'Add new']
|
|
7930
|
+
children: [jsx(SvgAdd, {}), " ", translate('Add new')]
|
|
7859
7931
|
})
|
|
7860
7932
|
}) : null, collapseEnabled ? jsx("button", {
|
|
7861
7933
|
type: "button",
|
|
7862
7934
|
class: "fjs-repeat-render-collapse",
|
|
7863
7935
|
onClick: toggle,
|
|
7864
7936
|
children: isCollapsed ? jsxs(Fragment, {
|
|
7865
|
-
children: [jsx(SvgExpand, {}), " ",
|
|
7937
|
+
children: [jsx(SvgExpand, {}), " ", translate('Expand all ({value})', {
|
|
7938
|
+
value: values.length - 1
|
|
7939
|
+
})]
|
|
7866
7940
|
}) : jsxs(Fragment, {
|
|
7867
|
-
children: [jsx(SvgCollapse, {}), " ", 'Collapse']
|
|
7941
|
+
children: [jsx(SvgCollapse, {}), " ", translate('Collapse')]
|
|
7868
7942
|
})
|
|
7869
7943
|
}) : null]
|
|
7870
7944
|
});
|
|
@@ -8497,11 +8571,12 @@ const EMAIL_PATTERN = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-
|
|
|
8497
8571
|
const PHONE_PATTERN = /(\+|00)(297|93|244|1264|358|355|376|971|54|374|1684|1268|61|43|994|257|32|229|226|880|359|973|1242|387|590|375|501|1441|591|55|1246|673|975|267|236|1|61|41|56|86|225|237|243|242|682|57|269|238|506|53|5999|61|1345|357|420|49|253|1767|45|1809|1829|1849|213|593|20|291|212|34|372|251|358|679|500|33|298|691|241|44|995|44|233|350|224|590|220|245|240|30|1473|299|502|594|1671|592|852|504|385|509|36|62|44|91|246|353|98|964|354|972|39|1876|44|962|81|76|77|254|996|855|686|1869|82|383|965|856|961|231|218|1758|423|94|266|370|352|371|853|590|212|377|373|261|960|52|692|389|223|356|95|382|976|1670|258|222|1664|596|230|265|60|262|264|687|227|672|234|505|683|31|47|977|674|64|968|92|507|64|51|63|680|675|48|1787|1939|850|351|595|970|689|974|262|40|7|250|966|249|221|65|500|4779|677|232|503|378|252|508|381|211|239|597|421|386|46|268|1721|248|963|1649|235|228|66|992|690|993|670|676|1868|216|90|688|886|255|256|380|598|1|998|3906698|379|1784|58|1284|1340|84|678|681|685|967|27|260|263)(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\d{4,20}$/;
|
|
8498
8572
|
const VALIDATE_FEEL_PROPERTIES = ['min', 'max', 'minLength', 'maxLength'];
|
|
8499
8573
|
class Validator {
|
|
8500
|
-
constructor(expressionLanguage, conditionChecker, form, formFieldRegistry) {
|
|
8574
|
+
constructor(expressionLanguage, conditionChecker, form, formFieldRegistry, translate) {
|
|
8501
8575
|
this._expressionLanguage = expressionLanguage;
|
|
8502
8576
|
this._conditionChecker = conditionChecker;
|
|
8503
8577
|
this._form = form;
|
|
8504
8578
|
this._formFieldRegistry = formFieldRegistry;
|
|
8579
|
+
this._translate = translate;
|
|
8505
8580
|
}
|
|
8506
8581
|
|
|
8507
8582
|
/**
|
|
@@ -8516,13 +8591,13 @@ class Validator {
|
|
|
8516
8591
|
} = field;
|
|
8517
8592
|
let errors = [];
|
|
8518
8593
|
if (type === 'number') {
|
|
8519
|
-
errors = [...errors, ...runNumberValidation(field, value)];
|
|
8594
|
+
errors = [...errors, ...runNumberValidation(field, value, this._translate)];
|
|
8520
8595
|
}
|
|
8521
8596
|
if (!validate) {
|
|
8522
8597
|
return errors;
|
|
8523
8598
|
}
|
|
8524
8599
|
const evaluatedValidation = oldEvaluateFEELValues(validate, this._expressionLanguage, this._conditionChecker, this._form);
|
|
8525
|
-
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value)];
|
|
8600
|
+
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value, this._translate)];
|
|
8526
8601
|
return errors;
|
|
8527
8602
|
}
|
|
8528
8603
|
|
|
@@ -8549,31 +8624,39 @@ class Validator {
|
|
|
8549
8624
|
} = field;
|
|
8550
8625
|
let errors = [];
|
|
8551
8626
|
if (type === 'number') {
|
|
8552
|
-
errors = [...errors, ...runNumberValidation(field, value)];
|
|
8627
|
+
errors = [...errors, ...runNumberValidation(field, value, this._translate)];
|
|
8553
8628
|
}
|
|
8554
8629
|
if (!validate) {
|
|
8555
8630
|
return errors;
|
|
8556
8631
|
}
|
|
8557
8632
|
const evaluatedValidation = evaluateFEELValues(validate, this._expressionLanguage, expressionContextInfo);
|
|
8558
|
-
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value)];
|
|
8633
|
+
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value, this._translate)];
|
|
8559
8634
|
return errors;
|
|
8560
8635
|
}
|
|
8561
8636
|
}
|
|
8562
|
-
Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form', 'formFieldRegistry'];
|
|
8637
|
+
Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form', 'formFieldRegistry', 'translate'];
|
|
8563
8638
|
|
|
8564
8639
|
// helpers //////////
|
|
8565
8640
|
|
|
8566
|
-
function runNumberValidation(field, value) {
|
|
8641
|
+
function runNumberValidation(field, value, translate) {
|
|
8567
8642
|
const {
|
|
8568
8643
|
decimalDigits,
|
|
8569
8644
|
increment
|
|
8570
8645
|
} = field;
|
|
8571
8646
|
const errors = [];
|
|
8572
8647
|
if (value === 'NaN') {
|
|
8573
|
-
errors.push('Value is not a number.');
|
|
8648
|
+
errors.push(translate('Value is not a number.'));
|
|
8574
8649
|
} else if (value) {
|
|
8575
8650
|
if (decimalDigits >= 0 && countDecimals(value) > decimalDigits) {
|
|
8576
|
-
|
|
8651
|
+
if (decimalDigits === 0) {
|
|
8652
|
+
errors.push(translate('Value is expected to be an integer.'));
|
|
8653
|
+
} else if (decimalDigits === 1) {
|
|
8654
|
+
errors.push(translate('Value is expected to have at most 1 decimal digit.'));
|
|
8655
|
+
} else {
|
|
8656
|
+
errors.push(translate('Value is expected to have at most {value} decimal digits.', {
|
|
8657
|
+
value: decimalDigits.toString()
|
|
8658
|
+
}));
|
|
8659
|
+
}
|
|
8577
8660
|
}
|
|
8578
8661
|
if (increment) {
|
|
8579
8662
|
const bigValue = Big(value);
|
|
@@ -8582,54 +8665,69 @@ function runNumberValidation(field, value) {
|
|
|
8582
8665
|
if (offset.cmp(0) !== 0) {
|
|
8583
8666
|
const previousValue = bigValue.minus(offset);
|
|
8584
8667
|
const nextValue = previousValue.plus(bigIncrement);
|
|
8585
|
-
errors.push(
|
|
8668
|
+
errors.push(translate('Please select a valid value, the two nearest valid values are {previousValue} and {nextValue}.', {
|
|
8669
|
+
previousValue: previousValue,
|
|
8670
|
+
nextValue: nextValue
|
|
8671
|
+
}));
|
|
8586
8672
|
}
|
|
8587
8673
|
}
|
|
8588
8674
|
}
|
|
8589
8675
|
return errors;
|
|
8590
8676
|
}
|
|
8591
|
-
function runPresetValidation(field, validation, value) {
|
|
8677
|
+
function runPresetValidation(field, validation, value, translate) {
|
|
8592
8678
|
const errors = [];
|
|
8593
8679
|
if (validation.pattern && value && !new RegExp(validation.pattern).test(value)) {
|
|
8594
|
-
errors.push(validation.patternErrorMessage ||
|
|
8680
|
+
errors.push(validation.patternErrorMessage || translate('Field must match pattern {value}.', {
|
|
8681
|
+
value: validation.pattern
|
|
8682
|
+
}));
|
|
8595
8683
|
}
|
|
8596
8684
|
if (validation.required) {
|
|
8597
8685
|
const isUncheckedCheckbox = field.type === 'checkbox' && value === false;
|
|
8598
8686
|
const isUnsetValue = isNil(value) || value === '';
|
|
8599
8687
|
const isEmptyMultiselect = Array.isArray(value) && value.length === 0;
|
|
8600
8688
|
if (isUncheckedCheckbox || isUnsetValue || isEmptyMultiselect) {
|
|
8601
|
-
errors.push('Field is required.');
|
|
8689
|
+
errors.push(translate('Field is required.'));
|
|
8602
8690
|
}
|
|
8603
8691
|
}
|
|
8692
|
+
|
|
8693
|
+
// stringify: `translate` falls back to the raw placeholder for a falsy replacement, so 0 must not be passed as a number
|
|
8604
8694
|
if ('min' in validation && (value || value === 0)) {
|
|
8605
8695
|
try {
|
|
8606
8696
|
if (Big(value).lt(Big(validation.min))) {
|
|
8607
|
-
errors.push(
|
|
8697
|
+
errors.push(translate('Field must have minimum value of {value}.', {
|
|
8698
|
+
value: validation.min.toString()
|
|
8699
|
+
}));
|
|
8608
8700
|
}
|
|
8609
8701
|
} catch {
|
|
8610
|
-
errors.push('Min validation value is not a valid number.');
|
|
8702
|
+
errors.push(translate('Min validation value is not a valid number.'));
|
|
8611
8703
|
}
|
|
8612
8704
|
}
|
|
8613
8705
|
if ('max' in validation && (value || value === 0)) {
|
|
8614
8706
|
try {
|
|
8615
8707
|
if (Big(value).gt(Big(validation.max))) {
|
|
8616
|
-
errors.push(
|
|
8708
|
+
errors.push(translate('Field must have maximum value of {value}.', {
|
|
8709
|
+
value: validation.max.toString()
|
|
8710
|
+
}));
|
|
8617
8711
|
}
|
|
8618
8712
|
} catch {
|
|
8619
|
-
errors.push('Max validation value is not a valid number.');
|
|
8713
|
+
errors.push(translate('Max validation value is not a valid number.'));
|
|
8620
8714
|
}
|
|
8621
8715
|
}
|
|
8622
8716
|
if ('minLength' in validation && value && value.trim().length < validation.minLength) {
|
|
8623
|
-
errors.push(
|
|
8717
|
+
errors.push(translate('Field must have minimum length of {value}.', {
|
|
8718
|
+
value: validation.minLength.toString()
|
|
8719
|
+
}));
|
|
8624
8720
|
}
|
|
8625
8721
|
if ('maxLength' in validation && value && value.trim().length > validation.maxLength) {
|
|
8626
|
-
errors.push(
|
|
8722
|
+
errors.push(translate('Field must have maximum length of {value}.', {
|
|
8723
|
+
value: validation.maxLength.toString()
|
|
8724
|
+
}));
|
|
8627
8725
|
}
|
|
8628
8726
|
if ('validationType' in validation && value && validation.validationType === 'phone' && !PHONE_PATTERN.test(value)) {
|
|
8629
|
-
errors.push('Field must be a valid
|
|
8727
|
+
errors.push(translate('Field must be a valid international phone number. (e.g. +4930664040900)'));
|
|
8630
8728
|
}
|
|
8631
8729
|
if ('validationType' in validation && value && validation.validationType === 'email' && !EMAIL_PATTERN.test(value)) {
|
|
8632
|
-
errors.push('Field must be a valid email.');
|
|
8730
|
+
errors.push(translate('Field must be a valid email.'));
|
|
8633
8731
|
}
|
|
8634
8732
|
return errors;
|
|
8635
8733
|
}
|
|
@@ -8787,17 +8885,24 @@ class Importer {
|
|
|
8787
8885
|
}
|
|
8788
8886
|
Importer.$inject = ['formFieldRegistry', 'pathRegistry', 'fieldFactory', 'formLayouter'];
|
|
8789
8887
|
|
|
8888
|
+
/**
|
|
8889
|
+
* @typedef { import('diagram-js/lib/i18n/translate/translate').default } Translate
|
|
8890
|
+
*/
|
|
8891
|
+
|
|
8790
8892
|
class FieldFactory {
|
|
8791
8893
|
/**
|
|
8792
8894
|
* @constructor
|
|
8793
8895
|
*
|
|
8794
|
-
* @param
|
|
8795
|
-
* @param
|
|
8896
|
+
* @param formFieldRegistry
|
|
8897
|
+
* @param pathRegistry
|
|
8898
|
+
* @param formFields
|
|
8899
|
+
* @param {Translate} translate
|
|
8796
8900
|
*/
|
|
8797
|
-
constructor(formFieldRegistry, pathRegistry, formFields) {
|
|
8901
|
+
constructor(formFieldRegistry, pathRegistry, formFields, translate) {
|
|
8798
8902
|
this._formFieldRegistry = formFieldRegistry;
|
|
8799
8903
|
this._pathRegistry = pathRegistry;
|
|
8800
8904
|
this._formFields = formFields;
|
|
8905
|
+
this._translate = translate;
|
|
8801
8906
|
}
|
|
8802
8907
|
create(attrs, isNewField = true) {
|
|
8803
8908
|
const {
|
|
@@ -8830,13 +8935,17 @@ class FieldFactory {
|
|
|
8830
8935
|
isClosed: true,
|
|
8831
8936
|
knownAncestorIds
|
|
8832
8937
|
})) {
|
|
8833
|
-
throw new Error(
|
|
8938
|
+
throw new Error(this._translate("binding path '{value}' is already claimed", {
|
|
8939
|
+
value: [...parentPath, key].join('.')
|
|
8940
|
+
}));
|
|
8834
8941
|
}
|
|
8835
8942
|
if (config.pathed && path && !this._pathRegistry.canClaimPath([...parentPath, ...path.split('.')], {
|
|
8836
8943
|
isRepeatable: config.repeatable,
|
|
8837
8944
|
knownAncestorIds
|
|
8838
8945
|
})) {
|
|
8839
|
-
throw new Error(
|
|
8946
|
+
throw new Error(this._translate("binding path '{value}' is already claimed", {
|
|
8947
|
+
value: [...parentPath, ...path.split('.')].join('.')
|
|
8948
|
+
}));
|
|
8840
8949
|
}
|
|
8841
8950
|
const field = config.create({
|
|
8842
8951
|
...(config.label ? {
|
|
@@ -8897,7 +9006,7 @@ class FieldFactory {
|
|
|
8897
9006
|
return `${field.type}_${random}`;
|
|
8898
9007
|
}
|
|
8899
9008
|
}
|
|
8900
|
-
FieldFactory.$inject = ['formFieldRegistry', 'pathRegistry', 'formFields'];
|
|
9009
|
+
FieldFactory.$inject = ['formFieldRegistry', 'pathRegistry', 'formFields', 'translate'];
|
|
8901
9010
|
|
|
8902
9011
|
/**
|
|
8903
9012
|
* The PathRegistry class manages a hierarchical structure of paths associated with form fields.
|
|
@@ -9907,7 +10016,7 @@ class Form {
|
|
|
9907
10016
|
config: ['value', enrichedConfig]
|
|
9908
10017
|
}, {
|
|
9909
10018
|
form: ['value', this]
|
|
9910
|
-
}, CoreModule, ...modules, ...additionalModules]);
|
|
10019
|
+
}, TranslateModule, CoreModule, ...modules, ...additionalModules]);
|
|
9911
10020
|
}
|
|
9912
10021
|
|
|
9913
10022
|
/**
|