@bpmn-io/form-js-viewer 1.25.0 → 1.26.1
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 +178 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +178 -63
- 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;
|
|
@@ -6269,7 +6336,13 @@ function PdfRenderer(props) {
|
|
|
6269
6336
|
onError();
|
|
6270
6337
|
return;
|
|
6271
6338
|
}
|
|
6272
|
-
|
|
6339
|
+
|
|
6340
|
+
// Re-type the response instead of trusting its content type. An object URL
|
|
6341
|
+
// inherits the form's origin and <embed> renders it by the blob's own type,
|
|
6342
|
+
// so a response served as HTML would execute script in that origin.
|
|
6343
|
+
const blob = new Blob([await response.arrayBuffer()], {
|
|
6344
|
+
type: 'application/pdf'
|
|
6345
|
+
});
|
|
6273
6346
|
objectUrl = URL.createObjectURL(blob);
|
|
6274
6347
|
setPdfObjectUrl(objectUrl);
|
|
6275
6348
|
} catch {
|
|
@@ -6291,7 +6364,7 @@ function PdfRenderer(props) {
|
|
|
6291
6364
|
class: `fjs-${type}-pdf-viewer`
|
|
6292
6365
|
}) : null, hasError ? jsxRuntime.jsx(Errors, {
|
|
6293
6366
|
id: errorMessageId,
|
|
6294
|
-
errors: ['Unable to download document']
|
|
6367
|
+
errors: [translate('Unable to download document')]
|
|
6295
6368
|
}) : null]
|
|
6296
6369
|
});
|
|
6297
6370
|
}
|
|
@@ -6371,9 +6444,10 @@ function DocumentRenderer(props) {
|
|
|
6371
6444
|
const isInViewport = useInViewport(ref);
|
|
6372
6445
|
const onError = hooks.useCallback(() => setHasError(true), []);
|
|
6373
6446
|
const requestInit = hooks.useMemo(() => getDocumentRequestInit(documentEndpointBuilder, documentMetadata), [documentEndpointBuilder, documentMetadata]);
|
|
6447
|
+
const translate = useService('translate');
|
|
6374
6448
|
const singleDocumentContainerClassName = `fjs-${type}-single-document-container`;
|
|
6375
6449
|
const errorMessageId = `${domId}-error-message`;
|
|
6376
|
-
const errorMessage = 'Unable to download document';
|
|
6450
|
+
const errorMessage = translate('Unable to download document');
|
|
6377
6451
|
const isContentTypePresent = typeof metadata.contentType === 'string';
|
|
6378
6452
|
if (isContentTypePresent && metadata.contentType.toLowerCase().startsWith('image/') && isInViewport) {
|
|
6379
6453
|
return jsxRuntime.jsxs("div", {
|
|
@@ -6451,6 +6525,7 @@ function DownloadButton(props) {
|
|
|
6451
6525
|
onDownloadError,
|
|
6452
6526
|
requestInit
|
|
6453
6527
|
} = props;
|
|
6528
|
+
const translate = useService('translate');
|
|
6454
6529
|
const handleDownload = async () => {
|
|
6455
6530
|
try {
|
|
6456
6531
|
const response = await fetch(endpoint, requestInit);
|
|
@@ -6473,7 +6548,9 @@ function DownloadButton(props) {
|
|
|
6473
6548
|
type: "button",
|
|
6474
6549
|
onClick: handleDownload,
|
|
6475
6550
|
class: classNames(`fjs-${type}-download-button`),
|
|
6476
|
-
"aria-label":
|
|
6551
|
+
"aria-label": translate('Download {fileName}', {
|
|
6552
|
+
fileName
|
|
6553
|
+
}),
|
|
6477
6554
|
children: jsxRuntime.jsx(SvgDownload, {})
|
|
6478
6555
|
});
|
|
6479
6556
|
}
|
|
@@ -7819,6 +7896,7 @@ class RepeatRenderManager {
|
|
|
7819
7896
|
const {
|
|
7820
7897
|
data
|
|
7821
7898
|
} = this._form._getState();
|
|
7899
|
+
const translate = useService('translate');
|
|
7822
7900
|
const dataPath = this._pathRegistry.getValuePath(repeaterField, {
|
|
7823
7901
|
indexes
|
|
7824
7902
|
});
|
|
@@ -7875,16 +7953,18 @@ class RepeatRenderManager {
|
|
|
7875
7953
|
ref: addButtonRef,
|
|
7876
7954
|
onClick: onAddItem,
|
|
7877
7955
|
children: jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
7878
|
-
children: [jsxRuntime.jsx(SvgAdd, {}), " ", 'Add new']
|
|
7956
|
+
children: [jsxRuntime.jsx(SvgAdd, {}), " ", translate('Add new')]
|
|
7879
7957
|
})
|
|
7880
7958
|
}) : null, collapseEnabled ? jsxRuntime.jsx("button", {
|
|
7881
7959
|
type: "button",
|
|
7882
7960
|
class: "fjs-repeat-render-collapse",
|
|
7883
7961
|
onClick: toggle,
|
|
7884
7962
|
children: isCollapsed ? jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
7885
|
-
children: [jsxRuntime.jsx(SvgExpand, {}), " ",
|
|
7963
|
+
children: [jsxRuntime.jsx(SvgExpand, {}), " ", translate('Expand all ({value})', {
|
|
7964
|
+
value: values.length - 1
|
|
7965
|
+
})]
|
|
7886
7966
|
}) : jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
7887
|
-
children: [jsxRuntime.jsx(SvgCollapse, {}), " ", 'Collapse']
|
|
7967
|
+
children: [jsxRuntime.jsx(SvgCollapse, {}), " ", translate('Collapse')]
|
|
7888
7968
|
})
|
|
7889
7969
|
}) : null]
|
|
7890
7970
|
});
|
|
@@ -8517,11 +8597,12 @@ const EMAIL_PATTERN = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-
|
|
|
8517
8597
|
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
8598
|
const VALIDATE_FEEL_PROPERTIES = ['min', 'max', 'minLength', 'maxLength'];
|
|
8519
8599
|
class Validator {
|
|
8520
|
-
constructor(expressionLanguage, conditionChecker, form, formFieldRegistry) {
|
|
8600
|
+
constructor(expressionLanguage, conditionChecker, form, formFieldRegistry, translate) {
|
|
8521
8601
|
this._expressionLanguage = expressionLanguage;
|
|
8522
8602
|
this._conditionChecker = conditionChecker;
|
|
8523
8603
|
this._form = form;
|
|
8524
8604
|
this._formFieldRegistry = formFieldRegistry;
|
|
8605
|
+
this._translate = translate;
|
|
8525
8606
|
}
|
|
8526
8607
|
|
|
8527
8608
|
/**
|
|
@@ -8536,13 +8617,13 @@ class Validator {
|
|
|
8536
8617
|
} = field;
|
|
8537
8618
|
let errors = [];
|
|
8538
8619
|
if (type === 'number') {
|
|
8539
|
-
errors = [...errors, ...runNumberValidation(field, value)];
|
|
8620
|
+
errors = [...errors, ...runNumberValidation(field, value, this._translate)];
|
|
8540
8621
|
}
|
|
8541
8622
|
if (!validate) {
|
|
8542
8623
|
return errors;
|
|
8543
8624
|
}
|
|
8544
8625
|
const evaluatedValidation = oldEvaluateFEELValues(validate, this._expressionLanguage, this._conditionChecker, this._form);
|
|
8545
|
-
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value)];
|
|
8626
|
+
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value, this._translate)];
|
|
8546
8627
|
return errors;
|
|
8547
8628
|
}
|
|
8548
8629
|
|
|
@@ -8569,31 +8650,39 @@ class Validator {
|
|
|
8569
8650
|
} = field;
|
|
8570
8651
|
let errors = [];
|
|
8571
8652
|
if (type === 'number') {
|
|
8572
|
-
errors = [...errors, ...runNumberValidation(field, value)];
|
|
8653
|
+
errors = [...errors, ...runNumberValidation(field, value, this._translate)];
|
|
8573
8654
|
}
|
|
8574
8655
|
if (!validate) {
|
|
8575
8656
|
return errors;
|
|
8576
8657
|
}
|
|
8577
8658
|
const evaluatedValidation = evaluateFEELValues(validate, this._expressionLanguage, expressionContextInfo);
|
|
8578
|
-
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value)];
|
|
8659
|
+
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value, this._translate)];
|
|
8579
8660
|
return errors;
|
|
8580
8661
|
}
|
|
8581
8662
|
}
|
|
8582
|
-
Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form', 'formFieldRegistry'];
|
|
8663
|
+
Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form', 'formFieldRegistry', 'translate'];
|
|
8583
8664
|
|
|
8584
8665
|
// helpers //////////
|
|
8585
8666
|
|
|
8586
|
-
function runNumberValidation(field, value) {
|
|
8667
|
+
function runNumberValidation(field, value, translate) {
|
|
8587
8668
|
const {
|
|
8588
8669
|
decimalDigits,
|
|
8589
8670
|
increment
|
|
8590
8671
|
} = field;
|
|
8591
8672
|
const errors = [];
|
|
8592
8673
|
if (value === 'NaN') {
|
|
8593
|
-
errors.push('Value is not a number.');
|
|
8674
|
+
errors.push(translate('Value is not a number.'));
|
|
8594
8675
|
} else if (value) {
|
|
8595
8676
|
if (decimalDigits >= 0 && countDecimals(value) > decimalDigits) {
|
|
8596
|
-
|
|
8677
|
+
if (decimalDigits === 0) {
|
|
8678
|
+
errors.push(translate('Value is expected to be an integer.'));
|
|
8679
|
+
} else if (decimalDigits === 1) {
|
|
8680
|
+
errors.push(translate('Value is expected to have at most 1 decimal digit.'));
|
|
8681
|
+
} else {
|
|
8682
|
+
errors.push(translate('Value is expected to have at most {value} decimal digits.', {
|
|
8683
|
+
value: decimalDigits.toString()
|
|
8684
|
+
}));
|
|
8685
|
+
}
|
|
8597
8686
|
}
|
|
8598
8687
|
if (increment) {
|
|
8599
8688
|
const bigValue = Big(value);
|
|
@@ -8602,54 +8691,69 @@ function runNumberValidation(field, value) {
|
|
|
8602
8691
|
if (offset.cmp(0) !== 0) {
|
|
8603
8692
|
const previousValue = bigValue.minus(offset);
|
|
8604
8693
|
const nextValue = previousValue.plus(bigIncrement);
|
|
8605
|
-
errors.push(
|
|
8694
|
+
errors.push(translate('Please select a valid value, the two nearest valid values are {previousValue} and {nextValue}.', {
|
|
8695
|
+
previousValue: previousValue,
|
|
8696
|
+
nextValue: nextValue
|
|
8697
|
+
}));
|
|
8606
8698
|
}
|
|
8607
8699
|
}
|
|
8608
8700
|
}
|
|
8609
8701
|
return errors;
|
|
8610
8702
|
}
|
|
8611
|
-
function runPresetValidation(field, validation, value) {
|
|
8703
|
+
function runPresetValidation(field, validation, value, translate) {
|
|
8612
8704
|
const errors = [];
|
|
8613
8705
|
if (validation.pattern && value && !new RegExp(validation.pattern).test(value)) {
|
|
8614
|
-
errors.push(validation.patternErrorMessage ||
|
|
8706
|
+
errors.push(validation.patternErrorMessage || translate('Field must match pattern {value}.', {
|
|
8707
|
+
value: validation.pattern
|
|
8708
|
+
}));
|
|
8615
8709
|
}
|
|
8616
8710
|
if (validation.required) {
|
|
8617
8711
|
const isUncheckedCheckbox = field.type === 'checkbox' && value === false;
|
|
8618
8712
|
const isUnsetValue = minDash.isNil(value) || value === '';
|
|
8619
8713
|
const isEmptyMultiselect = Array.isArray(value) && value.length === 0;
|
|
8620
8714
|
if (isUncheckedCheckbox || isUnsetValue || isEmptyMultiselect) {
|
|
8621
|
-
errors.push('Field is required.');
|
|
8715
|
+
errors.push(translate('Field is required.'));
|
|
8622
8716
|
}
|
|
8623
8717
|
}
|
|
8718
|
+
|
|
8719
|
+
// stringify: `translate` falls back to the raw placeholder for a falsy replacement, so 0 must not be passed as a number
|
|
8624
8720
|
if ('min' in validation && (value || value === 0)) {
|
|
8625
8721
|
try {
|
|
8626
8722
|
if (Big(value).lt(Big(validation.min))) {
|
|
8627
|
-
errors.push(
|
|
8723
|
+
errors.push(translate('Field must have minimum value of {value}.', {
|
|
8724
|
+
value: validation.min.toString()
|
|
8725
|
+
}));
|
|
8628
8726
|
}
|
|
8629
8727
|
} catch {
|
|
8630
|
-
errors.push('Min validation value is not a valid number.');
|
|
8728
|
+
errors.push(translate('Min validation value is not a valid number.'));
|
|
8631
8729
|
}
|
|
8632
8730
|
}
|
|
8633
8731
|
if ('max' in validation && (value || value === 0)) {
|
|
8634
8732
|
try {
|
|
8635
8733
|
if (Big(value).gt(Big(validation.max))) {
|
|
8636
|
-
errors.push(
|
|
8734
|
+
errors.push(translate('Field must have maximum value of {value}.', {
|
|
8735
|
+
value: validation.max.toString()
|
|
8736
|
+
}));
|
|
8637
8737
|
}
|
|
8638
8738
|
} catch {
|
|
8639
|
-
errors.push('Max validation value is not a valid number.');
|
|
8739
|
+
errors.push(translate('Max validation value is not a valid number.'));
|
|
8640
8740
|
}
|
|
8641
8741
|
}
|
|
8642
8742
|
if ('minLength' in validation && value && value.trim().length < validation.minLength) {
|
|
8643
|
-
errors.push(
|
|
8743
|
+
errors.push(translate('Field must have minimum length of {value}.', {
|
|
8744
|
+
value: validation.minLength.toString()
|
|
8745
|
+
}));
|
|
8644
8746
|
}
|
|
8645
8747
|
if ('maxLength' in validation && value && value.trim().length > validation.maxLength) {
|
|
8646
|
-
errors.push(
|
|
8748
|
+
errors.push(translate('Field must have maximum length of {value}.', {
|
|
8749
|
+
value: validation.maxLength.toString()
|
|
8750
|
+
}));
|
|
8647
8751
|
}
|
|
8648
8752
|
if ('validationType' in validation && value && validation.validationType === 'phone' && !PHONE_PATTERN.test(value)) {
|
|
8649
|
-
errors.push('Field must be a valid
|
|
8753
|
+
errors.push(translate('Field must be a valid international phone number. (e.g. +4930664040900)'));
|
|
8650
8754
|
}
|
|
8651
8755
|
if ('validationType' in validation && value && validation.validationType === 'email' && !EMAIL_PATTERN.test(value)) {
|
|
8652
|
-
errors.push('Field must be a valid email.');
|
|
8756
|
+
errors.push(translate('Field must be a valid email.'));
|
|
8653
8757
|
}
|
|
8654
8758
|
return errors;
|
|
8655
8759
|
}
|
|
@@ -8807,17 +8911,24 @@ class Importer {
|
|
|
8807
8911
|
}
|
|
8808
8912
|
Importer.$inject = ['formFieldRegistry', 'pathRegistry', 'fieldFactory', 'formLayouter'];
|
|
8809
8913
|
|
|
8914
|
+
/**
|
|
8915
|
+
* @typedef { import('diagram-js/lib/i18n/translate/translate').default } Translate
|
|
8916
|
+
*/
|
|
8917
|
+
|
|
8810
8918
|
class FieldFactory {
|
|
8811
8919
|
/**
|
|
8812
8920
|
* @constructor
|
|
8813
8921
|
*
|
|
8814
|
-
* @param
|
|
8815
|
-
* @param
|
|
8922
|
+
* @param formFieldRegistry
|
|
8923
|
+
* @param pathRegistry
|
|
8924
|
+
* @param formFields
|
|
8925
|
+
* @param {Translate} translate
|
|
8816
8926
|
*/
|
|
8817
|
-
constructor(formFieldRegistry, pathRegistry, formFields) {
|
|
8927
|
+
constructor(formFieldRegistry, pathRegistry, formFields, translate) {
|
|
8818
8928
|
this._formFieldRegistry = formFieldRegistry;
|
|
8819
8929
|
this._pathRegistry = pathRegistry;
|
|
8820
8930
|
this._formFields = formFields;
|
|
8931
|
+
this._translate = translate;
|
|
8821
8932
|
}
|
|
8822
8933
|
create(attrs, isNewField = true) {
|
|
8823
8934
|
const {
|
|
@@ -8850,13 +8961,17 @@ class FieldFactory {
|
|
|
8850
8961
|
isClosed: true,
|
|
8851
8962
|
knownAncestorIds
|
|
8852
8963
|
})) {
|
|
8853
|
-
throw new Error(
|
|
8964
|
+
throw new Error(this._translate("binding path '{value}' is already claimed", {
|
|
8965
|
+
value: [...parentPath, key].join('.')
|
|
8966
|
+
}));
|
|
8854
8967
|
}
|
|
8855
8968
|
if (config.pathed && path && !this._pathRegistry.canClaimPath([...parentPath, ...path.split('.')], {
|
|
8856
8969
|
isRepeatable: config.repeatable,
|
|
8857
8970
|
knownAncestorIds
|
|
8858
8971
|
})) {
|
|
8859
|
-
throw new Error(
|
|
8972
|
+
throw new Error(this._translate("binding path '{value}' is already claimed", {
|
|
8973
|
+
value: [...parentPath, ...path.split('.')].join('.')
|
|
8974
|
+
}));
|
|
8860
8975
|
}
|
|
8861
8976
|
const field = config.create({
|
|
8862
8977
|
...(config.label ? {
|
|
@@ -8917,7 +9032,7 @@ class FieldFactory {
|
|
|
8917
9032
|
return `${field.type}_${random}`;
|
|
8918
9033
|
}
|
|
8919
9034
|
}
|
|
8920
|
-
FieldFactory.$inject = ['formFieldRegistry', 'pathRegistry', 'formFields'];
|
|
9035
|
+
FieldFactory.$inject = ['formFieldRegistry', 'pathRegistry', 'formFields', 'translate'];
|
|
8921
9036
|
|
|
8922
9037
|
/**
|
|
8923
9038
|
* The PathRegistry class manages a hierarchical structure of paths associated with form fields.
|
|
@@ -9927,7 +10042,7 @@ class Form {
|
|
|
9927
10042
|
config: ['value', enrichedConfig]
|
|
9928
10043
|
}, {
|
|
9929
10044
|
form: ['value', this]
|
|
9930
|
-
}, CoreModule, ...modules, ...additionalModules]);
|
|
10045
|
+
}, TranslateModule, CoreModule, ...modules, ...additionalModules]);
|
|
9931
10046
|
}
|
|
9932
10047
|
|
|
9933
10048
|
/**
|