Merge branch 'feature/upload' of github.com:strapi/strapi into feature/upload

This commit is contained in:
Jim Laurie 2018-03-06 16:52:29 +01:00
commit 5cbfa32d48
24 changed files with 112 additions and 72 deletions

View File

@ -104,7 +104,7 @@
"components.Input.error.custom-error": "{errorMessage} ",
"components.ListRow.empty": "There is no data to be shown.",
"notification.error": "An error occurred",
"Users & Permissions": "Users & Permissions",

View File

@ -111,7 +111,7 @@
"Auth & Permissions": "認證 & 權限",
"Content Manager": "內容管理",
"Content Type Builder": "建資料結構",
"Content Type Builder": "立和更新資料結構",
"Settings Manager": "管理設定",
"Email": "Email",
"Password": "密碼",

View File

@ -63,6 +63,7 @@
.addonFocus {
border-color: #78caff;
border-right: 0;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
}
.invalidSearch {

View File

@ -27,7 +27,7 @@ class InputSelectWithErrors extends React.Component {
this.setState({ errors });
}
if (isEmpty(this.props.value) && this.props.validations.required) {
if (isEmpty(this.props.value) && this.props.validations.required === true) {
const target = {
type: 'select',
name: this.props.name,

View File

@ -7,8 +7,10 @@ import cn from 'classnames';
import styles from './styles.scss';
function InputText(props) {
const placeholder = isEmpty(props.placeholder) ? 'app.utils.placeholder.defaultMessage' : props.placeholder;
return (
<FormattedMessage id={props.placeholder} defaultMessage={props.placeholder}>
<FormattedMessage id={placeholder} defaultMessage={placeholder}>
{(message) => (
<input
autoFocus={props.autoFocus}
@ -32,7 +34,7 @@ function InputText(props) {
/>
)}
</FormattedMessage>
)
);
}
InputText.defaultProps = {

View File

@ -11,8 +11,8 @@
"containers.Edit.reset": "重設",
"containers.Edit.returnList": "回到清單",
"containers.List.addAnEntry": "增加新的 {entity}",
"containers.List.pluginHeaderDescription": "找到 {label} 個進入點",
"containers.List.pluginHeaderDescription.singular": "找到 {label} 個進入點",
"containers.List.pluginHeaderDescription": "找到 {label} 筆資料",
"containers.List.pluginHeaderDescription.singular": "找到 {label} 筆資料",
"components.LimitSelect.itemsPerPage": "每個頁面檔案數量",
"containers.List.errorFetchRecords": "錯誤",
@ -52,5 +52,5 @@
"popUpWarning.button.cancel": "取消",
"popUpWarning.button.confirm": "確認",
"popUpWarning.title": "請確認",
"popUpWarning.bodyMessage.contentType.delete": "您確定要刪除這個進入點嗎?"
"popUpWarning.bodyMessage.contentType.delete": "您確定要刪除這筆資料嗎?"
}

View File

@ -76,7 +76,7 @@ function validate(value, validations) {
}
break;
case 'required':
if (value.length === 0) {
if (validationValue === true && value.length === 0) {
errors.push({ id: 'content-manager.error.validation.required' });
}
break;

View File

@ -14,6 +14,7 @@ import {
findIndex,
filter,
get,
has,
includes,
isEmpty,
isUndefined,
@ -455,18 +456,27 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
}
}
renderModalBodyChooseAttributes = () => (
map(forms.attributesDisplay.items, (attribute, key) => (
<AttributeCard
key={key}
attribute={attribute}
autoFocus={key === 0}
routePath={this.props.routePath}
handleClick={this.goToAttributeTypeView}
tabIndex={key}
/>
))
)
renderModalBodyChooseAttributes = () => {
const attributesDisplay = forms.attributesDisplay.items;
// Don't display the media field if the upload plugin isn't installed
if (!has(this.context.plugins.toJS(), 'upload')) {
attributesDisplay.splice(8, 1);
}
return (
map(attributesDisplay, (attribute, key) => (
<AttributeCard
key={key}
attribute={attribute}
autoFocus={key === 0}
routePath={this.props.routePath}
handleClick={this.goToAttributeTypeView}
tabIndex={key}
/>
))
);
}
testContentType = (contentTypeName, cbSuccess, successData, cbFail, failData) => {
// Check if the content type is in the localStorage (not saved) to prevent request error

View File

@ -151,8 +151,8 @@
"popUpWarning.bodyMessage.contentType.delete": "您確定要刪除這個資料結構嗎?",
"popUpWarning.bodyMessage.attribute.delete": "您確定要刪除這個欄位嗎?",
"table.contentType.title.plural": "可用資料結構",
"table.contentType.title.singular": "可用資料結構",
"table.contentType.title.plural": "資料結構",
"table.contentType.title.singular": "資料結構",
"table.contentType.head.name": "名稱",
"table.contentType.head.description": "說明",
"table.contentType.head.fields": "欄位",

View File

@ -136,8 +136,8 @@
"list.languages.default.languages": "預設語言",
"list.languages.set.languages": "設為預設",
"list.databases.button.label": "增加新的連線",
"list.databases.title.singular": "個環境連線",
"list.databases.title.plural": "個環境連線",
"list.databases.title.singular": "個環境連線",
"list.databases.title.plural": "個環境連線",
"popUpWarning.title": "請確認",
"popUpWarning.databases.danger.message":

View File

@ -19,6 +19,6 @@
.subFormWrapper {
margin-bottom: 14px;
padding: 5px 30px 0 30px;
padding: 23px 30px 0 30px;
background-color: #FAFAFB;
}

View File

@ -1,6 +1,6 @@
{
"archive": ["rar", "zip"],
"code": ["js", "json", "rb", "erb", "txt", "css", "scss", "html", "jsx"],
"code": ["js", "json", "rb", "erb", "txt", "css", "scss", "html", "jsx", "svg"],
"img": ["jpg", "jpeg", "png", "gif", "ico"],
"pdf": ["pdf"],
"powerpoint": ["ppt", "key", "xls"],

View File

@ -40,7 +40,7 @@ function FileIcon({ fileType }) {
className={(cn(
styles.fileIconContainer,
iconType === 'file-pdf-o' && styles.pdf,
iconType === 'file-zip-o' && styles.zip,
iconType === 'file-archive-o' && styles.zip,
iconType === 'file-image-o' && styles.image,
iconType === 'file-video-o' && styles.video,
iconType === 'file-code-o' && styles.code,

View File

@ -1,9 +1,10 @@
.fileIconContainer {
font-size: 20px;
color: #BDBFC2;
}
.image {
color: #FFA35C;
color: #8AA066;
}
.pdf {
@ -15,9 +16,9 @@
}
.zip {
color: #C29357;
color: #715A31;
}
.code {
color: #BDBFC2;
color: #515A6D;
}

View File

@ -100,7 +100,7 @@
}
.truncate {
overflow-x: hidden;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

View File

@ -41,6 +41,7 @@ export function* submit() {
yield call(request, requestURL, { method: 'PUT', body });
// Update reducer with optimisticResponse
strapi.notification.success('upload.notification.config.success');
yield put(submitSucceeded(body));
} catch(err) {
console.log('err', err);

View File

@ -28,7 +28,7 @@
"PluginInputFile.text": "Drag & drop your files into this area or {link} from a file to upload",
"PluginInputFile.link": "browse",
"notification.delete.success": "The file has been deleted",
"notification.dropFile.success": "Your file has been uploaded",
"notification.dropFiles.success": "{number} files have been uploaded"

View File

@ -7,7 +7,7 @@
"EditForm.Input.select.inputDescription": "Files can either be uploaded on your server or on external providers.",
"EditForm.Input.toggle.label": "Enable file upload",
"EmptyLi.message": "There is no uploaded files",
"EmptyLi.message": "There are no uploaded files",
"EntriesNumber.number": "{number} file found",
"EntriesNumber.number.plural": "{number} files found",
@ -29,6 +29,7 @@
"PluginInputFile.link": "browse",
"PluginInputFile.loading": "Your files are being uploaded",
"notification.config.success": "The settings has been updated",
"notification.delete.success": "The file has been deleted",
"notification.dropFile.success": "Your file has been uploaded",
"notification.dropFiles.success": "{number} files have been uploaded"

View File

@ -59,42 +59,51 @@ CREATE TABLE ${quote}upload_file_morph${quote} (
name: 'upload'
});
fs.readdir(path.join(strapi.config.appPath, 'plugins', 'upload', 'node_modules'), async (err, node_modules) => {
// get all upload provider
const uploads = _.filter(node_modules, (node_module) => {
return _.startsWith(node_module, ('strapi-upload'));
});
const loadProviders = (basePath, cb) => {
fs.readdir(path.join(basePath, 'node_modules'), async (err, node_modules) => {
// get all upload provider
const uploads = _.filter(node_modules, (node_module) => {
return _.startsWith(node_module, ('strapi-upload'));
});
strapi.plugins.upload.config.providers = [];
strapi.plugins.upload.config.providers = [];
// mount all providers to get configs
_.forEach(uploads, (node_module) => {
strapi.plugins.upload.config.providers.push(
require(path.join(`${strapi.config.appPath}/plugins/upload/node_modules/${node_module}`))
);
});
// mount all providers to get configs
_.forEach(uploads, (node_module) => {
strapi.plugins.upload.config.providers.push(
require(path.join(`${basePath}/node_modules/${node_module}`))
);
});
try {
// if provider config not exit set one by default
const config = await pluginStore.get({key: 'provider'});
try {
// if provider config not exit set one by default
const config = await pluginStore.get({key: 'provider'});
if (!config) {
const provider = _.find(strapi.plugins.upload.config.providers, {provider: 'local'});
if (!config) {
const provider = _.find(strapi.plugins.upload.config.providers, {provider: 'local'});
const value = _.assign({}, provider, {
enabled: true,
// by default limit size to 1 GB
sizeLimit: 1000000
});
const value = _.assign({}, provider, {
enabled: true,
// by default limit size to 1 GB
sizeLimit: 1000000
});
await pluginStore.set({key: 'provider', value});
await pluginStore.set({key: 'provider', value});
}
} catch (err) {
strapi.log.error(`Can't load ${config.provider} upload provider.`);
strapi.log.warn(`Please install strapi-upload-${config.provider} --save in ${path.join(strapi.config.appPath, 'plugins', 'upload')} folder.`);
strapi.stop();
}
} catch (err) {
strapi.log.error(`Can't load ${config.provider} upload provider.`);
strapi.log.warn(`Please install strapi-upload-${config.provider} --save in ${path.join(strapi.config.appPath, 'plugins', 'upload')} folder.`);
strapi.stop();
}
cb();
cb();
});
}
// Load providers from the plugins' node_modules.
loadProviders(path.join(strapi.config.appPath, 'plugins', 'upload'), () => {
// Load providers from the root node_modules.
loadProviders(path.join(strapi.config.appPath), cb);
});
};

View File

@ -22,11 +22,12 @@ module.exports = {
environment: strapi.config.environment,
type: 'plugin',
name: 'upload'
}).get({key: 'provider'});
}).get({ key: 'provider' });
// Verify if the file upload is enable.
if (config.enabled === false) {
return ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: 'Upload.status.disabled' }] }] : 'The file upload is disabled!');
strapi.log.error('File upload is disabled');
return ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: 'Upload.status.disabled' }] }] : 'File upload is disabled');
}
// Extract optional relational data.

View File

@ -4,7 +4,7 @@
"description": "This is the description of the plugin.",
"strapi": {
"name": "Files Upload",
"icon": "upload",
"icon": "cloud-upload",
"description": "Description of upload plugin."
},
"scripts": {

View File

@ -44,6 +44,11 @@ module.exports = {
upload: async (files, config) => {
// Get upload provider settings to configure the provider to use.
const provider = _.find(strapi.plugins.upload.config.providers, { provider: config.provider });
if (!provider) {
throw new Error(`The provider package isn't installed. Please run \`npm install strapi-upload-${config.provider}\``);
}
const actions = provider.init(config);
// Execute upload function of the provider for all files.

View File

@ -4,9 +4,6 @@
"name": "user",
"description": ""
},
"options": {
"timestamps": true
},
"attributes": {
"username": {
"type": "string",

View File

@ -28,8 +28,20 @@ function getBool(envVar, defaultValue) {
const loggerConfig = {
level: getLogLevel(),
timestamp: getBool(process.env.STRAPI_LOG_TIMESTAMP, false),
prettyPrint: getBool(process.env.STRAPI_LOG_PRETTY_PRINT, true),
forceColor: getBool(process.env.STRAPI_LOG_FORCE_COLOR, true),
// prettyPrint: getBool(process.env.STRAPI_LOG_PRETTY_PRINT, true),
forceColor: getBool(process.env.STRAPI_LOG_FORCE_COLOR, true)
};
module.exports = pino(loggerConfig);
const pretty = pino.pretty({
formatter: (logs, options) => {
return `\u001b[90m[${new Date().toISOString()}] ${options.prefix.toLowerCase()} ${options.asColoredText(logs.level, logs.msg)}`;
}
});
pretty.pipe(process.stdout);
const logger = getBool(process.env.STRAPI_LOG_PRETTY_PRINT, true) ?
pino(loggerConfig, pretty):
pino(loggerConfig);
module.exports = logger;