erge branch 'develop' into features/webhooks

This commit is contained in:
Alexandre Bodin 2020-01-13 12:22:21 +01:00
commit 14d95f3de1
8 changed files with 96 additions and 58 deletions

View File

@ -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}"
```

View File

@ -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;

View File

@ -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 '-';
}

View File

@ -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;

View File

@ -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 (
<InputWrapperDate type={type || 'text'} style={wrapperStyle}>

View File

@ -0,0 +1,18 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
const Option = ({ id, value }) => {
return (
<FormattedMessage id={id}>
{msg => <option value={value}>{msg}</option>}
</FormattedMessage>
);
};
Option.propTypes = {
id: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
};
export default Option;

View File

@ -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 };

View File

@ -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)}
/>
<InputSelect
<Select
onChange={e => {
// 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}
/>
<InputSelect
<Select
onChange={onChange}
name={`${index}.filter`}
selectOptions={filtersOptions}
options={filtersOptions.map(option => (
<Option {...option} key={option.value} />
))}
style={styles.selectMiddle}
value={get(modifiedData, [index, 'filter'], '')}
/>
@ -69,7 +71,7 @@ function FilterPickerOption({
type={type}
name={`${index}.value`}
value={get(modifiedData, [index, 'value'], '')}
selectOptions={['true', 'false']}
options={['true', 'false']}
onChange={onChange}
/>
{showAddButton && <Button type="button" onClick={onClickAddFilter} />}