mirror of
https://github.com/strapi/strapi.git
synced 2025-11-01 02:16:03 +00:00
erge branch 'develop' into features/webhooks
This commit is contained in:
commit
14d95f3de1
@ -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}"
|
||||
```
|
||||
|
||||
@ -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;
|
||||
@ -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 '-';
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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}>
|
||||
|
||||
@ -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;
|
||||
@ -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 };
|
||||
|
||||
@ -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} />}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user