diff --git a/docs/3.0.0-beta.x/plugins/users-permissions.md b/docs/3.0.0-beta.x/plugins/users-permissions.md index a2ab423ec2..a07113970a 100644 --- a/docs/3.0.0-beta.x/plugins/users-permissions.md +++ b/docs/3.0.0-beta.x/plugins/users-permissions.md @@ -437,7 +437,9 @@ You can update these template in the **Email Templates** tab in the admin panel. - `URL` is the Strapi backend URL that confirm the code (by default `/auth/email-confirmation`). ## Security configuration -JWT tokens can be verified and trusted because the information is digitally signed. To sign a token a *secret* is required. By default Strapi generates one that is stored in `./your-app/extensions/users-permissions/config/jwt.json`. This is useful during development but for security reasons it is **recommended** to set a custom token via an environment variable `JWT_SECRET` when deploying to production. It is also possible to modify `jwt.json` file to accept `JWT_TOKEN` automatically by doing following ([docs](https://strapi.io/documentation/3.0.0-beta.x/concepts/configurations.html#dynamic-configurations)). + +JWT tokens can be verified and trusted because the information is digitally signed. To sign a token a _secret_ is required. By default Strapi generates one that is stored in `./your-app/extensions/users-permissions/config/jwt.json`. This is useful during development but for security reasons it is **recommended** to set a custom token via an environment variable `JWT_SECRET` when deploying to production. It is also possible to modify `jwt.json` file to accept `JWT_TOKEN` automatically by doing following ([docs](https://strapi.io/documentation/3.0.0-beta.x/concepts/configurations.html#dynamic-configurations)). + ``` "jwtSecret": "${process.env.JWT_SECRET}" ``` diff --git a/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/DATE_FORMATS.js b/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/DATE_FORMATS.js new file mode 100644 index 0000000000..4896778763 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/DATE_FORMATS.js @@ -0,0 +1,8 @@ +const DATE_FORMATS = { + date: 'dddd, MMMM Do YYYY', + datetime: 'dddd, MMMM Do YYYY HH:mm', + time: 'HH:mm A', + timestamp: 'dddd, MMMM Do YYYY', +}; + +export default DATE_FORMATS; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row.js b/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row.js index 07379b7f58..3249be5dc4 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/CustomTable/Row.js @@ -5,11 +5,12 @@ import { get, isEmpty, isNull, isObject, toLower, toString } from 'lodash'; import moment from 'moment'; import { IcoContainer, useGlobalContext } from 'strapi-helper-plugin'; import useListView from '../../hooks/useListView'; - import CustomInputCheckbox from '../CustomInputCheckbox'; import MediaPreviewList from '../MediaPreviewList'; - import { ActionContainer, Truncate, Truncated } from './styledComponents'; +import DATE_FORMATS from './DATE_FORMATS'; + +const dateToUtcTime = date => moment.parseZone(date).utc(); const getDisplayedValue = (type, value, name) => { switch (toLower(type)) { @@ -28,7 +29,6 @@ const getDisplayedValue = (type, value, name) => { case 'boolean': return value !== null ? toString(value) : '-'; case 'date': - case 'time': case 'datetime': case 'timestamp': { if (value == null) { @@ -40,10 +40,7 @@ const getDisplayedValue = (type, value, name) => { ? JSON.stringify(value) : value; - return moment - .parseZone(date) - .utc() - .format('dddd, MMMM Do YYYY'); + return dateToUtcTime(date).format(DATE_FORMATS[type]); } case 'password': return '••••••••'; @@ -51,6 +48,16 @@ const getDisplayedValue = (type, value, name) => { case 'file': case 'files': return value; + case 'time': { + const [hour, minute, second] = value.split(':'); + const timeObj = { + hour, + minute, + second, + }; + const date = moment().set(timeObj); + return date.format(DATE_FORMATS.time); + } default: return '-'; } diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/reducer.js b/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/reducer.js index 951311a0bd..5ac49fe907 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/reducer.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/reducer.js @@ -18,7 +18,7 @@ function reducer(state, action) { return state .updateIn(['modifiedData', ...action.keys], () => { - if (action.value._isAMomentObject === true) { + if (action.value && action.value._isAMomentObject === true) { return moment(action.value, 'YYYY-MM-DD HH:mm:ss').format(); } return action.value; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/Input.js b/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/Input.js index 9b9de53fc9..ea87f470f5 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/Input.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/Input.js @@ -5,28 +5,34 @@ import React, { memo } from 'react'; import PropTypes from 'prop-types'; + +import { DateTime } from '@buffetjs/custom'; import { - InputDate, - InputNumber, - InputSelect, + DatePicker, InputText, -} from 'strapi-helper-plugin'; + InputNumber, + Select, + TimePicker, +} from '@buffetjs/core'; import { InputWrapperDate } from './components'; const getInputType = attrType => { switch (attrType) { case 'boolean': - return InputSelect; + return Select; case 'date': - case 'datetime': case 'timestamp': case 'timestampUpdate': - return InputDate; + return DatePicker; + case 'datetime': + return DateTime; case 'integer': case 'biginteger': case 'decimal': case 'float': return InputNumber; + case 'time': + return TimePicker; default: return InputText; } @@ -34,10 +40,18 @@ const getInputType = attrType => { function Input({ type, ...rest }) { const Component = getInputType(type); - const style = { width: '210px', paddingTop: '4px' }; + let style = type !== 'time' ? { width: '210px', paddingTop: '4px' } : {}; + + if (['integer', 'biginteger', 'float', 'decimal'].includes(type)) { + style = { marginRight: '20px' }; + } const styles = type === 'boolean' ? { minWidth: '100px', maxWidth: '200px' } : style; - const wrapperStyle = type == 'boolean' ? { marginRight: '20px' } : {}; + const wrapperStyle = + type == 'boolean' || + ['date', 'timestamp', 'time', 'datetime'].includes(type) + ? { marginRight: '20px' } + : { marginRight: '10px' }; return ( diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/Option.js b/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/Option.js new file mode 100644 index 0000000000..b5b324dfee --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/Option.js @@ -0,0 +1,18 @@ +import React from 'react'; +import { FormattedMessage } from 'react-intl'; +import PropTypes from 'prop-types'; + +const Option = ({ id, value }) => { + return ( + + {msg => } + + ); +}; + +Option.propTypes = { + id: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, +}; + +export default Option; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/components.js b/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/components.js index 4d028d5924..905d5e2ced 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/components.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/components.js @@ -53,39 +53,27 @@ const Button = styled.button` const InputWrapperDate = styled.div` margin-right: 10px; + span { + left: 5px; + } + .rc-input-number-handler-wrap { + right: -5px !important; + } + .rc-input-number-input-wrap { + max-width: 210px; + overflow: visible; + } + > div { + width: 210px; + } + ${({ type }) => { - if ( - type.includes('date') || - type === 'timestampUpdate' || - type === 'timestamp' - ) { - return css` - position: relative; - &:before { - content: '\f073'; - position: absolute; - left: 6px; - top: 1px; - width: 32px; - height: 32px; - border-radius: 3px 0px 0px 3px; - background: #fafafb; - color: #b3b5b9; - text-align: center; - font-family: 'FontAwesome'; - font-size: 1.4rem; - line-height: 32px; - z-index: 999; - -webkit-font-smoothing: none; - } - input { - width: 100%; - padding-left: 42px; - box-shadow: 0px 1px 1px rgba(104, 118, 142, 0.05); - &:focus { - outline: none; - } - } + if (type === 'datetime') { + return ` + > div { + width: 300px; + } + `; } }} @@ -103,5 +91,4 @@ const Input = styled.input` font-family: 'Lato' !important; box-shadow: 0px 1px 1px rgba(104, 118, 142, 0.05); `; - export { Button, InputWrapper, Wrapper, InputWrapperDate, Input }; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/index.js b/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/index.js index 4ff4e44f69..21c0bb39b0 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/index.js @@ -1,10 +1,10 @@ import React, { memo } from 'react'; import { get, isEmpty } from 'lodash'; import PropTypes from 'prop-types'; - -import { InputSelect } from 'strapi-helper-plugin'; +import { Select } from '@buffetjs/core'; import { Button, InputWrapper, Wrapper } from './components'; import Input from './Input'; +import Option from './Option'; import getFilters from './utils'; const styles = { @@ -46,7 +46,7 @@ function FilterPickerOption({ isRemoveButton onClick={() => onRemoveFilter(index)} /> - { // Change the attribute onChange(e); @@ -55,13 +55,15 @@ function FilterPickerOption({ }} name={`${index}.name`} value={get(modifiedData, [index, 'name'], '')} - selectOptions={allowedAttributes.map(attr => attr.name)} + options={allowedAttributes.map(attr => attr.name)} style={styles.select} /> - ( +