@bpmn-io/form-js-viewer 1.24.1 → 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/assets/form-js-base.css +7 -1
- package/dist/assets/form-js.css +6 -1
- package/dist/index.cjs +178 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +178 -66
- 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 +5 -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,
|
|
@@ -1960,10 +2000,13 @@ function Label(props) {
|
|
|
1960
2000
|
class: classNames('fjs-form-field-label', {
|
|
1961
2001
|
'fjs-incollapsible-label': !collapseOnEmpty
|
|
1962
2002
|
}, props['class']),
|
|
1963
|
-
children: [props.children,
|
|
1964
|
-
class: "fjs-
|
|
1965
|
-
"
|
|
1966
|
-
|
|
2003
|
+
children: [props.children, jsxRuntime.jsxs("span", {
|
|
2004
|
+
class: "fjs-label-content",
|
|
2005
|
+
children: [evaluatedLabel, required && jsxRuntime.jsx("span", {
|
|
2006
|
+
class: "fjs-asterix",
|
|
2007
|
+
"aria-hidden": true,
|
|
2008
|
+
children: "*"
|
|
2009
|
+
})]
|
|
1967
2010
|
})]
|
|
1968
2011
|
});
|
|
1969
2012
|
}
|
|
@@ -3064,6 +3107,7 @@ function Datetime(props) {
|
|
|
3064
3107
|
const {
|
|
3065
3108
|
formId
|
|
3066
3109
|
} = hooks.useContext(FormContext);
|
|
3110
|
+
const translate = useService('translate');
|
|
3067
3111
|
|
|
3068
3112
|
/** @type {import("preact").RefObject<HTMLDivElement>} */
|
|
3069
3113
|
const dateTimeGroupRef = hooks.useRef();
|
|
@@ -3154,8 +3198,8 @@ function Datetime(props) {
|
|
|
3154
3198
|
const allErrors = hooks.useMemo(() => {
|
|
3155
3199
|
if (required || subtype !== DATETIME_SUBTYPES.DATETIME) return errors;
|
|
3156
3200
|
const isOnlyOneFieldSet = isValidDate(dateTime.date) && !isValidTime(dateTime.time) || !isValidDate(dateTime.date) && isValidTime(dateTime.time);
|
|
3157
|
-
return isOnlyOneFieldSet ? ['Date and time must both be entered.', ...errors] : errors;
|
|
3158
|
-
}, [required, subtype, dateTime, errors]);
|
|
3201
|
+
return isOnlyOneFieldSet ? [translate('Date and time must both be entered.'), ...errors] : errors;
|
|
3202
|
+
}, [required, subtype, dateTime, errors, translate]);
|
|
3159
3203
|
const setDate = hooks.useCallback(date => {
|
|
3160
3204
|
setDateTimeUpdateRequest(prev => prev ? {
|
|
3161
3205
|
...prev,
|
|
@@ -3317,6 +3361,7 @@ function IFrame(props) {
|
|
|
3317
3361
|
const evaluatedLabel = useSingleLineTemplateEvaluation(label, {
|
|
3318
3362
|
debug: true
|
|
3319
3363
|
});
|
|
3364
|
+
const translate = useService('translate');
|
|
3320
3365
|
const [sandbox, allow] = useSecurityAttributesMap(security);
|
|
3321
3366
|
const [iframeRefresh, setIframeRefresh] = hooks.useState(0);
|
|
3322
3367
|
|
|
@@ -3333,7 +3378,7 @@ function IFrame(props) {
|
|
|
3333
3378
|
htmlFor: domId,
|
|
3334
3379
|
label: evaluatedLabel
|
|
3335
3380
|
}), !evaluatedUrl && jsxRuntime.jsx(IFramePlaceholder, {
|
|
3336
|
-
text:
|
|
3381
|
+
text: translate('No content to show.')
|
|
3337
3382
|
}), evaluatedUrl && safeUrl && jsxRuntime.jsx("iframe", {
|
|
3338
3383
|
src: safeUrl,
|
|
3339
3384
|
title: evaluatedLabel,
|
|
@@ -3343,7 +3388,7 @@ function IFrame(props) {
|
|
|
3343
3388
|
sandbox: sandbox,
|
|
3344
3389
|
allow
|
|
3345
3390
|
}, 'iframe-' + iframeRefresh), evaluatedUrl && !safeUrl && jsxRuntime.jsx(IFramePlaceholder, {
|
|
3346
|
-
text: "External content couldn't be loaded."
|
|
3391
|
+
text: translate("External content couldn't be loaded.")
|
|
3347
3392
|
})]
|
|
3348
3393
|
});
|
|
3349
3394
|
}
|
|
@@ -3931,6 +3976,7 @@ function Numberfield(props) {
|
|
|
3931
3976
|
const {
|
|
3932
3977
|
required
|
|
3933
3978
|
} = validate;
|
|
3979
|
+
const translate = useService('translate');
|
|
3934
3980
|
|
|
3935
3981
|
/** @type {import("preact").RefObject<HTMLInputElement>} */
|
|
3936
3982
|
const inputRef = hooks.useRef();
|
|
@@ -4104,7 +4150,7 @@ function Numberfield(props) {
|
|
|
4104
4150
|
children: [jsxRuntime.jsx("button", {
|
|
4105
4151
|
type: "button",
|
|
4106
4152
|
class: "fjs-number-arrow-up",
|
|
4107
|
-
"aria-label":
|
|
4153
|
+
"aria-label": translate('Increment'),
|
|
4108
4154
|
onClick: () => increment(),
|
|
4109
4155
|
tabIndex: -1,
|
|
4110
4156
|
children: jsxRuntime.jsx(SvgAngelUp, {})
|
|
@@ -4113,7 +4159,7 @@ function Numberfield(props) {
|
|
|
4113
4159
|
}), jsxRuntime.jsx("button", {
|
|
4114
4160
|
type: "button",
|
|
4115
4161
|
class: "fjs-number-arrow-down",
|
|
4116
|
-
"aria-label":
|
|
4162
|
+
"aria-label": translate('Decrement'),
|
|
4117
4163
|
onClick: () => decrement(),
|
|
4118
4164
|
tabIndex: -1,
|
|
4119
4165
|
children: jsxRuntime.jsx(SvgAngelDown, {})
|
|
@@ -4796,6 +4842,7 @@ function Taglist(props) {
|
|
|
4796
4842
|
/** @type {import("preact").RefObject<HTMLInputElement>} */
|
|
4797
4843
|
const inputRef = hooks.useRef();
|
|
4798
4844
|
const eventBus = useService('eventBus');
|
|
4845
|
+
const translate = useService('translate');
|
|
4799
4846
|
const {
|
|
4800
4847
|
loadState,
|
|
4801
4848
|
options
|
|
@@ -4929,7 +4976,7 @@ function Taglist(props) {
|
|
|
4929
4976
|
htmlFor: domId
|
|
4930
4977
|
}), !disabled && !readonly && !!values.length && jsxRuntime.jsx(SkipLink, {
|
|
4931
4978
|
className: "fjs-taglist-skip-link",
|
|
4932
|
-
label:
|
|
4979
|
+
label: translate('Skip to search'),
|
|
4933
4980
|
onSkip: onSkipToSearch
|
|
4934
4981
|
}), jsxRuntime.jsxs("div", {
|
|
4935
4982
|
class: classNames('fjs-taglist', {
|
|
@@ -4950,7 +4997,7 @@ function Taglist(props) {
|
|
|
4950
4997
|
children: getLabelCorrelation(entry)
|
|
4951
4998
|
}), !disabled && !readonly && jsxRuntime.jsx("button", {
|
|
4952
4999
|
type: "button",
|
|
4953
|
-
title:
|
|
5000
|
+
title: translate('Remove tag'),
|
|
4954
5001
|
class: "fjs-taglist-tag-remove",
|
|
4955
5002
|
onFocus: onElementFocus,
|
|
4956
5003
|
onBlur: onElementBlur,
|
|
@@ -4968,7 +5015,7 @@ function Taglist(props) {
|
|
|
4968
5015
|
onChange: onInputChange,
|
|
4969
5016
|
type: "text",
|
|
4970
5017
|
value: filter,
|
|
4971
|
-
placeholder: disabled || readonly ? undefined : 'Search',
|
|
5018
|
+
placeholder: disabled || readonly ? undefined : translate('Search'),
|
|
4972
5019
|
autoComplete: "off",
|
|
4973
5020
|
onKeyDown: onInputKeyDown,
|
|
4974
5021
|
onMouseDown: () => setIsEscapeClose(false),
|
|
@@ -4984,7 +5031,7 @@ function Taglist(props) {
|
|
|
4984
5031
|
values: filteredOptions,
|
|
4985
5032
|
getLabel: option => option.label,
|
|
4986
5033
|
onValueSelected: option => selectValue(option.value),
|
|
4987
|
-
emptyListMessage: hasOptionsLeft ? 'No results' : 'All values selected',
|
|
5034
|
+
emptyListMessage: hasOptionsLeft ? translate('No results') : translate('All values selected'),
|
|
4988
5035
|
listenerElement: inputRef.current
|
|
4989
5036
|
})
|
|
4990
5037
|
}), jsxRuntime.jsx(Description, {
|
|
@@ -5587,6 +5634,8 @@ var SvgCaretRight = function SvgCaretRight(props) {
|
|
|
5587
5634
|
const type$2 = 'table';
|
|
5588
5635
|
|
|
5589
5636
|
/**
|
|
5637
|
+
* @typedef { import('diagram-js/lib/i18n/translate/translate').default } Translate
|
|
5638
|
+
*
|
|
5590
5639
|
* @typedef {('asc'|'desc')} Direction
|
|
5591
5640
|
*
|
|
5592
5641
|
* @typedef Sorting
|
|
@@ -5636,6 +5685,7 @@ function Table(props) {
|
|
|
5636
5685
|
const chunkedData = minDash.isNumber(rowCount) ? chunk(sortedData, rowCount) : [sortedData];
|
|
5637
5686
|
const [currentPage, setCurrentPage] = hooks.useState(0);
|
|
5638
5687
|
const currentChunk = chunkedData[currentPage] || [];
|
|
5688
|
+
const translate = useService('translate');
|
|
5639
5689
|
hooks.useEffect(() => {
|
|
5640
5690
|
setCurrentPage(0);
|
|
5641
5691
|
}, [rowCount, sortBy]);
|
|
@@ -5667,7 +5717,7 @@ function Table(props) {
|
|
|
5667
5717
|
class: classNames('fjs-table-middle-container', {
|
|
5668
5718
|
'fjs-table-empty': evaluatedColumns.length === 0
|
|
5669
5719
|
}),
|
|
5670
|
-
children: [evaluatedColumns.length === 0 ? 'Nothing to show.' : jsxRuntime.jsx("div", {
|
|
5720
|
+
children: [evaluatedColumns.length === 0 ? translate('Nothing to show.') : jsxRuntime.jsx("div", {
|
|
5671
5721
|
class: "fjs-table-inner-container",
|
|
5672
5722
|
children: jsxRuntime.jsxs("table", {
|
|
5673
5723
|
class: "fjs-table",
|
|
@@ -5692,7 +5742,7 @@ function Table(props) {
|
|
|
5692
5742
|
toggleSortBy(key);
|
|
5693
5743
|
}
|
|
5694
5744
|
},
|
|
5695
|
-
"aria-label": getHeaderAriaLabel(sortBy, key, displayLabel),
|
|
5745
|
+
"aria-label": getHeaderAriaLabel(sortBy, key, displayLabel, translate),
|
|
5696
5746
|
children: jsxRuntime.jsxs("span", {
|
|
5697
5747
|
class: "fjs-table-th-label",
|
|
5698
5748
|
children: [displayLabel, sortBy !== null && sortBy.key === key ? jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
@@ -5713,7 +5763,7 @@ function Table(props) {
|
|
|
5713
5763
|
children: jsxRuntime.jsx("td", {
|
|
5714
5764
|
class: "fjs-table-td",
|
|
5715
5765
|
colSpan: evaluatedColumns.length,
|
|
5716
|
-
children:
|
|
5766
|
+
children: translate('Nothing to show.')
|
|
5717
5767
|
})
|
|
5718
5768
|
})
|
|
5719
5769
|
}) : jsxRuntime.jsx("tbody", {
|
|
@@ -5729,9 +5779,13 @@ function Table(props) {
|
|
|
5729
5779
|
})
|
|
5730
5780
|
}), minDash.isNumber(rowCount) && chunkedData.length > 1 && evaluatedColumns.length > 0 ? jsxRuntime.jsxs("nav", {
|
|
5731
5781
|
class: "fjs-table-nav",
|
|
5732
|
-
children: [jsxRuntime.
|
|
5782
|
+
children: [jsxRuntime.jsx("span", {
|
|
5733
5783
|
class: "fjs-table-nav-label",
|
|
5734
|
-
children:
|
|
5784
|
+
children: translate('{page} of {total}', {
|
|
5785
|
+
// stringify: see Validator.js
|
|
5786
|
+
page: (currentPage + 1).toString(),
|
|
5787
|
+
total: chunkedData.length.toString()
|
|
5788
|
+
})
|
|
5735
5789
|
}), jsxRuntime.jsx("button", {
|
|
5736
5790
|
type: "button",
|
|
5737
5791
|
class: "fjs-table-nav-button",
|
|
@@ -5739,7 +5793,7 @@ function Table(props) {
|
|
|
5739
5793
|
setCurrentPage(page => Math.max(page - 1, 0));
|
|
5740
5794
|
},
|
|
5741
5795
|
disabled: currentPage === 0,
|
|
5742
|
-
"aria-label":
|
|
5796
|
+
"aria-label": translate('Previous page'),
|
|
5743
5797
|
children: jsxRuntime.jsx(SvgCaretLeft, {})
|
|
5744
5798
|
}), jsxRuntime.jsx("button", {
|
|
5745
5799
|
type: "button",
|
|
@@ -5748,7 +5802,7 @@ function Table(props) {
|
|
|
5748
5802
|
setCurrentPage(page => Math.min(page + 1, chunkedData.length - 1));
|
|
5749
5803
|
},
|
|
5750
5804
|
disabled: currentPage >= chunkedData.length - 1,
|
|
5751
|
-
"aria-label":
|
|
5805
|
+
"aria-label": translate('Next page'),
|
|
5752
5806
|
children: jsxRuntime.jsx(SvgCaretRight, {})
|
|
5753
5807
|
})]
|
|
5754
5808
|
}) : null]
|
|
@@ -5898,15 +5952,20 @@ function sortByColumn(array, key, direction) {
|
|
|
5898
5952
|
* @param {null|Sorting} sortBy
|
|
5899
5953
|
* @param {string} key
|
|
5900
5954
|
* @param {string} label
|
|
5955
|
+
* @param {Translate} translate
|
|
5901
5956
|
*/
|
|
5902
|
-
function getHeaderAriaLabel(sortBy, key, label) {
|
|
5957
|
+
function getHeaderAriaLabel(sortBy, key, label, translate) {
|
|
5903
5958
|
if (sortBy === null || sortBy.key !== key) {
|
|
5904
|
-
return
|
|
5959
|
+
return translate('Click to sort by {value} descending', {
|
|
5960
|
+
value: label
|
|
5961
|
+
});
|
|
5905
5962
|
}
|
|
5906
5963
|
if (sortBy.direction === 'asc') {
|
|
5907
|
-
return 'Click to remove sorting';
|
|
5964
|
+
return translate('Click to remove sorting');
|
|
5908
5965
|
}
|
|
5909
|
-
return
|
|
5966
|
+
return translate('Click to sort by {value} ascending', {
|
|
5967
|
+
value: label
|
|
5968
|
+
});
|
|
5910
5969
|
}
|
|
5911
5970
|
|
|
5912
5971
|
/**
|
|
@@ -5977,6 +6036,7 @@ function FilePicker(props) {
|
|
|
5977
6036
|
const errorMessageId = `${domId}-error-message`;
|
|
5978
6037
|
/** @type {File[]} */
|
|
5979
6038
|
const selectedFiles = fileRegistry === null ? EMPTY_ARRAY$1 : fileRegistry.getFiles(filesKey);
|
|
6039
|
+
const translate = useService('translate');
|
|
5980
6040
|
hooks.useEffect(() => {
|
|
5981
6041
|
if (filesKey && fileRegistry !== null && !fileRegistry.hasKey(filesKey)) {
|
|
5982
6042
|
onChange({
|
|
@@ -6047,7 +6107,7 @@ function FilePicker(props) {
|
|
|
6047
6107
|
children: "Browse"
|
|
6048
6108
|
}), jsxRuntime.jsx("span", {
|
|
6049
6109
|
className: "fjs-form-field-label",
|
|
6050
|
-
children: getSelectedFilesLabel(selectedFiles)
|
|
6110
|
+
children: getSelectedFilesLabel(selectedFiles, translate)
|
|
6051
6111
|
})]
|
|
6052
6112
|
}), jsxRuntime.jsx(Errors, {
|
|
6053
6113
|
id: errorMessageId,
|
|
@@ -6070,16 +6130,19 @@ FilePicker.config = {
|
|
|
6070
6130
|
|
|
6071
6131
|
/**
|
|
6072
6132
|
* @param {File[]} files
|
|
6133
|
+
* @param {Translate} translate
|
|
6073
6134
|
* @returns {string}
|
|
6074
6135
|
*/
|
|
6075
|
-
function getSelectedFilesLabel(files) {
|
|
6136
|
+
function getSelectedFilesLabel(files, translate) {
|
|
6076
6137
|
if (files.length === 0) {
|
|
6077
|
-
return 'No files selected';
|
|
6138
|
+
return translate('No files selected');
|
|
6078
6139
|
}
|
|
6079
6140
|
if (files.length === 1) {
|
|
6080
6141
|
return files[0].name;
|
|
6081
6142
|
}
|
|
6082
|
-
return
|
|
6143
|
+
return translate('{value} files selected', {
|
|
6144
|
+
value: files.length.toString()
|
|
6145
|
+
});
|
|
6083
6146
|
}
|
|
6084
6147
|
|
|
6085
6148
|
var _path$4;
|
|
@@ -6102,6 +6165,10 @@ var SvgDownload = function SvgDownload(props) {
|
|
|
6102
6165
|
|
|
6103
6166
|
const type = 'documentPreview';
|
|
6104
6167
|
|
|
6168
|
+
/**
|
|
6169
|
+
* @typedef { import('diagram-js/lib/i18n/translate/translate').default } Translate
|
|
6170
|
+
*/
|
|
6171
|
+
|
|
6105
6172
|
/**
|
|
6106
6173
|
* @typedef DocumentEndpointBuilder
|
|
6107
6174
|
* @property {(document: DocumentMetadata) => string} [buildUrl]
|
|
@@ -6147,6 +6214,7 @@ function DocumentPreview(props) {
|
|
|
6147
6214
|
const evaluatedLabel = useSingleLineTemplateEvaluation(label, {
|
|
6148
6215
|
debug: true
|
|
6149
6216
|
});
|
|
6217
|
+
const translate = useService('translate');
|
|
6150
6218
|
return jsxRuntime.jsxs("div", {
|
|
6151
6219
|
class: formFieldClasses(type),
|
|
6152
6220
|
children: [jsxRuntime.jsx(Label, {
|
|
@@ -6172,7 +6240,7 @@ function DocumentPreview(props) {
|
|
|
6172
6240
|
id: errorMessageId,
|
|
6173
6241
|
errors: getErrors({
|
|
6174
6242
|
dataSource
|
|
6175
|
-
})
|
|
6243
|
+
}, translate)
|
|
6176
6244
|
})]
|
|
6177
6245
|
});
|
|
6178
6246
|
}
|
|
@@ -6194,15 +6262,16 @@ DocumentPreview.config = {
|
|
|
6194
6262
|
* @property {string|undefined} dataSource
|
|
6195
6263
|
*
|
|
6196
6264
|
* @param {GetErrorOptions} options
|
|
6265
|
+
* @param {Translate} translate
|
|
6197
6266
|
* @returns {string[]}
|
|
6198
6267
|
*/
|
|
6199
|
-
function getErrors(options) {
|
|
6268
|
+
function getErrors(options, translate) {
|
|
6200
6269
|
const {
|
|
6201
6270
|
dataSource
|
|
6202
6271
|
} = options;
|
|
6203
6272
|
let errors = [];
|
|
6204
6273
|
if (!minDash.isString(dataSource) || dataSource.length < 1) {
|
|
6205
|
-
errors.push('Document reference is not defined.');
|
|
6274
|
+
errors.push(translate('Document reference is not defined.'));
|
|
6206
6275
|
}
|
|
6207
6276
|
return errors;
|
|
6208
6277
|
}
|
|
@@ -6255,6 +6324,7 @@ function PdfRenderer(props) {
|
|
|
6255
6324
|
/** @type {ReturnType<typeof import("preact/hooks").useState<null | string>>} */
|
|
6256
6325
|
const [pdfObjectUrl, setPdfObjectUrl] = hooks.useState(null);
|
|
6257
6326
|
const [hasError, setHasError] = hooks.useState(false);
|
|
6327
|
+
const translate = useService('translate');
|
|
6258
6328
|
hooks.useEffect(() => {
|
|
6259
6329
|
/** @type {null | string} */
|
|
6260
6330
|
let objectUrl = null;
|
|
@@ -6288,7 +6358,7 @@ function PdfRenderer(props) {
|
|
|
6288
6358
|
class: `fjs-${type}-pdf-viewer`
|
|
6289
6359
|
}) : null, hasError ? jsxRuntime.jsx(Errors, {
|
|
6290
6360
|
id: errorMessageId,
|
|
6291
|
-
errors: ['Unable to download document']
|
|
6361
|
+
errors: [translate('Unable to download document')]
|
|
6292
6362
|
}) : null]
|
|
6293
6363
|
});
|
|
6294
6364
|
}
|
|
@@ -6368,9 +6438,10 @@ function DocumentRenderer(props) {
|
|
|
6368
6438
|
const isInViewport = useInViewport(ref);
|
|
6369
6439
|
const onError = hooks.useCallback(() => setHasError(true), []);
|
|
6370
6440
|
const requestInit = hooks.useMemo(() => getDocumentRequestInit(documentEndpointBuilder, documentMetadata), [documentEndpointBuilder, documentMetadata]);
|
|
6441
|
+
const translate = useService('translate');
|
|
6371
6442
|
const singleDocumentContainerClassName = `fjs-${type}-single-document-container`;
|
|
6372
6443
|
const errorMessageId = `${domId}-error-message`;
|
|
6373
|
-
const errorMessage = 'Unable to download document';
|
|
6444
|
+
const errorMessage = translate('Unable to download document');
|
|
6374
6445
|
const isContentTypePresent = typeof metadata.contentType === 'string';
|
|
6375
6446
|
if (isContentTypePresent && metadata.contentType.toLowerCase().startsWith('image/') && isInViewport) {
|
|
6376
6447
|
return jsxRuntime.jsxs("div", {
|
|
@@ -6448,6 +6519,7 @@ function DownloadButton(props) {
|
|
|
6448
6519
|
onDownloadError,
|
|
6449
6520
|
requestInit
|
|
6450
6521
|
} = props;
|
|
6522
|
+
const translate = useService('translate');
|
|
6451
6523
|
const handleDownload = async () => {
|
|
6452
6524
|
try {
|
|
6453
6525
|
const response = await fetch(endpoint, requestInit);
|
|
@@ -6470,7 +6542,9 @@ function DownloadButton(props) {
|
|
|
6470
6542
|
type: "button",
|
|
6471
6543
|
onClick: handleDownload,
|
|
6472
6544
|
class: classNames(`fjs-${type}-download-button`),
|
|
6473
|
-
"aria-label":
|
|
6545
|
+
"aria-label": translate('Download {fileName}', {
|
|
6546
|
+
fileName
|
|
6547
|
+
}),
|
|
6474
6548
|
children: jsxRuntime.jsx(SvgDownload, {})
|
|
6475
6549
|
});
|
|
6476
6550
|
}
|
|
@@ -7816,6 +7890,7 @@ class RepeatRenderManager {
|
|
|
7816
7890
|
const {
|
|
7817
7891
|
data
|
|
7818
7892
|
} = this._form._getState();
|
|
7893
|
+
const translate = useService('translate');
|
|
7819
7894
|
const dataPath = this._pathRegistry.getValuePath(repeaterField, {
|
|
7820
7895
|
indexes
|
|
7821
7896
|
});
|
|
@@ -7872,16 +7947,18 @@ class RepeatRenderManager {
|
|
|
7872
7947
|
ref: addButtonRef,
|
|
7873
7948
|
onClick: onAddItem,
|
|
7874
7949
|
children: jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
7875
|
-
children: [jsxRuntime.jsx(SvgAdd, {}), " ", 'Add new']
|
|
7950
|
+
children: [jsxRuntime.jsx(SvgAdd, {}), " ", translate('Add new')]
|
|
7876
7951
|
})
|
|
7877
7952
|
}) : null, collapseEnabled ? jsxRuntime.jsx("button", {
|
|
7878
7953
|
type: "button",
|
|
7879
7954
|
class: "fjs-repeat-render-collapse",
|
|
7880
7955
|
onClick: toggle,
|
|
7881
7956
|
children: isCollapsed ? jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
7882
|
-
children: [jsxRuntime.jsx(SvgExpand, {}), " ",
|
|
7957
|
+
children: [jsxRuntime.jsx(SvgExpand, {}), " ", translate('Expand all ({value})', {
|
|
7958
|
+
value: values.length - 1
|
|
7959
|
+
})]
|
|
7883
7960
|
}) : jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
7884
|
-
children: [jsxRuntime.jsx(SvgCollapse, {}), " ", 'Collapse']
|
|
7961
|
+
children: [jsxRuntime.jsx(SvgCollapse, {}), " ", translate('Collapse')]
|
|
7885
7962
|
})
|
|
7886
7963
|
}) : null]
|
|
7887
7964
|
});
|
|
@@ -8514,11 +8591,12 @@ const EMAIL_PATTERN = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-
|
|
|
8514
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}$/;
|
|
8515
8592
|
const VALIDATE_FEEL_PROPERTIES = ['min', 'max', 'minLength', 'maxLength'];
|
|
8516
8593
|
class Validator {
|
|
8517
|
-
constructor(expressionLanguage, conditionChecker, form, formFieldRegistry) {
|
|
8594
|
+
constructor(expressionLanguage, conditionChecker, form, formFieldRegistry, translate) {
|
|
8518
8595
|
this._expressionLanguage = expressionLanguage;
|
|
8519
8596
|
this._conditionChecker = conditionChecker;
|
|
8520
8597
|
this._form = form;
|
|
8521
8598
|
this._formFieldRegistry = formFieldRegistry;
|
|
8599
|
+
this._translate = translate;
|
|
8522
8600
|
}
|
|
8523
8601
|
|
|
8524
8602
|
/**
|
|
@@ -8533,13 +8611,13 @@ class Validator {
|
|
|
8533
8611
|
} = field;
|
|
8534
8612
|
let errors = [];
|
|
8535
8613
|
if (type === 'number') {
|
|
8536
|
-
errors = [...errors, ...runNumberValidation(field, value)];
|
|
8614
|
+
errors = [...errors, ...runNumberValidation(field, value, this._translate)];
|
|
8537
8615
|
}
|
|
8538
8616
|
if (!validate) {
|
|
8539
8617
|
return errors;
|
|
8540
8618
|
}
|
|
8541
8619
|
const evaluatedValidation = oldEvaluateFEELValues(validate, this._expressionLanguage, this._conditionChecker, this._form);
|
|
8542
|
-
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value)];
|
|
8620
|
+
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value, this._translate)];
|
|
8543
8621
|
return errors;
|
|
8544
8622
|
}
|
|
8545
8623
|
|
|
@@ -8566,31 +8644,39 @@ class Validator {
|
|
|
8566
8644
|
} = field;
|
|
8567
8645
|
let errors = [];
|
|
8568
8646
|
if (type === 'number') {
|
|
8569
|
-
errors = [...errors, ...runNumberValidation(field, value)];
|
|
8647
|
+
errors = [...errors, ...runNumberValidation(field, value, this._translate)];
|
|
8570
8648
|
}
|
|
8571
8649
|
if (!validate) {
|
|
8572
8650
|
return errors;
|
|
8573
8651
|
}
|
|
8574
8652
|
const evaluatedValidation = evaluateFEELValues(validate, this._expressionLanguage, expressionContextInfo);
|
|
8575
|
-
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value)];
|
|
8653
|
+
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value, this._translate)];
|
|
8576
8654
|
return errors;
|
|
8577
8655
|
}
|
|
8578
8656
|
}
|
|
8579
|
-
Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form', 'formFieldRegistry'];
|
|
8657
|
+
Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form', 'formFieldRegistry', 'translate'];
|
|
8580
8658
|
|
|
8581
8659
|
// helpers //////////
|
|
8582
8660
|
|
|
8583
|
-
function runNumberValidation(field, value) {
|
|
8661
|
+
function runNumberValidation(field, value, translate) {
|
|
8584
8662
|
const {
|
|
8585
8663
|
decimalDigits,
|
|
8586
8664
|
increment
|
|
8587
8665
|
} = field;
|
|
8588
8666
|
const errors = [];
|
|
8589
8667
|
if (value === 'NaN') {
|
|
8590
|
-
errors.push('Value is not a number.');
|
|
8668
|
+
errors.push(translate('Value is not a number.'));
|
|
8591
8669
|
} else if (value) {
|
|
8592
8670
|
if (decimalDigits >= 0 && countDecimals(value) > decimalDigits) {
|
|
8593
|
-
|
|
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
|
+
}
|
|
8594
8680
|
}
|
|
8595
8681
|
if (increment) {
|
|
8596
8682
|
const bigValue = Big(value);
|
|
@@ -8599,54 +8685,69 @@ function runNumberValidation(field, value) {
|
|
|
8599
8685
|
if (offset.cmp(0) !== 0) {
|
|
8600
8686
|
const previousValue = bigValue.minus(offset);
|
|
8601
8687
|
const nextValue = previousValue.plus(bigIncrement);
|
|
8602
|
-
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
|
+
}));
|
|
8603
8692
|
}
|
|
8604
8693
|
}
|
|
8605
8694
|
}
|
|
8606
8695
|
return errors;
|
|
8607
8696
|
}
|
|
8608
|
-
function runPresetValidation(field, validation, value) {
|
|
8697
|
+
function runPresetValidation(field, validation, value, translate) {
|
|
8609
8698
|
const errors = [];
|
|
8610
8699
|
if (validation.pattern && value && !new RegExp(validation.pattern).test(value)) {
|
|
8611
|
-
errors.push(validation.patternErrorMessage ||
|
|
8700
|
+
errors.push(validation.patternErrorMessage || translate('Field must match pattern {value}.', {
|
|
8701
|
+
value: validation.pattern
|
|
8702
|
+
}));
|
|
8612
8703
|
}
|
|
8613
8704
|
if (validation.required) {
|
|
8614
8705
|
const isUncheckedCheckbox = field.type === 'checkbox' && value === false;
|
|
8615
8706
|
const isUnsetValue = minDash.isNil(value) || value === '';
|
|
8616
8707
|
const isEmptyMultiselect = Array.isArray(value) && value.length === 0;
|
|
8617
8708
|
if (isUncheckedCheckbox || isUnsetValue || isEmptyMultiselect) {
|
|
8618
|
-
errors.push('Field is required.');
|
|
8709
|
+
errors.push(translate('Field is required.'));
|
|
8619
8710
|
}
|
|
8620
8711
|
}
|
|
8712
|
+
|
|
8713
|
+
// stringify: `translate` falls back to the raw placeholder for a falsy replacement, so 0 must not be passed as a number
|
|
8621
8714
|
if ('min' in validation && (value || value === 0)) {
|
|
8622
8715
|
try {
|
|
8623
8716
|
if (Big(value).lt(Big(validation.min))) {
|
|
8624
|
-
errors.push(
|
|
8717
|
+
errors.push(translate('Field must have minimum value of {value}.', {
|
|
8718
|
+
value: validation.min.toString()
|
|
8719
|
+
}));
|
|
8625
8720
|
}
|
|
8626
8721
|
} catch {
|
|
8627
|
-
errors.push('Min validation value is not a valid number.');
|
|
8722
|
+
errors.push(translate('Min validation value is not a valid number.'));
|
|
8628
8723
|
}
|
|
8629
8724
|
}
|
|
8630
8725
|
if ('max' in validation && (value || value === 0)) {
|
|
8631
8726
|
try {
|
|
8632
8727
|
if (Big(value).gt(Big(validation.max))) {
|
|
8633
|
-
errors.push(
|
|
8728
|
+
errors.push(translate('Field must have maximum value of {value}.', {
|
|
8729
|
+
value: validation.max.toString()
|
|
8730
|
+
}));
|
|
8634
8731
|
}
|
|
8635
8732
|
} catch {
|
|
8636
|
-
errors.push('Max validation value is not a valid number.');
|
|
8733
|
+
errors.push(translate('Max validation value is not a valid number.'));
|
|
8637
8734
|
}
|
|
8638
8735
|
}
|
|
8639
8736
|
if ('minLength' in validation && value && value.trim().length < validation.minLength) {
|
|
8640
|
-
errors.push(
|
|
8737
|
+
errors.push(translate('Field must have minimum length of {value}.', {
|
|
8738
|
+
value: validation.minLength.toString()
|
|
8739
|
+
}));
|
|
8641
8740
|
}
|
|
8642
8741
|
if ('maxLength' in validation && value && value.trim().length > validation.maxLength) {
|
|
8643
|
-
errors.push(
|
|
8742
|
+
errors.push(translate('Field must have maximum length of {value}.', {
|
|
8743
|
+
value: validation.maxLength.toString()
|
|
8744
|
+
}));
|
|
8644
8745
|
}
|
|
8645
8746
|
if ('validationType' in validation && value && validation.validationType === 'phone' && !PHONE_PATTERN.test(value)) {
|
|
8646
|
-
errors.push('Field must be a valid
|
|
8747
|
+
errors.push(translate('Field must be a valid international phone number. (e.g. +4930664040900)'));
|
|
8647
8748
|
}
|
|
8648
8749
|
if ('validationType' in validation && value && validation.validationType === 'email' && !EMAIL_PATTERN.test(value)) {
|
|
8649
|
-
errors.push('Field must be a valid email.');
|
|
8750
|
+
errors.push(translate('Field must be a valid email.'));
|
|
8650
8751
|
}
|
|
8651
8752
|
return errors;
|
|
8652
8753
|
}
|
|
@@ -8804,17 +8905,24 @@ class Importer {
|
|
|
8804
8905
|
}
|
|
8805
8906
|
Importer.$inject = ['formFieldRegistry', 'pathRegistry', 'fieldFactory', 'formLayouter'];
|
|
8806
8907
|
|
|
8908
|
+
/**
|
|
8909
|
+
* @typedef { import('diagram-js/lib/i18n/translate/translate').default } Translate
|
|
8910
|
+
*/
|
|
8911
|
+
|
|
8807
8912
|
class FieldFactory {
|
|
8808
8913
|
/**
|
|
8809
8914
|
* @constructor
|
|
8810
8915
|
*
|
|
8811
|
-
* @param
|
|
8812
|
-
* @param
|
|
8916
|
+
* @param formFieldRegistry
|
|
8917
|
+
* @param pathRegistry
|
|
8918
|
+
* @param formFields
|
|
8919
|
+
* @param {Translate} translate
|
|
8813
8920
|
*/
|
|
8814
|
-
constructor(formFieldRegistry, pathRegistry, formFields) {
|
|
8921
|
+
constructor(formFieldRegistry, pathRegistry, formFields, translate) {
|
|
8815
8922
|
this._formFieldRegistry = formFieldRegistry;
|
|
8816
8923
|
this._pathRegistry = pathRegistry;
|
|
8817
8924
|
this._formFields = formFields;
|
|
8925
|
+
this._translate = translate;
|
|
8818
8926
|
}
|
|
8819
8927
|
create(attrs, isNewField = true) {
|
|
8820
8928
|
const {
|
|
@@ -8847,13 +8955,17 @@ class FieldFactory {
|
|
|
8847
8955
|
isClosed: true,
|
|
8848
8956
|
knownAncestorIds
|
|
8849
8957
|
})) {
|
|
8850
|
-
throw new Error(
|
|
8958
|
+
throw new Error(this._translate("binding path '{value}' is already claimed", {
|
|
8959
|
+
value: [...parentPath, key].join('.')
|
|
8960
|
+
}));
|
|
8851
8961
|
}
|
|
8852
8962
|
if (config.pathed && path && !this._pathRegistry.canClaimPath([...parentPath, ...path.split('.')], {
|
|
8853
8963
|
isRepeatable: config.repeatable,
|
|
8854
8964
|
knownAncestorIds
|
|
8855
8965
|
})) {
|
|
8856
|
-
throw new Error(
|
|
8966
|
+
throw new Error(this._translate("binding path '{value}' is already claimed", {
|
|
8967
|
+
value: [...parentPath, ...path.split('.')].join('.')
|
|
8968
|
+
}));
|
|
8857
8969
|
}
|
|
8858
8970
|
const field = config.create({
|
|
8859
8971
|
...(config.label ? {
|
|
@@ -8914,7 +9026,7 @@ class FieldFactory {
|
|
|
8914
9026
|
return `${field.type}_${random}`;
|
|
8915
9027
|
}
|
|
8916
9028
|
}
|
|
8917
|
-
FieldFactory.$inject = ['formFieldRegistry', 'pathRegistry', 'formFields'];
|
|
9029
|
+
FieldFactory.$inject = ['formFieldRegistry', 'pathRegistry', 'formFields', 'translate'];
|
|
8918
9030
|
|
|
8919
9031
|
/**
|
|
8920
9032
|
* The PathRegistry class manages a hierarchical structure of paths associated with form fields.
|
|
@@ -9924,7 +10036,7 @@ class Form {
|
|
|
9924
10036
|
config: ['value', enrichedConfig]
|
|
9925
10037
|
}, {
|
|
9926
10038
|
form: ['value', this]
|
|
9927
|
-
}, CoreModule, ...modules, ...additionalModules]);
|
|
10039
|
+
}, TranslateModule, CoreModule, ...modules, ...additionalModules]);
|
|
9928
10040
|
}
|
|
9929
10041
|
|
|
9930
10042
|
/**
|