@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.cjs
CHANGED
|
@@ -36,6 +36,46 @@ function _interopNamespaceDefault(e) {
|
|
|
36
36
|
|
|
37
37
|
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* @typedef { {
|
|
41
|
+
* [key: string]: string;
|
|
42
|
+
* } } TranslateReplacements
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A simple translation stub to be used for multi-language support
|
|
47
|
+
* in diagrams. Can be easily replaced with a more sophisticated
|
|
48
|
+
* solution.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
*
|
|
52
|
+
* ```javascript
|
|
53
|
+
* // use it inside any diagram component by injecting `translate`.
|
|
54
|
+
*
|
|
55
|
+
* function MyService(translate) {
|
|
56
|
+
* alert(translate('HELLO {you}', { you: 'You!' }));
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @param {string} template to interpolate
|
|
61
|
+
* @param {TranslateReplacements} [replacements] a map with substitutes
|
|
62
|
+
*
|
|
63
|
+
* @return {string} the translated string
|
|
64
|
+
*/
|
|
65
|
+
function translate(template, replacements) {
|
|
66
|
+
replacements = replacements || {};
|
|
67
|
+
return template.replace(/{([^}]+)}/g, function (_, key) {
|
|
68
|
+
return replacements[key] || '{' + key + '}';
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @type { import('didi').ModuleDeclaration }
|
|
74
|
+
*/
|
|
75
|
+
var TranslateModule = {
|
|
76
|
+
translate: ['value', translate]
|
|
77
|
+
};
|
|
78
|
+
|
|
39
79
|
const getFlavouredFeelVariableNames = (feelString, feelFlavour = 'expression', options = {}) => {
|
|
40
80
|
const {
|
|
41
81
|
depth = 0,
|
|
@@ -3067,6 +3107,7 @@ function Datetime(props) {
|
|
|
3067
3107
|
const {
|
|
3068
3108
|
formId
|
|
3069
3109
|
} = hooks.useContext(FormContext);
|
|
3110
|
+
const translate = useService('translate');
|
|
3070
3111
|
|
|
3071
3112
|
/** @type {import("preact").RefObject<HTMLDivElement>} */
|
|
3072
3113
|
const dateTimeGroupRef = hooks.useRef();
|
|
@@ -3157,8 +3198,8 @@ function Datetime(props) {
|
|
|
3157
3198
|
const allErrors = hooks.useMemo(() => {
|
|
3158
3199
|
if (required || subtype !== DATETIME_SUBTYPES.DATETIME) return errors;
|
|
3159
3200
|
const isOnlyOneFieldSet = isValidDate(dateTime.date) && !isValidTime(dateTime.time) || !isValidDate(dateTime.date) && isValidTime(dateTime.time);
|
|
3160
|
-
return isOnlyOneFieldSet ? ['Date and time must both be entered.', ...errors] : errors;
|
|
3161
|
-
}, [required, subtype, dateTime, errors]);
|
|
3201
|
+
return isOnlyOneFieldSet ? [translate('Date and time must both be entered.'), ...errors] : errors;
|
|
3202
|
+
}, [required, subtype, dateTime, errors, translate]);
|
|
3162
3203
|
const setDate = hooks.useCallback(date => {
|
|
3163
3204
|
setDateTimeUpdateRequest(prev => prev ? {
|
|
3164
3205
|
...prev,
|
|
@@ -3320,6 +3361,7 @@ function IFrame(props) {
|
|
|
3320
3361
|
const evaluatedLabel = useSingleLineTemplateEvaluation(label, {
|
|
3321
3362
|
debug: true
|
|
3322
3363
|
});
|
|
3364
|
+
const translate = useService('translate');
|
|
3323
3365
|
const [sandbox, allow] = useSecurityAttributesMap(security);
|
|
3324
3366
|
const [iframeRefresh, setIframeRefresh] = hooks.useState(0);
|
|
3325
3367
|
|
|
@@ -3336,7 +3378,7 @@ function IFrame(props) {
|
|
|
3336
3378
|
htmlFor: domId,
|
|
3337
3379
|
label: evaluatedLabel
|
|
3338
3380
|
}), !evaluatedUrl && jsxRuntime.jsx(IFramePlaceholder, {
|
|
3339
|
-
text:
|
|
3381
|
+
text: translate('No content to show.')
|
|
3340
3382
|
}), evaluatedUrl && safeUrl && jsxRuntime.jsx("iframe", {
|
|
3341
3383
|
src: safeUrl,
|
|
3342
3384
|
title: evaluatedLabel,
|
|
@@ -3346,7 +3388,7 @@ function IFrame(props) {
|
|
|
3346
3388
|
sandbox: sandbox,
|
|
3347
3389
|
allow
|
|
3348
3390
|
}, 'iframe-' + iframeRefresh), evaluatedUrl && !safeUrl && jsxRuntime.jsx(IFramePlaceholder, {
|
|
3349
|
-
text: "External content couldn't be loaded."
|
|
3391
|
+
text: translate("External content couldn't be loaded.")
|
|
3350
3392
|
})]
|
|
3351
3393
|
});
|
|
3352
3394
|
}
|
|
@@ -3934,6 +3976,7 @@ function Numberfield(props) {
|
|
|
3934
3976
|
const {
|
|
3935
3977
|
required
|
|
3936
3978
|
} = validate;
|
|
3979
|
+
const translate = useService('translate');
|
|
3937
3980
|
|
|
3938
3981
|
/** @type {import("preact").RefObject<HTMLInputElement>} */
|
|
3939
3982
|
const inputRef = hooks.useRef();
|
|
@@ -4107,7 +4150,7 @@ function Numberfield(props) {
|
|
|
4107
4150
|
children: [jsxRuntime.jsx("button", {
|
|
4108
4151
|
type: "button",
|
|
4109
4152
|
class: "fjs-number-arrow-up",
|
|
4110
|
-
"aria-label":
|
|
4153
|
+
"aria-label": translate('Increment'),
|
|
4111
4154
|
onClick: () => increment(),
|
|
4112
4155
|
tabIndex: -1,
|
|
4113
4156
|
children: jsxRuntime.jsx(SvgAngelUp, {})
|
|
@@ -4116,7 +4159,7 @@ function Numberfield(props) {
|
|
|
4116
4159
|
}), jsxRuntime.jsx("button", {
|
|
4117
4160
|
type: "button",
|
|
4118
4161
|
class: "fjs-number-arrow-down",
|
|
4119
|
-
"aria-label":
|
|
4162
|
+
"aria-label": translate('Decrement'),
|
|
4120
4163
|
onClick: () => decrement(),
|
|
4121
4164
|
tabIndex: -1,
|
|
4122
4165
|
children: jsxRuntime.jsx(SvgAngelDown, {})
|
|
@@ -4799,6 +4842,7 @@ function Taglist(props) {
|
|
|
4799
4842
|
/** @type {import("preact").RefObject<HTMLInputElement>} */
|
|
4800
4843
|
const inputRef = hooks.useRef();
|
|
4801
4844
|
const eventBus = useService('eventBus');
|
|
4845
|
+
const translate = useService('translate');
|
|
4802
4846
|
const {
|
|
4803
4847
|
loadState,
|
|
4804
4848
|
options
|
|
@@ -4932,7 +4976,7 @@ function Taglist(props) {
|
|
|
4932
4976
|
htmlFor: domId
|
|
4933
4977
|
}), !disabled && !readonly && !!values.length && jsxRuntime.jsx(SkipLink, {
|
|
4934
4978
|
className: "fjs-taglist-skip-link",
|
|
4935
|
-
label:
|
|
4979
|
+
label: translate('Skip to search'),
|
|
4936
4980
|
onSkip: onSkipToSearch
|
|
4937
4981
|
}), jsxRuntime.jsxs("div", {
|
|
4938
4982
|
class: classNames('fjs-taglist', {
|
|
@@ -4953,7 +4997,7 @@ function Taglist(props) {
|
|
|
4953
4997
|
children: getLabelCorrelation(entry)
|
|
4954
4998
|
}), !disabled && !readonly && jsxRuntime.jsx("button", {
|
|
4955
4999
|
type: "button",
|
|
4956
|
-
title:
|
|
5000
|
+
title: translate('Remove tag'),
|
|
4957
5001
|
class: "fjs-taglist-tag-remove",
|
|
4958
5002
|
onFocus: onElementFocus,
|
|
4959
5003
|
onBlur: onElementBlur,
|
|
@@ -4971,7 +5015,7 @@ function Taglist(props) {
|
|
|
4971
5015
|
onChange: onInputChange,
|
|
4972
5016
|
type: "text",
|
|
4973
5017
|
value: filter,
|
|
4974
|
-
placeholder: disabled || readonly ? undefined : 'Search',
|
|
5018
|
+
placeholder: disabled || readonly ? undefined : translate('Search'),
|
|
4975
5019
|
autoComplete: "off",
|
|
4976
5020
|
onKeyDown: onInputKeyDown,
|
|
4977
5021
|
onMouseDown: () => setIsEscapeClose(false),
|
|
@@ -4987,7 +5031,7 @@ function Taglist(props) {
|
|
|
4987
5031
|
values: filteredOptions,
|
|
4988
5032
|
getLabel: option => option.label,
|
|
4989
5033
|
onValueSelected: option => selectValue(option.value),
|
|
4990
|
-
emptyListMessage: hasOptionsLeft ? 'No results' : 'All values selected',
|
|
5034
|
+
emptyListMessage: hasOptionsLeft ? translate('No results') : translate('All values selected'),
|
|
4991
5035
|
listenerElement: inputRef.current
|
|
4992
5036
|
})
|
|
4993
5037
|
}), jsxRuntime.jsx(Description, {
|
|
@@ -5590,6 +5634,8 @@ var SvgCaretRight = function SvgCaretRight(props) {
|
|
|
5590
5634
|
const type$2 = 'table';
|
|
5591
5635
|
|
|
5592
5636
|
/**
|
|
5637
|
+
* @typedef { import('diagram-js/lib/i18n/translate/translate').default } Translate
|
|
5638
|
+
*
|
|
5593
5639
|
* @typedef {('asc'|'desc')} Direction
|
|
5594
5640
|
*
|
|
5595
5641
|
* @typedef Sorting
|
|
@@ -5639,6 +5685,7 @@ function Table(props) {
|
|
|
5639
5685
|
const chunkedData = minDash.isNumber(rowCount) ? chunk(sortedData, rowCount) : [sortedData];
|
|
5640
5686
|
const [currentPage, setCurrentPage] = hooks.useState(0);
|
|
5641
5687
|
const currentChunk = chunkedData[currentPage] || [];
|
|
5688
|
+
const translate = useService('translate');
|
|
5642
5689
|
hooks.useEffect(() => {
|
|
5643
5690
|
setCurrentPage(0);
|
|
5644
5691
|
}, [rowCount, sortBy]);
|
|
@@ -5670,7 +5717,7 @@ function Table(props) {
|
|
|
5670
5717
|
class: classNames('fjs-table-middle-container', {
|
|
5671
5718
|
'fjs-table-empty': evaluatedColumns.length === 0
|
|
5672
5719
|
}),
|
|
5673
|
-
children: [evaluatedColumns.length === 0 ? 'Nothing to show.' : jsxRuntime.jsx("div", {
|
|
5720
|
+
children: [evaluatedColumns.length === 0 ? translate('Nothing to show.') : jsxRuntime.jsx("div", {
|
|
5674
5721
|
class: "fjs-table-inner-container",
|
|
5675
5722
|
children: jsxRuntime.jsxs("table", {
|
|
5676
5723
|
class: "fjs-table",
|
|
@@ -5695,7 +5742,7 @@ function Table(props) {
|
|
|
5695
5742
|
toggleSortBy(key);
|
|
5696
5743
|
}
|
|
5697
5744
|
},
|
|
5698
|
-
"aria-label": getHeaderAriaLabel(sortBy, key, displayLabel),
|
|
5745
|
+
"aria-label": getHeaderAriaLabel(sortBy, key, displayLabel, translate),
|
|
5699
5746
|
children: jsxRuntime.jsxs("span", {
|
|
5700
5747
|
class: "fjs-table-th-label",
|
|
5701
5748
|
children: [displayLabel, sortBy !== null && sortBy.key === key ? jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
@@ -5716,7 +5763,7 @@ function Table(props) {
|
|
|
5716
5763
|
children: jsxRuntime.jsx("td", {
|
|
5717
5764
|
class: "fjs-table-td",
|
|
5718
5765
|
colSpan: evaluatedColumns.length,
|
|
5719
|
-
children:
|
|
5766
|
+
children: translate('Nothing to show.')
|
|
5720
5767
|
})
|
|
5721
5768
|
})
|
|
5722
5769
|
}) : jsxRuntime.jsx("tbody", {
|
|
@@ -5732,9 +5779,13 @@ function Table(props) {
|
|
|
5732
5779
|
})
|
|
5733
5780
|
}), minDash.isNumber(rowCount) && chunkedData.length > 1 && evaluatedColumns.length > 0 ? jsxRuntime.jsxs("nav", {
|
|
5734
5781
|
class: "fjs-table-nav",
|
|
5735
|
-
children: [jsxRuntime.
|
|
5782
|
+
children: [jsxRuntime.jsx("span", {
|
|
5736
5783
|
class: "fjs-table-nav-label",
|
|
5737
|
-
children:
|
|
5784
|
+
children: translate('{page} of {total}', {
|
|
5785
|
+
// stringify: see Validator.js
|
|
5786
|
+
page: (currentPage + 1).toString(),
|
|
5787
|
+
total: chunkedData.length.toString()
|
|
5788
|
+
})
|
|
5738
5789
|
}), jsxRuntime.jsx("button", {
|
|
5739
5790
|
type: "button",
|
|
5740
5791
|
class: "fjs-table-nav-button",
|
|
@@ -5742,7 +5793,7 @@ function Table(props) {
|
|
|
5742
5793
|
setCurrentPage(page => Math.max(page - 1, 0));
|
|
5743
5794
|
},
|
|
5744
5795
|
disabled: currentPage === 0,
|
|
5745
|
-
"aria-label":
|
|
5796
|
+
"aria-label": translate('Previous page'),
|
|
5746
5797
|
children: jsxRuntime.jsx(SvgCaretLeft, {})
|
|
5747
5798
|
}), jsxRuntime.jsx("button", {
|
|
5748
5799
|
type: "button",
|
|
@@ -5751,7 +5802,7 @@ function Table(props) {
|
|
|
5751
5802
|
setCurrentPage(page => Math.min(page + 1, chunkedData.length - 1));
|
|
5752
5803
|
},
|
|
5753
5804
|
disabled: currentPage >= chunkedData.length - 1,
|
|
5754
|
-
"aria-label":
|
|
5805
|
+
"aria-label": translate('Next page'),
|
|
5755
5806
|
children: jsxRuntime.jsx(SvgCaretRight, {})
|
|
5756
5807
|
})]
|
|
5757
5808
|
}) : null]
|
|
@@ -5901,15 +5952,20 @@ function sortByColumn(array, key, direction) {
|
|
|
5901
5952
|
* @param {null|Sorting} sortBy
|
|
5902
5953
|
* @param {string} key
|
|
5903
5954
|
* @param {string} label
|
|
5955
|
+
* @param {Translate} translate
|
|
5904
5956
|
*/
|
|
5905
|
-
function getHeaderAriaLabel(sortBy, key, label) {
|
|
5957
|
+
function getHeaderAriaLabel(sortBy, key, label, translate) {
|
|
5906
5958
|
if (sortBy === null || sortBy.key !== key) {
|
|
5907
|
-
return
|
|
5959
|
+
return translate('Click to sort by {value} descending', {
|
|
5960
|
+
value: label
|
|
5961
|
+
});
|
|
5908
5962
|
}
|
|
5909
5963
|
if (sortBy.direction === 'asc') {
|
|
5910
|
-
return 'Click to remove sorting';
|
|
5964
|
+
return translate('Click to remove sorting');
|
|
5911
5965
|
}
|
|
5912
|
-
return
|
|
5966
|
+
return translate('Click to sort by {value} ascending', {
|
|
5967
|
+
value: label
|
|
5968
|
+
});
|
|
5913
5969
|
}
|
|
5914
5970
|
|
|
5915
5971
|
/**
|
|
@@ -5980,6 +6036,7 @@ function FilePicker(props) {
|
|
|
5980
6036
|
const errorMessageId = `${domId}-error-message`;
|
|
5981
6037
|
/** @type {File[]} */
|
|
5982
6038
|
const selectedFiles = fileRegistry === null ? EMPTY_ARRAY$1 : fileRegistry.getFiles(filesKey);
|
|
6039
|
+
const translate = useService('translate');
|
|
5983
6040
|
hooks.useEffect(() => {
|
|
5984
6041
|
if (filesKey && fileRegistry !== null && !fileRegistry.hasKey(filesKey)) {
|
|
5985
6042
|
onChange({
|
|
@@ -6050,7 +6107,7 @@ function FilePicker(props) {
|
|
|
6050
6107
|
children: "Browse"
|
|
6051
6108
|
}), jsxRuntime.jsx("span", {
|
|
6052
6109
|
className: "fjs-form-field-label",
|
|
6053
|
-
children: getSelectedFilesLabel(selectedFiles)
|
|
6110
|
+
children: getSelectedFilesLabel(selectedFiles, translate)
|
|
6054
6111
|
})]
|
|
6055
6112
|
}), jsxRuntime.jsx(Errors, {
|
|
6056
6113
|
id: errorMessageId,
|
|
@@ -6073,16 +6130,19 @@ FilePicker.config = {
|
|
|
6073
6130
|
|
|
6074
6131
|
/**
|
|
6075
6132
|
* @param {File[]} files
|
|
6133
|
+
* @param {Translate} translate
|
|
6076
6134
|
* @returns {string}
|
|
6077
6135
|
*/
|
|
6078
|
-
function getSelectedFilesLabel(files) {
|
|
6136
|
+
function getSelectedFilesLabel(files, translate) {
|
|
6079
6137
|
if (files.length === 0) {
|
|
6080
|
-
return 'No files selected';
|
|
6138
|
+
return translate('No files selected');
|
|
6081
6139
|
}
|
|
6082
6140
|
if (files.length === 1) {
|
|
6083
6141
|
return files[0].name;
|
|
6084
6142
|
}
|
|
6085
|
-
return
|
|
6143
|
+
return translate('{value} files selected', {
|
|
6144
|
+
value: files.length.toString()
|
|
6145
|
+
});
|
|
6086
6146
|
}
|
|
6087
6147
|
|
|
6088
6148
|
var _path$4;
|
|
@@ -6105,6 +6165,10 @@ var SvgDownload = function SvgDownload(props) {
|
|
|
6105
6165
|
|
|
6106
6166
|
const type = 'documentPreview';
|
|
6107
6167
|
|
|
6168
|
+
/**
|
|
6169
|
+
* @typedef { import('diagram-js/lib/i18n/translate/translate').default } Translate
|
|
6170
|
+
*/
|
|
6171
|
+
|
|
6108
6172
|
/**
|
|
6109
6173
|
* @typedef DocumentEndpointBuilder
|
|
6110
6174
|
* @property {(document: DocumentMetadata) => string} [buildUrl]
|
|
@@ -6150,6 +6214,7 @@ function DocumentPreview(props) {
|
|
|
6150
6214
|
const evaluatedLabel = useSingleLineTemplateEvaluation(label, {
|
|
6151
6215
|
debug: true
|
|
6152
6216
|
});
|
|
6217
|
+
const translate = useService('translate');
|
|
6153
6218
|
return jsxRuntime.jsxs("div", {
|
|
6154
6219
|
class: formFieldClasses(type),
|
|
6155
6220
|
children: [jsxRuntime.jsx(Label, {
|
|
@@ -6175,7 +6240,7 @@ function DocumentPreview(props) {
|
|
|
6175
6240
|
id: errorMessageId,
|
|
6176
6241
|
errors: getErrors({
|
|
6177
6242
|
dataSource
|
|
6178
|
-
})
|
|
6243
|
+
}, translate)
|
|
6179
6244
|
})]
|
|
6180
6245
|
});
|
|
6181
6246
|
}
|
|
@@ -6197,15 +6262,16 @@ DocumentPreview.config = {
|
|
|
6197
6262
|
* @property {string|undefined} dataSource
|
|
6198
6263
|
*
|
|
6199
6264
|
* @param {GetErrorOptions} options
|
|
6265
|
+
* @param {Translate} translate
|
|
6200
6266
|
* @returns {string[]}
|
|
6201
6267
|
*/
|
|
6202
|
-
function getErrors(options) {
|
|
6268
|
+
function getErrors(options, translate) {
|
|
6203
6269
|
const {
|
|
6204
6270
|
dataSource
|
|
6205
6271
|
} = options;
|
|
6206
6272
|
let errors = [];
|
|
6207
6273
|
if (!minDash.isString(dataSource) || dataSource.length < 1) {
|
|
6208
|
-
errors.push('Document reference is not defined.');
|
|
6274
|
+
errors.push(translate('Document reference is not defined.'));
|
|
6209
6275
|
}
|
|
6210
6276
|
return errors;
|
|
6211
6277
|
}
|
|
@@ -6258,6 +6324,7 @@ function PdfRenderer(props) {
|
|
|
6258
6324
|
/** @type {ReturnType<typeof import("preact/hooks").useState<null | string>>} */
|
|
6259
6325
|
const [pdfObjectUrl, setPdfObjectUrl] = hooks.useState(null);
|
|
6260
6326
|
const [hasError, setHasError] = hooks.useState(false);
|
|
6327
|
+
const translate = useService('translate');
|
|
6261
6328
|
hooks.useEffect(() => {
|
|
6262
6329
|
/** @type {null | string} */
|
|
6263
6330
|
let objectUrl = null;
|
|
@@ -6291,7 +6358,7 @@ function PdfRenderer(props) {
|
|
|
6291
6358
|
class: `fjs-${type}-pdf-viewer`
|
|
6292
6359
|
}) : null, hasError ? jsxRuntime.jsx(Errors, {
|
|
6293
6360
|
id: errorMessageId,
|
|
6294
|
-
errors: ['Unable to download document']
|
|
6361
|
+
errors: [translate('Unable to download document')]
|
|
6295
6362
|
}) : null]
|
|
6296
6363
|
});
|
|
6297
6364
|
}
|
|
@@ -6371,9 +6438,10 @@ function DocumentRenderer(props) {
|
|
|
6371
6438
|
const isInViewport = useInViewport(ref);
|
|
6372
6439
|
const onError = hooks.useCallback(() => setHasError(true), []);
|
|
6373
6440
|
const requestInit = hooks.useMemo(() => getDocumentRequestInit(documentEndpointBuilder, documentMetadata), [documentEndpointBuilder, documentMetadata]);
|
|
6441
|
+
const translate = useService('translate');
|
|
6374
6442
|
const singleDocumentContainerClassName = `fjs-${type}-single-document-container`;
|
|
6375
6443
|
const errorMessageId = `${domId}-error-message`;
|
|
6376
|
-
const errorMessage = 'Unable to download document';
|
|
6444
|
+
const errorMessage = translate('Unable to download document');
|
|
6377
6445
|
const isContentTypePresent = typeof metadata.contentType === 'string';
|
|
6378
6446
|
if (isContentTypePresent && metadata.contentType.toLowerCase().startsWith('image/') && isInViewport) {
|
|
6379
6447
|
return jsxRuntime.jsxs("div", {
|
|
@@ -6451,6 +6519,7 @@ function DownloadButton(props) {
|
|
|
6451
6519
|
onDownloadError,
|
|
6452
6520
|
requestInit
|
|
6453
6521
|
} = props;
|
|
6522
|
+
const translate = useService('translate');
|
|
6454
6523
|
const handleDownload = async () => {
|
|
6455
6524
|
try {
|
|
6456
6525
|
const response = await fetch(endpoint, requestInit);
|
|
@@ -6473,7 +6542,9 @@ function DownloadButton(props) {
|
|
|
6473
6542
|
type: "button",
|
|
6474
6543
|
onClick: handleDownload,
|
|
6475
6544
|
class: classNames(`fjs-${type}-download-button`),
|
|
6476
|
-
"aria-label":
|
|
6545
|
+
"aria-label": translate('Download {fileName}', {
|
|
6546
|
+
fileName
|
|
6547
|
+
}),
|
|
6477
6548
|
children: jsxRuntime.jsx(SvgDownload, {})
|
|
6478
6549
|
});
|
|
6479
6550
|
}
|
|
@@ -7819,6 +7890,7 @@ class RepeatRenderManager {
|
|
|
7819
7890
|
const {
|
|
7820
7891
|
data
|
|
7821
7892
|
} = this._form._getState();
|
|
7893
|
+
const translate = useService('translate');
|
|
7822
7894
|
const dataPath = this._pathRegistry.getValuePath(repeaterField, {
|
|
7823
7895
|
indexes
|
|
7824
7896
|
});
|
|
@@ -7875,16 +7947,18 @@ class RepeatRenderManager {
|
|
|
7875
7947
|
ref: addButtonRef,
|
|
7876
7948
|
onClick: onAddItem,
|
|
7877
7949
|
children: jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
7878
|
-
children: [jsxRuntime.jsx(SvgAdd, {}), " ", 'Add new']
|
|
7950
|
+
children: [jsxRuntime.jsx(SvgAdd, {}), " ", translate('Add new')]
|
|
7879
7951
|
})
|
|
7880
7952
|
}) : null, collapseEnabled ? jsxRuntime.jsx("button", {
|
|
7881
7953
|
type: "button",
|
|
7882
7954
|
class: "fjs-repeat-render-collapse",
|
|
7883
7955
|
onClick: toggle,
|
|
7884
7956
|
children: isCollapsed ? jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
7885
|
-
children: [jsxRuntime.jsx(SvgExpand, {}), " ",
|
|
7957
|
+
children: [jsxRuntime.jsx(SvgExpand, {}), " ", translate('Expand all ({value})', {
|
|
7958
|
+
value: values.length - 1
|
|
7959
|
+
})]
|
|
7886
7960
|
}) : jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
7887
|
-
children: [jsxRuntime.jsx(SvgCollapse, {}), " ", 'Collapse']
|
|
7961
|
+
children: [jsxRuntime.jsx(SvgCollapse, {}), " ", translate('Collapse')]
|
|
7888
7962
|
})
|
|
7889
7963
|
}) : null]
|
|
7890
7964
|
});
|
|
@@ -8517,11 +8591,12 @@ const EMAIL_PATTERN = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-
|
|
|
8517
8591
|
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}$/;
|
|
8518
8592
|
const VALIDATE_FEEL_PROPERTIES = ['min', 'max', 'minLength', 'maxLength'];
|
|
8519
8593
|
class Validator {
|
|
8520
|
-
constructor(expressionLanguage, conditionChecker, form, formFieldRegistry) {
|
|
8594
|
+
constructor(expressionLanguage, conditionChecker, form, formFieldRegistry, translate) {
|
|
8521
8595
|
this._expressionLanguage = expressionLanguage;
|
|
8522
8596
|
this._conditionChecker = conditionChecker;
|
|
8523
8597
|
this._form = form;
|
|
8524
8598
|
this._formFieldRegistry = formFieldRegistry;
|
|
8599
|
+
this._translate = translate;
|
|
8525
8600
|
}
|
|
8526
8601
|
|
|
8527
8602
|
/**
|
|
@@ -8536,13 +8611,13 @@ class Validator {
|
|
|
8536
8611
|
} = field;
|
|
8537
8612
|
let errors = [];
|
|
8538
8613
|
if (type === 'number') {
|
|
8539
|
-
errors = [...errors, ...runNumberValidation(field, value)];
|
|
8614
|
+
errors = [...errors, ...runNumberValidation(field, value, this._translate)];
|
|
8540
8615
|
}
|
|
8541
8616
|
if (!validate) {
|
|
8542
8617
|
return errors;
|
|
8543
8618
|
}
|
|
8544
8619
|
const evaluatedValidation = oldEvaluateFEELValues(validate, this._expressionLanguage, this._conditionChecker, this._form);
|
|
8545
|
-
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value)];
|
|
8620
|
+
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value, this._translate)];
|
|
8546
8621
|
return errors;
|
|
8547
8622
|
}
|
|
8548
8623
|
|
|
@@ -8569,31 +8644,39 @@ class Validator {
|
|
|
8569
8644
|
} = field;
|
|
8570
8645
|
let errors = [];
|
|
8571
8646
|
if (type === 'number') {
|
|
8572
|
-
errors = [...errors, ...runNumberValidation(field, value)];
|
|
8647
|
+
errors = [...errors, ...runNumberValidation(field, value, this._translate)];
|
|
8573
8648
|
}
|
|
8574
8649
|
if (!validate) {
|
|
8575
8650
|
return errors;
|
|
8576
8651
|
}
|
|
8577
8652
|
const evaluatedValidation = evaluateFEELValues(validate, this._expressionLanguage, expressionContextInfo);
|
|
8578
|
-
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value)];
|
|
8653
|
+
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value, this._translate)];
|
|
8579
8654
|
return errors;
|
|
8580
8655
|
}
|
|
8581
8656
|
}
|
|
8582
|
-
Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form', 'formFieldRegistry'];
|
|
8657
|
+
Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form', 'formFieldRegistry', 'translate'];
|
|
8583
8658
|
|
|
8584
8659
|
// helpers //////////
|
|
8585
8660
|
|
|
8586
|
-
function runNumberValidation(field, value) {
|
|
8661
|
+
function runNumberValidation(field, value, translate) {
|
|
8587
8662
|
const {
|
|
8588
8663
|
decimalDigits,
|
|
8589
8664
|
increment
|
|
8590
8665
|
} = field;
|
|
8591
8666
|
const errors = [];
|
|
8592
8667
|
if (value === 'NaN') {
|
|
8593
|
-
errors.push('Value is not a number.');
|
|
8668
|
+
errors.push(translate('Value is not a number.'));
|
|
8594
8669
|
} else if (value) {
|
|
8595
8670
|
if (decimalDigits >= 0 && countDecimals(value) > decimalDigits) {
|
|
8596
|
-
|
|
8671
|
+
if (decimalDigits === 0) {
|
|
8672
|
+
errors.push(translate('Value is expected to be an integer.'));
|
|
8673
|
+
} else if (decimalDigits === 1) {
|
|
8674
|
+
errors.push(translate('Value is expected to have at most 1 decimal digit.'));
|
|
8675
|
+
} else {
|
|
8676
|
+
errors.push(translate('Value is expected to have at most {value} decimal digits.', {
|
|
8677
|
+
value: decimalDigits.toString()
|
|
8678
|
+
}));
|
|
8679
|
+
}
|
|
8597
8680
|
}
|
|
8598
8681
|
if (increment) {
|
|
8599
8682
|
const bigValue = Big(value);
|
|
@@ -8602,54 +8685,69 @@ function runNumberValidation(field, value) {
|
|
|
8602
8685
|
if (offset.cmp(0) !== 0) {
|
|
8603
8686
|
const previousValue = bigValue.minus(offset);
|
|
8604
8687
|
const nextValue = previousValue.plus(bigIncrement);
|
|
8605
|
-
errors.push(
|
|
8688
|
+
errors.push(translate('Please select a valid value, the two nearest valid values are {previousValue} and {nextValue}.', {
|
|
8689
|
+
previousValue: previousValue,
|
|
8690
|
+
nextValue: nextValue
|
|
8691
|
+
}));
|
|
8606
8692
|
}
|
|
8607
8693
|
}
|
|
8608
8694
|
}
|
|
8609
8695
|
return errors;
|
|
8610
8696
|
}
|
|
8611
|
-
function runPresetValidation(field, validation, value) {
|
|
8697
|
+
function runPresetValidation(field, validation, value, translate) {
|
|
8612
8698
|
const errors = [];
|
|
8613
8699
|
if (validation.pattern && value && !new RegExp(validation.pattern).test(value)) {
|
|
8614
|
-
errors.push(validation.patternErrorMessage ||
|
|
8700
|
+
errors.push(validation.patternErrorMessage || translate('Field must match pattern {value}.', {
|
|
8701
|
+
value: validation.pattern
|
|
8702
|
+
}));
|
|
8615
8703
|
}
|
|
8616
8704
|
if (validation.required) {
|
|
8617
8705
|
const isUncheckedCheckbox = field.type === 'checkbox' && value === false;
|
|
8618
8706
|
const isUnsetValue = minDash.isNil(value) || value === '';
|
|
8619
8707
|
const isEmptyMultiselect = Array.isArray(value) && value.length === 0;
|
|
8620
8708
|
if (isUncheckedCheckbox || isUnsetValue || isEmptyMultiselect) {
|
|
8621
|
-
errors.push('Field is required.');
|
|
8709
|
+
errors.push(translate('Field is required.'));
|
|
8622
8710
|
}
|
|
8623
8711
|
}
|
|
8712
|
+
|
|
8713
|
+
// stringify: `translate` falls back to the raw placeholder for a falsy replacement, so 0 must not be passed as a number
|
|
8624
8714
|
if ('min' in validation && (value || value === 0)) {
|
|
8625
8715
|
try {
|
|
8626
8716
|
if (Big(value).lt(Big(validation.min))) {
|
|
8627
|
-
errors.push(
|
|
8717
|
+
errors.push(translate('Field must have minimum value of {value}.', {
|
|
8718
|
+
value: validation.min.toString()
|
|
8719
|
+
}));
|
|
8628
8720
|
}
|
|
8629
8721
|
} catch {
|
|
8630
|
-
errors.push('Min validation value is not a valid number.');
|
|
8722
|
+
errors.push(translate('Min validation value is not a valid number.'));
|
|
8631
8723
|
}
|
|
8632
8724
|
}
|
|
8633
8725
|
if ('max' in validation && (value || value === 0)) {
|
|
8634
8726
|
try {
|
|
8635
8727
|
if (Big(value).gt(Big(validation.max))) {
|
|
8636
|
-
errors.push(
|
|
8728
|
+
errors.push(translate('Field must have maximum value of {value}.', {
|
|
8729
|
+
value: validation.max.toString()
|
|
8730
|
+
}));
|
|
8637
8731
|
}
|
|
8638
8732
|
} catch {
|
|
8639
|
-
errors.push('Max validation value is not a valid number.');
|
|
8733
|
+
errors.push(translate('Max validation value is not a valid number.'));
|
|
8640
8734
|
}
|
|
8641
8735
|
}
|
|
8642
8736
|
if ('minLength' in validation && value && value.trim().length < validation.minLength) {
|
|
8643
|
-
errors.push(
|
|
8737
|
+
errors.push(translate('Field must have minimum length of {value}.', {
|
|
8738
|
+
value: validation.minLength.toString()
|
|
8739
|
+
}));
|
|
8644
8740
|
}
|
|
8645
8741
|
if ('maxLength' in validation && value && value.trim().length > validation.maxLength) {
|
|
8646
|
-
errors.push(
|
|
8742
|
+
errors.push(translate('Field must have maximum length of {value}.', {
|
|
8743
|
+
value: validation.maxLength.toString()
|
|
8744
|
+
}));
|
|
8647
8745
|
}
|
|
8648
8746
|
if ('validationType' in validation && value && validation.validationType === 'phone' && !PHONE_PATTERN.test(value)) {
|
|
8649
|
-
errors.push('Field must be a valid
|
|
8747
|
+
errors.push(translate('Field must be a valid international phone number. (e.g. +4930664040900)'));
|
|
8650
8748
|
}
|
|
8651
8749
|
if ('validationType' in validation && value && validation.validationType === 'email' && !EMAIL_PATTERN.test(value)) {
|
|
8652
|
-
errors.push('Field must be a valid email.');
|
|
8750
|
+
errors.push(translate('Field must be a valid email.'));
|
|
8653
8751
|
}
|
|
8654
8752
|
return errors;
|
|
8655
8753
|
}
|
|
@@ -8807,17 +8905,24 @@ class Importer {
|
|
|
8807
8905
|
}
|
|
8808
8906
|
Importer.$inject = ['formFieldRegistry', 'pathRegistry', 'fieldFactory', 'formLayouter'];
|
|
8809
8907
|
|
|
8908
|
+
/**
|
|
8909
|
+
* @typedef { import('diagram-js/lib/i18n/translate/translate').default } Translate
|
|
8910
|
+
*/
|
|
8911
|
+
|
|
8810
8912
|
class FieldFactory {
|
|
8811
8913
|
/**
|
|
8812
8914
|
* @constructor
|
|
8813
8915
|
*
|
|
8814
|
-
* @param
|
|
8815
|
-
* @param
|
|
8916
|
+
* @param formFieldRegistry
|
|
8917
|
+
* @param pathRegistry
|
|
8918
|
+
* @param formFields
|
|
8919
|
+
* @param {Translate} translate
|
|
8816
8920
|
*/
|
|
8817
|
-
constructor(formFieldRegistry, pathRegistry, formFields) {
|
|
8921
|
+
constructor(formFieldRegistry, pathRegistry, formFields, translate) {
|
|
8818
8922
|
this._formFieldRegistry = formFieldRegistry;
|
|
8819
8923
|
this._pathRegistry = pathRegistry;
|
|
8820
8924
|
this._formFields = formFields;
|
|
8925
|
+
this._translate = translate;
|
|
8821
8926
|
}
|
|
8822
8927
|
create(attrs, isNewField = true) {
|
|
8823
8928
|
const {
|
|
@@ -8850,13 +8955,17 @@ class FieldFactory {
|
|
|
8850
8955
|
isClosed: true,
|
|
8851
8956
|
knownAncestorIds
|
|
8852
8957
|
})) {
|
|
8853
|
-
throw new Error(
|
|
8958
|
+
throw new Error(this._translate("binding path '{value}' is already claimed", {
|
|
8959
|
+
value: [...parentPath, key].join('.')
|
|
8960
|
+
}));
|
|
8854
8961
|
}
|
|
8855
8962
|
if (config.pathed && path && !this._pathRegistry.canClaimPath([...parentPath, ...path.split('.')], {
|
|
8856
8963
|
isRepeatable: config.repeatable,
|
|
8857
8964
|
knownAncestorIds
|
|
8858
8965
|
})) {
|
|
8859
|
-
throw new Error(
|
|
8966
|
+
throw new Error(this._translate("binding path '{value}' is already claimed", {
|
|
8967
|
+
value: [...parentPath, ...path.split('.')].join('.')
|
|
8968
|
+
}));
|
|
8860
8969
|
}
|
|
8861
8970
|
const field = config.create({
|
|
8862
8971
|
...(config.label ? {
|
|
@@ -8917,7 +9026,7 @@ class FieldFactory {
|
|
|
8917
9026
|
return `${field.type}_${random}`;
|
|
8918
9027
|
}
|
|
8919
9028
|
}
|
|
8920
|
-
FieldFactory.$inject = ['formFieldRegistry', 'pathRegistry', 'formFields'];
|
|
9029
|
+
FieldFactory.$inject = ['formFieldRegistry', 'pathRegistry', 'formFields', 'translate'];
|
|
8921
9030
|
|
|
8922
9031
|
/**
|
|
8923
9032
|
* The PathRegistry class manages a hierarchical structure of paths associated with form fields.
|
|
@@ -9927,7 +10036,7 @@ class Form {
|
|
|
9927
10036
|
config: ['value', enrichedConfig]
|
|
9928
10037
|
}, {
|
|
9929
10038
|
form: ['value', this]
|
|
9930
|
-
}, CoreModule, ...modules, ...additionalModules]);
|
|
10039
|
+
}, TranslateModule, CoreModule, ...modules, ...additionalModules]);
|
|
9931
10040
|
}
|
|
9932
10041
|
|
|
9933
10042
|
/**
|