@plone/volto 14.0.2 → 14.1.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/CHANGELOG.md +22 -0
- package/locales/ca/LC_MESSAGES/volto.po +12 -2
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +12 -2
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +12 -2
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +12 -2
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +12 -2
- package/locales/eu.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +12 -2
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +12 -2
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +12 -2
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +12 -2
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +12 -2
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +12 -2
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +12 -2
- package/locales/ro.json +1 -1
- package/locales/volto.pot +12 -2
- package/package.json +2 -1
- package/src/actions/vocabularies/vocabularies.js +14 -3
- package/src/components/index.js +1 -0
- package/src/components/manage/Blocks/HeroImageLeft/Edit.jsx +1 -1
- package/src/components/manage/Blocks/Listing/getAsyncData.js +1 -1
- package/src/components/manage/Blocks/Text/Edit.jsx +19 -0
- package/src/components/manage/Form/Form.jsx +11 -1
- package/src/components/manage/Form/UndoToolbar.jsx +78 -0
- package/src/components/manage/Widgets/AlignWidget.stories.jsx +5 -21
- package/src/components/manage/Widgets/ArrayWidget.jsx +83 -101
- package/src/components/manage/Widgets/ArrayWidget.stories.jsx +29 -64
- package/src/components/manage/Widgets/CheckboxWidget.stories.jsx +5 -22
- package/src/components/manage/Widgets/DatetimeWidget.jsx +65 -74
- package/src/components/manage/Widgets/DatetimeWidget.stories.jsx +7 -23
- package/src/components/manage/Widgets/DatetimeWidget.test.jsx +17 -15
- package/src/components/manage/Widgets/EmailWidget.stories.jsx +5 -22
- package/src/components/manage/Widgets/FileWidget.stories.jsx +5 -22
- package/src/components/manage/Widgets/NumberWidget.stories.jsx +5 -23
- package/src/components/manage/Widgets/ObjectBrowserWidget.stories.js +24 -32
- package/src/components/manage/Widgets/ObjectListWidget.stories.js +44 -44
- package/src/components/manage/Widgets/ObjectWidget.stories.jsx +13 -28
- package/src/components/manage/Widgets/PasswordWidget.stories.jsx +5 -22
- package/src/components/manage/Widgets/QueryWidget.jsx +2 -2
- package/src/components/manage/Widgets/QueryWidget.stories.jsx +1637 -22
- package/src/components/manage/Widgets/SelectAutoComplete.jsx +79 -48
- package/src/components/manage/Widgets/SelectAutoComplete.test.jsx +16 -0
- package/src/components/manage/Widgets/SelectAutocompleteWidget.stories.jsx +161 -0
- package/src/components/manage/Widgets/SelectUtils.js +90 -30
- package/src/components/manage/Widgets/SelectUtils.test.jsx +76 -1
- package/src/components/manage/Widgets/SelectWidget.jsx +26 -37
- package/src/components/manage/Widgets/SelectWidget.stories.jsx +96 -28
- package/src/components/manage/Widgets/TextWidget.stories.jsx +5 -22
- package/src/components/manage/Widgets/TextareaWidget.stories.jsx +5 -22
- package/src/components/manage/Widgets/TokenWidget.jsx +19 -17
- package/src/components/manage/Widgets/TokenWidget.stories.jsx +141 -0
- package/src/components/manage/Widgets/UrlWidget.stories.jsx +5 -21
- package/src/components/manage/Widgets/VocabularyTermsWidget.stories.js +27 -64
- package/src/components/manage/Widgets/WysiwygWidget.stories.jsx +5 -22
- package/src/components/manage/Widgets/story.jsx +38 -0
- package/src/components/theme/ContactForm/ContactForm.jsx +1 -0
- package/src/components/theme/ContactForm/ContactForm.stories.jsx +126 -0
- package/src/components/theme/CorsError/CorsError.jsx +2 -2
- package/src/config/Loadables.jsx +2 -0
- package/src/config/index.js +1 -0
- package/src/helpers/UndoManager/useUndoManager.js +102 -0
- package/src/helpers/index.js +1 -0
- package/src/reducers/vocabularies/vocabularies.js +13 -2
- package/src/store.js +1 -1
- package/src/storybook.jsx +55 -0
- package/theme/themes/pastanaga/extras/time-picker-overrides.less +1 -1
- package/include/python3.8/Python-ast.h +0 -715
- package/include/python3.8/Python.h +0 -160
- package/include/python3.8/abstract.h +0 -844
- package/include/python3.8/asdl.h +0 -46
- package/include/python3.8/ast.h +0 -37
- package/include/python3.8/bitset.h +0 -23
- package/include/python3.8/bltinmodule.h +0 -14
- package/include/python3.8/boolobject.h +0 -34
- package/include/python3.8/bytearrayobject.h +0 -62
- package/include/python3.8/bytes_methods.h +0 -69
- package/include/python3.8/bytesobject.h +0 -224
- package/include/python3.8/cellobject.h +0 -29
- package/include/python3.8/ceval.h +0 -231
- package/include/python3.8/classobject.h +0 -59
- package/include/python3.8/code.h +0 -180
- package/include/python3.8/codecs.h +0 -240
- package/include/python3.8/compile.h +0 -106
- package/include/python3.8/complexobject.h +0 -69
- package/include/python3.8/context.h +0 -84
- package/include/python3.8/cpython/abstract.h +0 -319
- package/include/python3.8/cpython/dictobject.h +0 -94
- package/include/python3.8/cpython/fileobject.h +0 -24
- package/include/python3.8/cpython/initconfig.h +0 -434
- package/include/python3.8/cpython/interpreteridobject.h +0 -19
- package/include/python3.8/cpython/object.h +0 -470
- package/include/python3.8/cpython/objimpl.h +0 -113
- package/include/python3.8/cpython/pyerrors.h +0 -188
- package/include/python3.8/cpython/pylifecycle.h +0 -78
- package/include/python3.8/cpython/pymem.h +0 -108
- package/include/python3.8/cpython/pystate.h +0 -252
- package/include/python3.8/cpython/sysmodule.h +0 -21
- package/include/python3.8/cpython/traceback.h +0 -22
- package/include/python3.8/cpython/tupleobject.h +0 -36
- package/include/python3.8/cpython/unicodeobject.h +0 -1239
- package/include/python3.8/datetime.h +0 -259
- package/include/python3.8/descrobject.h +0 -108
- package/include/python3.8/dictobject.h +0 -94
- package/include/python3.8/dtoa.h +0 -19
- package/include/python3.8/dynamic_annotations.h +0 -499
- package/include/python3.8/enumobject.h +0 -17
- package/include/python3.8/errcode.h +0 -38
- package/include/python3.8/eval.h +0 -37
- package/include/python3.8/fileobject.h +0 -49
- package/include/python3.8/fileutils.h +0 -185
- package/include/python3.8/floatobject.h +0 -130
- package/include/python3.8/frameobject.h +0 -92
- package/include/python3.8/funcobject.h +0 -104
- package/include/python3.8/genobject.h +0 -109
- package/include/python3.8/graminit.h +0 -94
- package/include/python3.8/grammar.h +0 -77
- package/include/python3.8/import.h +0 -149
- package/include/python3.8/internal/pycore_accu.h +0 -39
- package/include/python3.8/internal/pycore_atomic.h +0 -558
- package/include/python3.8/internal/pycore_ceval.h +0 -37
- package/include/python3.8/internal/pycore_code.h +0 -27
- package/include/python3.8/internal/pycore_condvar.h +0 -95
- package/include/python3.8/internal/pycore_context.h +0 -42
- package/include/python3.8/internal/pycore_fileutils.h +0 -54
- package/include/python3.8/internal/pycore_getopt.h +0 -22
- package/include/python3.8/internal/pycore_gil.h +0 -50
- package/include/python3.8/internal/pycore_hamt.h +0 -116
- package/include/python3.8/internal/pycore_initconfig.h +0 -166
- package/include/python3.8/internal/pycore_object.h +0 -81
- package/include/python3.8/internal/pycore_pathconfig.h +0 -75
- package/include/python3.8/internal/pycore_pyerrors.h +0 -62
- package/include/python3.8/internal/pycore_pyhash.h +0 -10
- package/include/python3.8/internal/pycore_pylifecycle.h +0 -118
- package/include/python3.8/internal/pycore_pymem.h +0 -212
- package/include/python3.8/internal/pycore_pystate.h +0 -326
- package/include/python3.8/internal/pycore_traceback.h +0 -96
- package/include/python3.8/internal/pycore_tupleobject.h +0 -19
- package/include/python3.8/internal/pycore_warnings.h +0 -25
- package/include/python3.8/interpreteridobject.h +0 -17
- package/include/python3.8/intrcheck.h +0 -33
- package/include/python3.8/iterobject.h +0 -25
- package/include/python3.8/listobject.h +0 -81
- package/include/python3.8/longintrepr.h +0 -99
- package/include/python3.8/longobject.h +0 -242
- package/include/python3.8/marshal.h +0 -28
- package/include/python3.8/memoryobject.h +0 -72
- package/include/python3.8/methodobject.h +0 -131
- package/include/python3.8/modsupport.h +0 -248
- package/include/python3.8/moduleobject.h +0 -90
- package/include/python3.8/namespaceobject.h +0 -19
- package/include/python3.8/node.h +0 -48
- package/include/python3.8/object.h +0 -753
- package/include/python3.8/objimpl.h +0 -284
- package/include/python3.8/odictobject.h +0 -43
- package/include/python3.8/opcode.h +0 -148
- package/include/python3.8/osdefs.h +0 -51
- package/include/python3.8/osmodule.h +0 -17
- package/include/python3.8/parsetok.h +0 -110
- package/include/python3.8/patchlevel.h +0 -35
- package/include/python3.8/picklebufobject.h +0 -31
- package/include/python3.8/py_curses.h +0 -100
- package/include/python3.8/pyarena.h +0 -64
- package/include/python3.8/pycapsule.h +0 -59
- package/include/python3.8/pyconfig.h +0 -1665
- package/include/python3.8/pyctype.h +0 -39
- package/include/python3.8/pydebug.h +0 -40
- package/include/python3.8/pydtrace.h +0 -59
- package/include/python3.8/pydtrace_probes.h +0 -228
- package/include/python3.8/pyerrors.h +0 -335
- package/include/python3.8/pyexpat.h +0 -55
- package/include/python3.8/pyfpe.h +0 -12
- package/include/python3.8/pyhash.h +0 -145
- package/include/python3.8/pylifecycle.h +0 -75
- package/include/python3.8/pymacconfig.h +0 -102
- package/include/python3.8/pymacro.h +0 -106
- package/include/python3.8/pymath.h +0 -230
- package/include/python3.8/pymem.h +0 -150
- package/include/python3.8/pyport.h +0 -850
- package/include/python3.8/pystate.h +0 -136
- package/include/python3.8/pystrcmp.h +0 -23
- package/include/python3.8/pystrhex.h +0 -22
- package/include/python3.8/pystrtod.h +0 -45
- package/include/python3.8/pythonrun.h +0 -210
- package/include/python3.8/pythread.h +0 -161
- package/include/python3.8/pytime.h +0 -246
- package/include/python3.8/rangeobject.h +0 -27
- package/include/python3.8/setobject.h +0 -108
- package/include/python3.8/sliceobject.h +0 -65
- package/include/python3.8/structmember.h +0 -74
- package/include/python3.8/structseq.h +0 -49
- package/include/python3.8/symtable.h +0 -123
- package/include/python3.8/sysmodule.h +0 -41
- package/include/python3.8/token.h +0 -92
- package/include/python3.8/traceback.h +0 -28
- package/include/python3.8/tracemalloc.h +0 -38
- package/include/python3.8/tupleobject.h +0 -48
- package/include/python3.8/typeslots.h +0 -85
- package/include/python3.8/ucnhash.h +0 -36
- package/include/python3.8/unicodeobject.h +0 -1044
- package/include/python3.8/warnings.h +0 -67
- package/include/python3.8/weakrefobject.h +0 -86
- package/src/components/theme/ContactForm/ContactForm.stories.mdx +0 -39
|
@@ -3,21 +3,25 @@
|
|
|
3
3
|
* @module components/manage/Widgets/DatetimeWidget
|
|
4
4
|
*/
|
|
5
5
|
import React, { Component } from 'react';
|
|
6
|
+
import { compose } from 'redux';
|
|
6
7
|
import PropTypes from 'prop-types';
|
|
7
8
|
import { defineMessages, injectIntl } from 'react-intl';
|
|
8
|
-
import
|
|
9
|
-
import { SingleDatePicker } from 'react-dates';
|
|
10
|
-
import TimePicker from 'rc-time-picker';
|
|
9
|
+
import loadable from '@loadable/component';
|
|
11
10
|
import cx from 'classnames';
|
|
12
11
|
import { Icon, FormFieldWrapper } from '@plone/volto/components';
|
|
13
12
|
import { parseDateTime } from '@plone/volto/helpers';
|
|
13
|
+
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
14
|
+
|
|
14
15
|
import leftKey from '@plone/volto/icons/left-key.svg';
|
|
15
16
|
import rightKey from '@plone/volto/icons/right-key.svg';
|
|
16
17
|
import clearSVG from '@plone/volto/icons/clear.svg';
|
|
18
|
+
|
|
17
19
|
import 'rc-time-picker/assets/index.css';
|
|
18
20
|
import 'react-dates/initialize';
|
|
19
21
|
import 'react-dates/lib/css/_datepicker.css';
|
|
20
22
|
|
|
23
|
+
const TimePicker = loadable(() => import('rc-time-picker'));
|
|
24
|
+
|
|
21
25
|
const messages = defineMessages({
|
|
22
26
|
date: {
|
|
23
27
|
id: 'Date',
|
|
@@ -80,7 +84,7 @@ const defaultTimeDateOnly = {
|
|
|
80
84
|
* }
|
|
81
85
|
* ```
|
|
82
86
|
*/
|
|
83
|
-
class
|
|
87
|
+
export class DatetimeWidgetComponent extends Component {
|
|
84
88
|
/**
|
|
85
89
|
* Constructor
|
|
86
90
|
* @method constructor
|
|
@@ -89,17 +93,27 @@ class DatetimeWidget extends Component {
|
|
|
89
93
|
*/
|
|
90
94
|
constructor(props) {
|
|
91
95
|
super(props);
|
|
92
|
-
|
|
93
|
-
let datetime = parseDateTime(this.props.intl.locale, this.props.value);
|
|
96
|
+
const moment = props.moment.default;
|
|
94
97
|
|
|
95
98
|
this.state = {
|
|
96
99
|
focused: false,
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
// if passed value matches the construction time, we guess it's a default
|
|
101
|
+
isDefault:
|
|
102
|
+
parseDateTime(
|
|
103
|
+
this.props.intl.locale,
|
|
104
|
+
this.props.value,
|
|
105
|
+
)?.toISOString() === moment().utc().toISOString(),
|
|
100
106
|
};
|
|
101
107
|
}
|
|
102
108
|
|
|
109
|
+
getInternalValue() {
|
|
110
|
+
return parseDateTime(this.props.intl.locale, this.props.value);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
getDateOnly() {
|
|
114
|
+
return this.props.dateOnly || this.props.widget === 'date';
|
|
115
|
+
}
|
|
116
|
+
|
|
103
117
|
/**
|
|
104
118
|
* Update date storage
|
|
105
119
|
* @method onDateChange
|
|
@@ -107,26 +121,21 @@ class DatetimeWidget extends Component {
|
|
|
107
121
|
* @returns {undefined}
|
|
108
122
|
*/
|
|
109
123
|
onDateChange = (date) => {
|
|
110
|
-
if (date)
|
|
111
|
-
this.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}),
|
|
126
|
-
isDefault: false,
|
|
127
|
-
}),
|
|
128
|
-
() => this.onDateTimeChange(),
|
|
129
|
-
);
|
|
124
|
+
if (date) {
|
|
125
|
+
const moment = this.props.moment.default;
|
|
126
|
+
const isDateOnly = this.getDateOnly();
|
|
127
|
+
const base = (this.getInternalValue() || moment()).set({
|
|
128
|
+
year: date.year(),
|
|
129
|
+
month: date.month(),
|
|
130
|
+
date: date.date(),
|
|
131
|
+
...(isDateOnly ? defaultTimeDateOnly : {}),
|
|
132
|
+
});
|
|
133
|
+
const dateValue = isDateOnly
|
|
134
|
+
? base.format('YYYY-MM-DD')
|
|
135
|
+
: base.toISOString();
|
|
136
|
+
this.props.onChange(this.props.id, dateValue);
|
|
137
|
+
}
|
|
138
|
+
this.setState({ isDefault: false });
|
|
130
139
|
};
|
|
131
140
|
|
|
132
141
|
/**
|
|
@@ -136,45 +145,21 @@ class DatetimeWidget extends Component {
|
|
|
136
145
|
* @returns {undefined}
|
|
137
146
|
*/
|
|
138
147
|
onTimeChange = (time) => {
|
|
139
|
-
this.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
minutes: time.minutes(),
|
|
150
|
-
seconds: 0,
|
|
151
|
-
}),
|
|
152
|
-
isDefault: false,
|
|
153
|
-
}),
|
|
154
|
-
() => this.onDateTimeChange(),
|
|
155
|
-
);
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Update date storage
|
|
160
|
-
* @method onDateTimeChange
|
|
161
|
-
* @returns {undefined}
|
|
162
|
-
*/
|
|
163
|
-
onDateTimeChange = () => {
|
|
164
|
-
const dateValue = this.state.dateOnly
|
|
165
|
-
? this.state.datetime.format('YYYY-MM-DD')
|
|
166
|
-
: this.state.datetime.toISOString();
|
|
167
|
-
this.props.onChange(this.props.id, dateValue);
|
|
148
|
+
const moment = this.props.moment.default;
|
|
149
|
+
if (time) {
|
|
150
|
+
const base = (this.getInternalValue() || moment()).set({
|
|
151
|
+
hours: time.hours(),
|
|
152
|
+
minutes: time.minutes(),
|
|
153
|
+
seconds: 0,
|
|
154
|
+
});
|
|
155
|
+
const dateValue = base.toISOString();
|
|
156
|
+
this.props.onChange(this.props.id, dateValue);
|
|
157
|
+
}
|
|
168
158
|
};
|
|
169
159
|
|
|
170
160
|
onResetDates = () => {
|
|
171
|
-
this.setState(
|
|
172
|
-
|
|
173
|
-
datetime: null,
|
|
174
|
-
isDefault: false,
|
|
175
|
-
}),
|
|
176
|
-
this.props.onChange(this.props.id, null),
|
|
177
|
-
);
|
|
161
|
+
this.setState({ isDefault: false });
|
|
162
|
+
this.props.onChange(this.props.id, null);
|
|
178
163
|
};
|
|
179
164
|
|
|
180
165
|
/**
|
|
@@ -186,22 +171,25 @@ class DatetimeWidget extends Component {
|
|
|
186
171
|
onFocusChange = ({ focused }) => this.setState({ focused });
|
|
187
172
|
|
|
188
173
|
render() {
|
|
189
|
-
const { id, noPastDates, resettable, intl } = this.props;
|
|
190
|
-
const
|
|
174
|
+
const { id, noPastDates, resettable, intl, reactDates } = this.props;
|
|
175
|
+
const moment = this.props.moment.default;
|
|
176
|
+
const datetime = this.getInternalValue();
|
|
177
|
+
const dateOnly = this.getDateOnly();
|
|
178
|
+
const { SingleDatePicker } = reactDates;
|
|
191
179
|
|
|
192
180
|
return (
|
|
193
181
|
<FormFieldWrapper {...this.props}>
|
|
194
182
|
<div className="date-time-widget-wrapper">
|
|
195
183
|
<div
|
|
196
184
|
className={cx('ui input date-input', {
|
|
197
|
-
'default-date': isDefault,
|
|
185
|
+
'default-date': this.state.isDefault,
|
|
198
186
|
})}
|
|
199
187
|
>
|
|
200
188
|
<SingleDatePicker
|
|
201
189
|
date={datetime}
|
|
202
190
|
disabled={this.props.isDisabled}
|
|
203
191
|
onDateChange={this.onDateChange}
|
|
204
|
-
focused={focused}
|
|
192
|
+
focused={this.state.focused}
|
|
205
193
|
numberOfMonths={1}
|
|
206
194
|
{...(noPastDates ? {} : { isOutsideRange: () => false })}
|
|
207
195
|
onFocusChange={this.onFocusChange}
|
|
@@ -213,10 +201,10 @@ class DatetimeWidget extends Component {
|
|
|
213
201
|
placeholder={intl.formatMessage(messages.date)}
|
|
214
202
|
/>
|
|
215
203
|
</div>
|
|
216
|
-
{!
|
|
204
|
+
{!dateOnly && (
|
|
217
205
|
<div
|
|
218
206
|
className={cx('ui input time-input', {
|
|
219
|
-
'default-date': isDefault,
|
|
207
|
+
'default-date': this.state.isDefault,
|
|
220
208
|
})}
|
|
221
209
|
>
|
|
222
210
|
<TimePicker
|
|
@@ -255,7 +243,7 @@ class DatetimeWidget extends Component {
|
|
|
255
243
|
* @property {Object} propTypes Property types.
|
|
256
244
|
* @static
|
|
257
245
|
*/
|
|
258
|
-
|
|
246
|
+
DatetimeWidgetComponent.propTypes = {
|
|
259
247
|
id: PropTypes.string.isRequired,
|
|
260
248
|
title: PropTypes.string.isRequired,
|
|
261
249
|
description: PropTypes.string,
|
|
@@ -274,7 +262,7 @@ DatetimeWidget.propTypes = {
|
|
|
274
262
|
* @property {Object} defaultProps Default properties.
|
|
275
263
|
* @static
|
|
276
264
|
*/
|
|
277
|
-
|
|
265
|
+
DatetimeWidgetComponent.defaultProps = {
|
|
278
266
|
description: null,
|
|
279
267
|
required: false,
|
|
280
268
|
error: [],
|
|
@@ -284,4 +272,7 @@ DatetimeWidget.defaultProps = {
|
|
|
284
272
|
resettable: true,
|
|
285
273
|
};
|
|
286
274
|
|
|
287
|
-
export default
|
|
275
|
+
export default compose(
|
|
276
|
+
injectLazyLibs(['reactDates', 'moment']),
|
|
277
|
+
injectIntl,
|
|
278
|
+
)(DatetimeWidgetComponent);
|
|
@@ -1,32 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { DatetimeWidgetComponent } from './DatetimeWidget';
|
|
2
3
|
import DatetimeWidget from './DatetimeWidget';
|
|
3
|
-
import
|
|
4
|
+
import WidgetStory from './story';
|
|
4
5
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<Wrapper location={{ pathname: '/folder2/folder21/doc212' }}>
|
|
10
|
-
<div className="ui segment form attached" style={{ width: '400px' }}>
|
|
11
|
-
<DatetimeWidget
|
|
12
|
-
{...args}
|
|
13
|
-
id="field"
|
|
14
|
-
title="Datetime"
|
|
15
|
-
block="testBlock"
|
|
16
|
-
value={value}
|
|
17
|
-
onChange={onChange}
|
|
18
|
-
/>
|
|
19
|
-
</div>
|
|
20
|
-
<pre>Value: {JSON.stringify(value, null, 4)}</pre>
|
|
21
|
-
</Wrapper>
|
|
22
|
-
);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const Datetime = DatetimeWidgetComponent.bind({});
|
|
6
|
+
export const Datetime = WidgetStory.bind({
|
|
7
|
+
props: { id: 'datetime', title: 'Datetime', block: 'block' },
|
|
8
|
+
widget: DatetimeWidget,
|
|
9
|
+
});
|
|
26
10
|
|
|
27
11
|
export default {
|
|
28
12
|
title: 'Widgets/Datetime',
|
|
29
|
-
component:
|
|
13
|
+
component: DatetimeWidgetComponent,
|
|
30
14
|
decorators: [
|
|
31
15
|
(Story) => (
|
|
32
16
|
<div className="ui segment form attached" style={{ width: '400px' }}>
|
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
import moment from 'moment';
|
|
2
|
-
import TimePicker from 'rc-time-picker';
|
|
3
2
|
import React from 'react';
|
|
4
3
|
import { Provider } from 'react-intl-redux';
|
|
5
|
-
import renderer from 'react-test-renderer';
|
|
6
4
|
import configureStore from 'redux-mock-store';
|
|
7
5
|
import DatetimeWidget from './DatetimeWidget';
|
|
6
|
+
import { waitFor, render, screen } from '@testing-library/react';
|
|
8
7
|
|
|
9
8
|
const mockStore = configureStore();
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
jest.mock('@plone/volto/helpers/Loadable/Loadable');
|
|
11
|
+
beforeAll(
|
|
12
|
+
async () =>
|
|
13
|
+
await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
test('renders a datetime widget component', async () => {
|
|
12
17
|
const store = mockStore({
|
|
13
18
|
intl: {
|
|
14
19
|
locale: 'en',
|
|
15
20
|
messages: {},
|
|
16
21
|
},
|
|
17
22
|
});
|
|
18
|
-
const
|
|
23
|
+
const { container } = render(
|
|
19
24
|
<Provider store={store}>
|
|
20
25
|
<DatetimeWidget
|
|
21
26
|
id="my-field"
|
|
@@ -26,31 +31,28 @@ test('renders a datetime widget component', () => {
|
|
|
26
31
|
/>
|
|
27
32
|
</Provider>,
|
|
28
33
|
);
|
|
29
|
-
|
|
30
|
-
expect(
|
|
34
|
+
await waitFor(() => screen.getByText(/My field/));
|
|
35
|
+
expect(container).toMatchSnapshot();
|
|
31
36
|
});
|
|
32
37
|
|
|
33
|
-
test('datetime widget converts UTC date and adapt to local datetime', () => {
|
|
38
|
+
test('datetime widget converts UTC date and adapt to local datetime', async () => {
|
|
34
39
|
const store = mockStore({
|
|
35
40
|
intl: {
|
|
36
41
|
locale: 'en',
|
|
37
42
|
messages: {},
|
|
38
43
|
},
|
|
39
44
|
});
|
|
40
|
-
const
|
|
45
|
+
const date = '2020-02-10T15:01:00.000Z';
|
|
46
|
+
const { container } = render(
|
|
41
47
|
<Provider store={store}>
|
|
42
48
|
<DatetimeWidget
|
|
43
49
|
id="my-field"
|
|
44
50
|
title="My field"
|
|
45
51
|
onChange={() => {}}
|
|
46
|
-
value={
|
|
52
|
+
value={date}
|
|
47
53
|
/>
|
|
48
54
|
</Provider>,
|
|
49
55
|
);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
expect(componentTimeInput.props.defaultValue.toISOString()).toBe(
|
|
54
|
-
moment('2020-02-10T15:01:00').utc().toISOString(),
|
|
55
|
-
);
|
|
56
|
+
await waitFor(() => screen.getByText(/My field/));
|
|
57
|
+
expect(container).toMatchSnapshot();
|
|
56
58
|
});
|
|
@@ -1,28 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import EmailWidget from './EmailWidget';
|
|
3
|
-
import
|
|
3
|
+
import WidgetStory from './story';
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<Wrapper location={{ pathname: '/folder2/folder21/doc212' }}>
|
|
10
|
-
<div className="ui segment form attached" style={{ width: '400px' }}>
|
|
11
|
-
<EmailWidget
|
|
12
|
-
{...args}
|
|
13
|
-
id="field"
|
|
14
|
-
title="Email"
|
|
15
|
-
block="testBlock"
|
|
16
|
-
value={value}
|
|
17
|
-
onChange={onChange}
|
|
18
|
-
/>
|
|
19
|
-
</div>
|
|
20
|
-
<pre>Value: {JSON.stringify(value, null, 4)}</pre>
|
|
21
|
-
</Wrapper>
|
|
22
|
-
);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const Email = EmailWidgetComponent.bind({});
|
|
5
|
+
export const Email = WidgetStory.bind({
|
|
6
|
+
props: { id: 'email', title: 'Email', block: 'block' },
|
|
7
|
+
widget: EmailWidget,
|
|
8
|
+
});
|
|
26
9
|
|
|
27
10
|
export default {
|
|
28
11
|
title: 'Widgets/Email',
|
|
@@ -1,28 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import FileWidget from './FileWidget';
|
|
3
|
-
import
|
|
3
|
+
import WidgetStory from './story';
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<Wrapper location={{ pathname: '/folder2/folder21/doc212' }}>
|
|
10
|
-
<div className="ui segment form attached" style={{ width: '400px' }}>
|
|
11
|
-
<FileWidget
|
|
12
|
-
{...args}
|
|
13
|
-
id="field"
|
|
14
|
-
title="File"
|
|
15
|
-
block="testBlock"
|
|
16
|
-
value={value}
|
|
17
|
-
onChange={onChange}
|
|
18
|
-
/>
|
|
19
|
-
</div>
|
|
20
|
-
<pre>Value: {JSON.stringify(value, null, 4)}</pre>
|
|
21
|
-
</Wrapper>
|
|
22
|
-
);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const File = FileWidgetComponent.bind({});
|
|
5
|
+
export const File = WidgetStory.bind({
|
|
6
|
+
props: { id: 'file', title: 'File', block: 'block' },
|
|
7
|
+
widget: FileWidget,
|
|
8
|
+
});
|
|
26
9
|
|
|
27
10
|
export default {
|
|
28
11
|
title: 'Widgets/File',
|
|
@@ -1,29 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import NumberWidget from './NumberWidget';
|
|
3
|
-
import
|
|
3
|
+
import WidgetStory from './story';
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<Wrapper location={{ pathname: '/folder2/folder21/doc212' }}>
|
|
10
|
-
<div className="ui segment form attached" style={{ width: '400px' }}>
|
|
11
|
-
<NumberWidget
|
|
12
|
-
{...args}
|
|
13
|
-
id="field"
|
|
14
|
-
title="Number"
|
|
15
|
-
block="testBlock"
|
|
16
|
-
value={value}
|
|
17
|
-
onChange={onChange}
|
|
18
|
-
default={10}
|
|
19
|
-
/>
|
|
20
|
-
</div>
|
|
21
|
-
<pre>Value: {JSON.stringify(value, null, 4)}</pre>
|
|
22
|
-
</Wrapper>
|
|
23
|
-
);
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export const Number = NumberWidgetComponent.bind({});
|
|
5
|
+
export const Number = WidgetStory.bind({
|
|
6
|
+
props: { id: 'number', title: 'Number', block: 'block' },
|
|
7
|
+
widget: NumberWidget,
|
|
8
|
+
});
|
|
27
9
|
|
|
28
10
|
export default {
|
|
29
11
|
title: 'Widgets/Number',
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import ObjectBrowserWidgetDefault, {
|
|
2
2
|
ObjectBrowserWidgetComponent as OBC,
|
|
3
3
|
} from './ObjectBrowserWidget';
|
|
4
|
-
import Wrapper from '@plone/volto/storybook';
|
|
4
|
+
import Wrapper, { FormUndoWrapper } from '@plone/volto/storybook';
|
|
5
5
|
import React from 'react';
|
|
6
|
-
import { injectIntl } from 'react-intl';
|
|
7
6
|
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
|
|
8
7
|
|
|
9
8
|
export const searchResults = {
|
|
@@ -157,43 +156,40 @@ const customStore = {
|
|
|
157
156
|
},
|
|
158
157
|
};
|
|
159
158
|
|
|
160
|
-
const ObjectBrowserWidgetComponent = (args) => {
|
|
161
|
-
const IntlWrappedComponent = injectIntl(OBC);
|
|
162
|
-
return (
|
|
163
|
-
<Wrapper>
|
|
164
|
-
<IntlWrappedComponent {...args} search={searchResults} />
|
|
165
|
-
</Wrapper>
|
|
166
|
-
);
|
|
167
|
-
};
|
|
168
|
-
|
|
169
159
|
const ObjectBrowserWidget = (args) => {
|
|
170
|
-
const [value, setValue] = React.useState([]);
|
|
171
|
-
const onChange = (block, value) => setValue(value);
|
|
172
|
-
|
|
173
160
|
return (
|
|
174
161
|
<Wrapper
|
|
175
162
|
location={{ pathname: '/folder2/folder21/doc212' }}
|
|
176
163
|
customStore={customStore}
|
|
177
164
|
>
|
|
178
|
-
<
|
|
179
|
-
{
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
165
|
+
<FormUndoWrapper initialState={{ value: undefined }} showControls={true}>
|
|
166
|
+
{({ state, onChange }) => (
|
|
167
|
+
<>
|
|
168
|
+
<ObjectBrowserWidgetDefault
|
|
169
|
+
{...args}
|
|
170
|
+
id="objectBrowser"
|
|
171
|
+
title="Object Browser"
|
|
172
|
+
block="testBlock"
|
|
173
|
+
value={state.value}
|
|
174
|
+
onChange={(block, value) => onChange({ value })}
|
|
175
|
+
/>
|
|
176
|
+
<pre>
|
|
177
|
+
Value:
|
|
178
|
+
{state.value?.length > 0 && (
|
|
179
|
+
<UniversalLink item={state.value[0]}>
|
|
180
|
+
{state.value[0]['@id']}
|
|
181
|
+
</UniversalLink>
|
|
182
|
+
)}
|
|
183
|
+
</pre>
|
|
184
|
+
</>
|
|
185
|
+
)}
|
|
186
|
+
</FormUndoWrapper>
|
|
191
187
|
</Wrapper>
|
|
192
188
|
);
|
|
193
189
|
};
|
|
194
190
|
|
|
195
191
|
export default {
|
|
196
|
-
title: '
|
|
192
|
+
title: 'Widgets/Object Browser',
|
|
197
193
|
component: OBC,
|
|
198
194
|
decorators: [
|
|
199
195
|
(Story) => (
|
|
@@ -206,9 +202,5 @@ export default {
|
|
|
206
202
|
// subcomponents: { ArgsTable },
|
|
207
203
|
};
|
|
208
204
|
|
|
209
|
-
export const Renderer = () => (
|
|
210
|
-
<ObjectBrowserWidgetComponent search={searchResults} />
|
|
211
|
-
);
|
|
212
|
-
|
|
213
205
|
export const Connected = () => <ObjectBrowserWidget />;
|
|
214
206
|
export const SingleElement = () => <ObjectBrowserWidget mode="link" />;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ObjectListWidgetDefault from './ObjectListWidget';
|
|
2
|
-
import Wrapper from '@plone/volto/storybook';
|
|
2
|
+
import Wrapper, { FormUndoWrapper } from '@plone/volto/storybook';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { searchResults } from './ObjectBrowserWidget.stories';
|
|
5
5
|
|
|
@@ -108,55 +108,55 @@ const ObjectListWidgetComponent = ({
|
|
|
108
108
|
enableSchemaExtender,
|
|
109
109
|
...args
|
|
110
110
|
}) => {
|
|
111
|
-
const [value, setValue] = React.useState([]);
|
|
112
|
-
const onChange = (block, value) => setValue(value);
|
|
113
|
-
|
|
114
111
|
return (
|
|
115
112
|
<Wrapper
|
|
116
113
|
location={{ pathname: '/folder2/folder21/doc212' }}
|
|
117
114
|
customStore={customStore}
|
|
118
115
|
>
|
|
119
|
-
<
|
|
120
|
-
{
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
data
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
116
|
+
<FormUndoWrapper initialState={{ value: undefined }} showControls={true}>
|
|
117
|
+
{({ state, onChange }) => (
|
|
118
|
+
<div className="ui segment form attached" style={{ width: '400px' }}>
|
|
119
|
+
{children}
|
|
120
|
+
<ObjectListWidgetDefault
|
|
121
|
+
{...args}
|
|
122
|
+
id="SliderItem"
|
|
123
|
+
title="Slider Item"
|
|
124
|
+
block="testBlock"
|
|
125
|
+
value={state.value}
|
|
126
|
+
onChange={(block, value) => onChange({ value })}
|
|
127
|
+
schemaExtender={
|
|
128
|
+
enableSchemaExtender &&
|
|
129
|
+
((schema, data, intl) => {
|
|
130
|
+
const finalSchema =
|
|
131
|
+
data?.href?.[0]?.['@id'] === '/image'
|
|
132
|
+
? {
|
|
133
|
+
...schema,
|
|
134
|
+
fieldsets: [
|
|
135
|
+
{
|
|
136
|
+
...schema.fieldsets[0],
|
|
137
|
+
fields: [
|
|
138
|
+
...schema.fieldsets[0].fields,
|
|
139
|
+
...secondarySchema.fieldsets[0].fields,
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
...schema.fieldsets.slice(1),
|
|
143
|
+
...secondarySchema.fieldsets.slice(1),
|
|
141
144
|
],
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
<strong>Resulting value</strong>
|
|
158
|
-
<pre>{JSON.stringify(value, null, 4)}</pre>
|
|
159
|
-
</div>
|
|
145
|
+
properties: {
|
|
146
|
+
...schema.properties,
|
|
147
|
+
...secondarySchema.properties,
|
|
148
|
+
},
|
|
149
|
+
}
|
|
150
|
+
: schema;
|
|
151
|
+
return finalSchema;
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
/>
|
|
155
|
+
<hr />
|
|
156
|
+
<pre>Value: {JSON.stringify(state.value, null, 4)}</pre>
|
|
157
|
+
</div>
|
|
158
|
+
)}
|
|
159
|
+
</FormUndoWrapper>
|
|
160
160
|
</Wrapper>
|
|
161
161
|
);
|
|
162
162
|
};
|