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