mirror of
https://github.com/strapi/strapi.git
synced 2025-12-27 15:13:21 +00:00
Merge branch 'master' into feature/allow-filtering-on-a-relation-attribute
This commit is contained in:
commit
6482a6ec84
18
.github/PULL_REQUEST_TEMPLATE.md
vendored
18
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -3,15 +3,17 @@
|
||||
<!-- Uncomment the correct contribution type. !-->
|
||||
|
||||
My PR is a:
|
||||
<!-- 💥 Breaking change -->
|
||||
<!-- 🐛 Bug fix -->
|
||||
<!-- 💅 Enhancement -->
|
||||
<!-- 🚀 New feature -->
|
||||
- [ ] 💥 Breaking change
|
||||
- [ ] 🐛 Bug fix #issueNumber
|
||||
- [ ] 💅 Enhancement
|
||||
- [ ] 🚀 New feature
|
||||
|
||||
Main update on the:
|
||||
<!-- Admin -->
|
||||
<!-- Documentation -->
|
||||
<!-- Framework -->
|
||||
<!-- Plugin -->
|
||||
- [ ] Admin
|
||||
- [ ] Documentation
|
||||
- [ ] Framework
|
||||
- [ ] Plugin
|
||||
|
||||
<!-- Write a short description of what your PR does and link the concerned issues of your update. -->
|
||||
|
||||
<!-- ⚠️ Please link issue(s) you close / fix by using GitHub keywords https://help.github.com/articles/closing-issues-using-keywords/ !-->
|
||||
|
||||
@ -74,7 +74,7 @@ To use the providers authentication, set your credentials in
|
||||
|
||||
Redirect your user to: `GET /connect/:provider`.
|
||||
|
||||
After his approval, he will be redirected to `/auth/:provider/callback`. The jwt and user will be available in the querystring.
|
||||
After their approval, they will be redirected to `/auth/:provider/callback`. The jwt and user will be available in the querystring.
|
||||
|
||||
Response payload:
|
||||
|
||||
|
||||
@ -296,7 +296,7 @@ A `product` can be related to many `categories`, so a `category` can have many `
|
||||
```
|
||||
|
||||
::: note
|
||||
The `dominant` key allows you to define in which table/collection (only for NoSQL databases) should be stored the array that defines the relationship. Because there is no join table in NoSQL, this key is required for NoSQL databases (ex: MongoDB).
|
||||
(NoSQL databases only) The `dominant` key defines which table/collection should store the array that defines the relationship. Because there are no join tables in NoSQL, this key is required for NoSQL databases (ex: MongoDB).
|
||||
:::
|
||||
|
||||
**Path —** `./api/category/models/Category.settings.json`.
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright@React-FullStory (https://github.com/cereallarceny/react-fullstory)
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const canUseDOM = !!(
|
||||
typeof window !== 'undefined' &&
|
||||
window.document &&
|
||||
window.document.createElement
|
||||
);
|
||||
|
||||
export const getWindowFullStory = () => window[window['_fs_namespace']];
|
||||
|
||||
class FullStory extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
window['_fs_debug'] = false;
|
||||
window['_fs_host'] = 'fullstory.com';
|
||||
window['_fs_org'] = props.org;
|
||||
window['_fs_namespace'] = 'FS';
|
||||
(function(m,n,e,t,l,o,g,y) {
|
||||
if (e in m) {
|
||||
if(m.console && m.console.log) {
|
||||
m.console.log('FullStory namespace conflict. Please set window["_fs_namespace"].');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g = m[e]= function(a,b,s) {
|
||||
g.q ? g.q.push([a,b,s]) : g._api(a,b,s);
|
||||
};
|
||||
g.q=[];
|
||||
o = n.createElement(t);
|
||||
o.async = 1;
|
||||
o.src = `https://${window._fs_host}/s/fs.js`;
|
||||
y = n.getElementsByTagName(t)[0];
|
||||
y.parentNode.insertBefore(o,y);
|
||||
g.identify = function(i,v,s) {
|
||||
g(l,{ uid:i },s);
|
||||
|
||||
if (v) {
|
||||
g(l,v,s);
|
||||
}
|
||||
};
|
||||
g.setUserVars = function(v,s) {
|
||||
g(l,v,s);
|
||||
};
|
||||
g.event = function(i,v,s) {
|
||||
g('event',{ n:i,p:v },s);
|
||||
};
|
||||
g.shutdown = function() {
|
||||
g("rec",!1);
|
||||
};
|
||||
g.restart = function() {
|
||||
g("rec",!0);
|
||||
};
|
||||
g.consent = function(a) {
|
||||
g("consent",!arguments.length||a);
|
||||
};
|
||||
g.identifyAccount = function(i,v) {
|
||||
o = 'account';
|
||||
v = v||{};
|
||||
v.acctId = i;
|
||||
g(o,v);
|
||||
};
|
||||
g.clearUserCookie = function() {};
|
||||
})(window, document, window['_fs_namespace'], 'script', 'user');
|
||||
}
|
||||
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (!canUseDOM || !getWindowFullStory()) return false;
|
||||
|
||||
getWindowFullStory().shutdown();
|
||||
|
||||
delete getWindowFullStory();
|
||||
}
|
||||
|
||||
render() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FullStory.propTypes = {
|
||||
org: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default FullStory;
|
||||
@ -1,3 +1,3 @@
|
||||
{
|
||||
"languages": ["en", "ar", "es", "fr", "de", "it", "ko", "nl", "pl", "pt", "pt-BR", "ru", "tr", "zh", "zh-Hans", "ja"]
|
||||
"languages": ["en", "ar", "es", "fa", "fr", "de", "it", "ko", "nl", "pl", "pt", "pt-BR", "ru", "tr", "zh", "zh-Hans", "ja"]
|
||||
}
|
||||
|
||||
@ -43,6 +43,7 @@ import Logout from 'components/Logout';
|
||||
import NotFoundPage from 'containers/NotFoundPage/Loadable';
|
||||
import OverlayBlocker from 'components/OverlayBlocker';
|
||||
import PluginPage from 'containers/PluginPage';
|
||||
import FullStory from 'components/FullStory';
|
||||
// Utils
|
||||
import auth from 'utils/auth';
|
||||
import injectReducer from 'utils/injectReducer';
|
||||
@ -73,12 +74,12 @@ export class AdminPage extends React.Component {
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { adminPage: { allowGa }, location: { pathname }, plugins } = this.props;
|
||||
const { adminPage: { uuid }, location: { pathname }, plugins } = this.props;
|
||||
|
||||
if (prevProps.location.pathname !== pathname) {
|
||||
this.checkLogin(this.props);
|
||||
|
||||
if (allowGa) {
|
||||
if (uuid) {
|
||||
ReactGA.pageview(pathname);
|
||||
}
|
||||
}
|
||||
@ -198,6 +199,7 @@ export class AdminPage extends React.Component {
|
||||
|
||||
return (
|
||||
<div className={styles.adminPage}>
|
||||
{this.props.adminPage.uuid ? <FullStory org="GK708" /> : ''}
|
||||
{this.showLeftMenu() && (
|
||||
<LeftMenu
|
||||
plugins={this.retrievePlugins()}
|
||||
|
||||
@ -11,7 +11,7 @@ import {
|
||||
} from './constants';
|
||||
|
||||
const initialState = fromJS({
|
||||
allowGa: true,
|
||||
uuid: false,
|
||||
currentEnvironment: 'development',
|
||||
isLoading: true,
|
||||
layout: Map({}),
|
||||
@ -22,7 +22,7 @@ function adminPageReducer(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case GET_ADMIN_DATA_SUCCEEDED:
|
||||
return state
|
||||
.update('allowGa', () => action.data.allowGa)
|
||||
.update('uuid', () => action.data.uuid)
|
||||
.update('currentEnvironment', () => action.data.currentEnvironment)
|
||||
.update('layout', () => Map(action.data.layout))
|
||||
.update('strapiVersion', () => action.data.strapiVersion)
|
||||
|
||||
@ -16,13 +16,13 @@ function* getData() {
|
||||
yield call(request, `${strapi.backendURL}/users/me`, { method: 'GET' });
|
||||
}
|
||||
|
||||
const [{ allowGa }, { strapiVersion }, { currentEnvironment }, { layout }] = yield all([
|
||||
const [{ uuid }, { strapiVersion }, { currentEnvironment }, { layout }] = yield all([
|
||||
call(request, '/admin/gaConfig', { method: 'GET' }),
|
||||
call(request, '/admin/strapiVersion', { method: 'GET' }),
|
||||
call(request, '/admin/currentEnvironment', { method: 'GET' }),
|
||||
call(request, '/admin/layout', { method: 'GET' }),
|
||||
]);
|
||||
yield put(getAdminDataSucceeded({ allowGa, strapiVersion, currentEnvironment, layout }));
|
||||
yield put(getAdminDataSucceeded({ uuid, strapiVersion, currentEnvironment, layout }));
|
||||
|
||||
} catch(err) {
|
||||
console.log(err); // eslint-disable-line no-console
|
||||
|
||||
@ -37,6 +37,8 @@ export class LocaleToggle extends React.Component { // eslint-disable-line
|
||||
return 'https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/flags/4x3/kr.svg';
|
||||
case 'ja':
|
||||
return 'https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/flags/4x3/jp.svg';
|
||||
case 'fa':
|
||||
return 'https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/flags/4x3/ir.svg';
|
||||
default:
|
||||
return `https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/flags/4x3/${locale}.svg`;
|
||||
}
|
||||
|
||||
141
packages/strapi-admin/admin/src/translations/fa.json
Normal file
141
packages/strapi-admin/admin/src/translations/fa.json
Normal file
@ -0,0 +1,141 @@
|
||||
{
|
||||
"Analytics": "آنالیز",
|
||||
"Content Manager": "مدیریت محتوا",
|
||||
"Content Type Builder": "سازنده ی الگوی محتوایی",
|
||||
"Email": "ایمیل",
|
||||
"Files Upload": "آپلود فایل",
|
||||
"HomePage.notification.newsLetter.success": "موفقیت در اشتراک خبر نامه",
|
||||
"New entry": "رکورد جدید",
|
||||
"Password": "رمز عبور",
|
||||
"Provider": "سرویس دهنده",
|
||||
"ResetPasswordToken": "بازنشانی رمز عبور",
|
||||
"Role": "نقش",
|
||||
"Roles & Permissions": "نقش ها و دسترسی ها",
|
||||
"Settings Manager": "مدیریت تنظیمات",
|
||||
"Username": "نام کاربری",
|
||||
"Users": "کاربران",
|
||||
"Users & Permissions": "کاربران و دسترسی ها",
|
||||
"app.components.BlockLink.code": "نمونه کد",
|
||||
"app.components.BlockLink.code.content": "با بررسی و آزمایش پروژه های واقعی توسط جامعه توسعه دهنده Strapi را یاد بگیرید.",
|
||||
"app.components.BlockLink.documentation": "خواندن مستندات",
|
||||
"app.components.BlockLink.documentation.content": "مفاهیم، راهنمای مرجع و آموزش ها را فرا بگیرید.",
|
||||
"app.components.Button.cancel": "کنسل",
|
||||
"app.components.Button.save": "ذخیره",
|
||||
"app.components.ComingSoonPage.comingSoon": "بزودی",
|
||||
"app.components.ComingSoonPage.featuresNotAvailable": "این ویژگی هنوز در حال توسعه است.",
|
||||
"app.components.DownloadInfo.download": "در حال دانلود...",
|
||||
"app.components.DownloadInfo.text": "ممکن است دقایقی طول بکشد، با تشکر از شکیبایی شما.",
|
||||
"app.components.EmptyAttributes.title": "هیچ فیلدی وجود ندارد",
|
||||
"app.components.HomePage.button.blog": "مشاهده بیشتر در بلاگ",
|
||||
"app.components.HomePage.button.quickStart": "شروع آموزش سریع",
|
||||
"app.components.HomePage.community": "جستجوی جامعه توسعه دهنده در اینترنت",
|
||||
"app.components.HomePage.community.content": "گفتگو با اعضای تیم و توسعه دهندگان در کانال های مختلف ارتباطی",
|
||||
"app.components.HomePage.create": "ساخت اولین الگوی محتوا",
|
||||
"app.components.HomePage.createBlock.content.first": "این ",
|
||||
"app.components.HomePage.createBlock.content.second": " افزونه به شما کمک میکند مدل ساختاری داده های خود را تعریف کنید،اگر شما جدیدا به اینجا مراجعه کردید، پس حتما مارا دنبال کنید ",
|
||||
"app.components.HomePage.createBlock.content.tutorial": " آموزش.",
|
||||
"app.components.HomePage.cta": "تایید",
|
||||
"app.components.HomePage.newsLetter": "برای آگاهی از آخرین اخبار Strapi مشترک خبرنامه شوید.",
|
||||
"app.components.HomePage.support": "مارا حمایت کنید",
|
||||
"app.components.HomePage.support.content": "با خرید تی شرت ما میتوانیم به توسعه Strapi ادامه داده و بهترین تجربه را برای شما فراهم کنیم!",
|
||||
"app.components.HomePage.support.link": "هم اکنون تی شرت خود را دریافت کنید",
|
||||
"app.components.HomePage.welcome": "خوش آمدید!",
|
||||
"app.components.HomePage.welcome.again": "خوش آمدید ",
|
||||
"app.components.HomePage.welcomeBlock.content": "خرسندیم که شما را به عنوان عضوی از جامعه توسعه دهنده بشناسیم، ما هر لحظه به دنبال دریافت بازخورد شما هستیم، در ارسال بازخورد تردید نکنید ",
|
||||
"app.components.HomePage.welcomeBlock.content.again": "امیدواریم در پروژه خود پیشرفت کنید... میتوانید در مورد آخرین های Strapi مطالعه کنید. بر اساس بازخورد شما ما موثر ترین اقدامات را برای بهبود محصول انجام خواهیم داد.",
|
||||
"app.components.HomePage.welcomeBlock.content.issues": "مشکلات.",
|
||||
"app.components.HomePage.welcomeBlock.content.raise": " یا ارتقاء دهید ",
|
||||
"app.components.ImgPreview.hint": "برای آپلود، فایل خود را بکشید و در این نقطه رها کنید یا {browse}",
|
||||
"app.components.ImgPreview.hint.browse": "مرور کردن",
|
||||
"app.components.InputFile.newFile": "افزودن فایل جدید",
|
||||
"app.components.InputFileDetails.open": "باز کردن در تب جدید",
|
||||
"app.components.InputFileDetails.originalName": "نام اصلی:",
|
||||
"app.components.InputFileDetails.remove": "حذف این فایل",
|
||||
"app.components.InputFileDetails.size": "حجم:",
|
||||
"app.components.InstallPluginPage.InputSearch.label": " ",
|
||||
"app.components.InstallPluginPage.InputSearch.placeholder": "جستجوی افزونه... (برای مثال: authentication)",
|
||||
"app.components.InstallPluginPage.description": "به راحتی برنامه خود را توسعه دهید.",
|
||||
"app.components.InstallPluginPage.helmet": "فروشگاه - افزونه ها",
|
||||
"app.components.InstallPluginPage.plugin.support-us.description": "با خرید تی شرت ما میتوانیم به توسعه Strapi ادامه داده و بهترین تجربه را برای شما فراهم کنیم!",
|
||||
"app.components.InstallPluginPage.title": "فروشگاه - افزونه ها",
|
||||
"app.components.InstallPluginPopup.downloads": "دانلود",
|
||||
"app.components.InstallPluginPopup.navLink.avis": "مشاهده",
|
||||
"app.components.InstallPluginPopup.navLink.changelog": "تغییرات",
|
||||
"app.components.InstallPluginPopup.navLink.description": "توضیحات",
|
||||
"app.components.InstallPluginPopup.navLink.faq": "پرسش و پاسخ",
|
||||
"app.components.InstallPluginPopup.navLink.screenshots": "تصاویر",
|
||||
"app.components.InstallPluginPopup.noDescription": "توضیحاتی وجود ندارد",
|
||||
"app.components.LeftMenuFooter.poweredBy": "قدرت گرفته از ",
|
||||
"app.components.LeftMenuLinkContainer.configuration": "پیکربندی",
|
||||
"app.components.LeftMenuLinkContainer.general": "عمومی",
|
||||
"app.components.LeftMenuLinkContainer.installNewPlugin": "فروشگاه",
|
||||
"app.components.LeftMenuLinkContainer.listPlugins": "افزونه ها",
|
||||
"app.components.LeftMenuLinkContainer.noPluginsInstalled": "هیچ افزونه ای نصب نشده است",
|
||||
"app.components.LeftMenuLinkContainer.plugins": "افزونه ها",
|
||||
"app.components.ListPluginsPage.description": "فهرست افزونه های نصب شده در پروژه.",
|
||||
"app.components.ListPluginsPage.helmet.title": "فهرست افزونه ها",
|
||||
"app.components.ListPluginsPage.title": "افزونه ها",
|
||||
"app.components.NotFoundPage.back": "بازگشت به صفحه اصلی",
|
||||
"app.components.NotFoundPage.description": "یافت نشد",
|
||||
"app.components.Official": "رسمی",
|
||||
"app.components.PluginCard.Button.label.download": "دانلود",
|
||||
"app.components.PluginCard.Button.label.install": "قبلا نصب شده است",
|
||||
"app.components.PluginCard.Button.label.support": "حمایت از ما",
|
||||
"app.components.PluginCard.compatible": "سازگار با برنامه ی شما",
|
||||
"app.components.PluginCard.compatibleCommunity": "سازگار با جامعه ی توسعه دهنده",
|
||||
"app.components.PluginCard.more-details": "اطلاعات بیشتر",
|
||||
"app.components.PluginCard.price.free": "ریگان",
|
||||
"app.components.listPlugins.button": "افزودن افزونه جدید",
|
||||
"app.components.listPlugins.title.none": "هیچ افزونه ای نصب نشده است",
|
||||
"app.components.listPlugins.title.plural": "{number} افزونه نصب شده",
|
||||
"app.components.listPlugins.title.singular": "{number} افزونه نصب شده",
|
||||
"app.components.listPluginsPage.deletePlugin.error": "خطا در هنگام حذف این افزونه",
|
||||
"app.utils.SelectOption.defaultMessage": " ",
|
||||
"app.utils.defaultMessage": " ",
|
||||
"app.utils.placeholder.defaultMessage": " ",
|
||||
"components.AutoReloadBlocker.description": "فایل را باز کرده و این ویژگی را فعال کنید.",
|
||||
"components.AutoReloadBlocker.header": "بارگذاری مجدد برای این افزونه ضروری است.",
|
||||
"components.ErrorBoundary.title": "خطایی رخ داده است...",
|
||||
"components.Input.error.attribute.key.taken": "این مقدار در حال حاضر وجود دارد",
|
||||
"components.Input.error.attribute.sameKeyAndName": "نمیتواند برابر باشد",
|
||||
"components.Input.error.attribute.taken": "نام فیلد در حال حاضر وجود دارد",
|
||||
"components.Input.error.contentTypeName.taken": "این نام هم اکنون وجود دارد",
|
||||
"components.Input.error.custom-error": "{errorMessage} ",
|
||||
"components.Input.error.validation.email": "این مقدار پست الکترونیک صحیح نیست",
|
||||
"components.Input.error.validation.json": "این مقدار با فرمت استاندارد JSON مطابقت ندارد",
|
||||
"components.Input.error.validation.max": "این مقدار زیاد است.",
|
||||
"components.Input.error.validation.maxLength": "این مقدار طولانی است.",
|
||||
"components.Input.error.validation.min": "این مقدار کوچک است.",
|
||||
"components.Input.error.validation.minLength": "طول این مقدار کم است.",
|
||||
"components.Input.error.validation.minSupMax": "نمی تواند بالاتر باشد",
|
||||
"components.Input.error.validation.regex": "این مقدار با عبارت منظم مطابقت ندارد.",
|
||||
"components.Input.error.validation.required": "این مقدار ضروری است.",
|
||||
"components.ListRow.empty": "داده ای جهت نمایش وجود ندارد.",
|
||||
"components.OverlayBlocker.description": "اقدام مورد نظر نیازمند راه اندازی مجدد سرور است. لطفا منتظر بمانید.",
|
||||
"components.OverlayBlocker.title": "در انتظار راه اندازی مجدد...",
|
||||
"components.PageFooter.select": "تعداد سطر در هر صفحه",
|
||||
"components.ProductionBlocker.description": "به جهت موارد امنیتی ما باید این افزونه را در محیط های دیگر غیرفعال کنیم.",
|
||||
"components.ProductionBlocker.header": "این افزونه فقط در حالت توسعه در دسترس است.",
|
||||
"components.Wysiwyg.ToggleMode.markdown": "تبدیل به حالت markdown",
|
||||
"components.Wysiwyg.ToggleMode.preview": "تبدیل به حالت نمایشی",
|
||||
"components.Wysiwyg.collapse": "کوچک کردن",
|
||||
"components.Wysiwyg.selectOptions.H1": "عنوان H1",
|
||||
"components.Wysiwyg.selectOptions.H2": "عنوان H2",
|
||||
"components.Wysiwyg.selectOptions.H3": "عنوان H3",
|
||||
"components.Wysiwyg.selectOptions.H4": "عنوان H4",
|
||||
"components.Wysiwyg.selectOptions.H5": "عنوان H5",
|
||||
"components.Wysiwyg.selectOptions.H6": "عنوان H6",
|
||||
"components.Wysiwyg.selectOptions.title": "افزدون عنوان",
|
||||
"components.WysiwygBottomControls.charactersIndicators": "حروف",
|
||||
"components.WysiwygBottomControls.fullscreen": "تمام صفحه",
|
||||
"components.WysiwygBottomControls.uploadFiles": "کشیدن و رها کردن فایل، خواندن از حافظه یا {browse}.",
|
||||
"components.WysiwygBottomControls.uploadFiles.browse": "انتخاب کنید",
|
||||
"components.popUpWarning.button.cancel": "کنسل",
|
||||
"components.popUpWarning.button.confirm": "تایید",
|
||||
"components.popUpWarning.message": "آیا از حذف این مقدار اطمینان دارید؟",
|
||||
"components.popUpWarning.title": "لطفا تایید کنید",
|
||||
"notification.error": "خطایی رخ داده است",
|
||||
"notification.error.layout": "خطا در بازیابی طرح",
|
||||
"request.error.model.unknown": "این مدل وجود ندارد",
|
||||
"app.utils.delete": "حذف"
|
||||
}
|
||||
@ -28,8 +28,7 @@ module.exports = {
|
||||
|
||||
getGaConfig: async ctx => {
|
||||
try {
|
||||
const allowGa = _.get(strapi.config, 'info.customs.allowGa', true);
|
||||
ctx.send({ allowGa });
|
||||
ctx.send({ uuid: _.get(strapi.config, 'uuid', false) });
|
||||
} catch(err) {
|
||||
ctx.badRequest(null, [{ messages: [{ id: 'An error occurred' }] }]);
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ If you don't want to share your data with us, you can simply modify the `strapi`
|
||||
```json
|
||||
{
|
||||
"strapi": {
|
||||
"allowGa": false
|
||||
"uuid": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -12,7 +12,15 @@ module.exports = {
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchCollection: async (model, columns, options) => {},
|
||||
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchCollection: async (model, columns, options) => {},
|
||||
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
|
||||
@ -242,13 +242,13 @@ module.exports = {
|
||||
acc[current] = params.values[current];
|
||||
} else if (response[current] && _.isArray(response[current]) && current !== 'id') {
|
||||
// Records to add in the relation.
|
||||
const toAdd = _.differenceWith(params.values[current], response[current], (a, b) =>
|
||||
a[this.primaryKey].toString() === b[this.primaryKey].toString()
|
||||
const toAdd = _.differenceWith(params.values[current], response[current], (a, b) =>
|
||||
(a[this.primaryKey] || a).toString() === (b[this.primaryKey] || b).toString()
|
||||
);
|
||||
|
||||
// Records to remove in the relation.
|
||||
const toRemove = _.differenceWith(response[current], params.values[current], (a, b) =>
|
||||
a[this.primaryKey].toString() === b[this.primaryKey].toString()
|
||||
(a[this.primaryKey] || a).toString() === (b[this.primaryKey] || b).toString()
|
||||
)
|
||||
.filter(x => toAdd.find(y => x.id === y.id) === undefined);
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import React from 'react';
|
||||
import Select from 'react-select';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { cloneDeep, isArray, isNull, isUndefined, get, findIndex, isEmpty } from 'lodash';
|
||||
import { cloneDeep, includes, isArray, isNull, isUndefined, get, findIndex, isEmpty } from 'lodash';
|
||||
|
||||
// Utils.
|
||||
import request from 'utils/request';
|
||||
@ -103,6 +103,15 @@ class SelectMany extends React.PureComponent {
|
||||
});
|
||||
};
|
||||
|
||||
handleInputChange = (value) => {
|
||||
const clonedOptions = this.state.options;
|
||||
const filteredValues = clonedOptions.filter(data => includes(data.label, value));
|
||||
|
||||
if (filteredValues.length === 0) {
|
||||
return this.getOptions(value);
|
||||
}
|
||||
}
|
||||
|
||||
handleChange = value => {
|
||||
// Remove new added value from available option;
|
||||
this.state.options = this.state.options.filter(el =>
|
||||
@ -169,6 +178,7 @@ class SelectMany extends React.PureComponent {
|
||||
id={this.props.relation.alias}
|
||||
isLoading={this.state.isLoading}
|
||||
onChange={this.handleChange}
|
||||
onInputChange={this.handleInputChange}
|
||||
onMenuScrollToBottom={this.handleBottomScroll}
|
||||
options={this.state.options}
|
||||
placeholder={<FormattedMessage id='content-manager.containers.Edit.addAnItem' />}
|
||||
|
||||
@ -102,7 +102,7 @@ module.exports = async cb => {
|
||||
disabled: false,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
// Don't display fields that are hidden by default like the resetPasswordToken for the model user
|
||||
_.unset(fields, fieldsToRemove);
|
||||
schemaModel.attributes = _.omit(schemaModel.attributes, fieldsToRemove);
|
||||
@ -339,16 +339,16 @@ module.exports = async cb => {
|
||||
});
|
||||
|
||||
// Update other keys
|
||||
sameApis.map(apiPath => {
|
||||
sameApis.forEach(apiPath => {
|
||||
// This doesn't keep the prevSettings for the relations, the user will have to reset it.
|
||||
// We might have to improve this if we want the order of the relations to be kept
|
||||
const keysToUpdate = ['relations', 'loadedModel', 'associations', 'attributes', ['editDisplay', 'relations']].map(key => apiPath.concat(key));
|
||||
['relations', 'loadedModel', 'associations', 'attributes', ['editDisplay', 'relations']]
|
||||
.map(key => apiPath.concat(key))
|
||||
.forEach(keyPath => {
|
||||
const newValue = _.get(schema.models, keyPath);
|
||||
|
||||
keysToUpdate.map(keyPath => {
|
||||
const newValue = _.get(schema.models, keyPath);
|
||||
|
||||
_.set(prevSchema.models, keyPath, newValue);
|
||||
});
|
||||
_.set(prevSchema.models, keyPath, newValue);
|
||||
});
|
||||
});
|
||||
|
||||
// Special handler for the upload relations
|
||||
@ -363,6 +363,7 @@ module.exports = async cb => {
|
||||
});
|
||||
|
||||
await pluginStore.set({ key: 'schema', value: prevSchema });
|
||||
|
||||
} catch(err) {
|
||||
console.log('error', err);
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
const _ = require('lodash');
|
||||
|
||||
/**
|
||||
* Retrieve the path of each API
|
||||
* @param {Object}} data
|
||||
* @param {Object}} data
|
||||
* @returns {Array} Array of API path ['plugins.upload.file', 'plugins.users-permissions.user', ...]
|
||||
*/
|
||||
const getApis = (data) => Object.keys(data).reduce((acc, curr) => {
|
||||
@ -10,8 +11,8 @@ const getApis = (data) => Object.keys(data).reduce((acc, curr) => {
|
||||
}
|
||||
|
||||
if (curr === 'plugins') {
|
||||
Object.keys(data[curr]).map(plugin => {
|
||||
Object.keys(data[curr][plugin]).map(api => {
|
||||
Object.keys(data[curr]).forEach(plugin => {
|
||||
Object.keys(data[curr][plugin]).forEach(api => {
|
||||
acc = acc.concat([`${curr}.${plugin}.${api}`]);
|
||||
});
|
||||
});
|
||||
@ -23,8 +24,8 @@ const getApis = (data) => Object.keys(data).reduce((acc, curr) => {
|
||||
|
||||
/**
|
||||
* Retrieve all the fields from an api
|
||||
* @param {Object} data
|
||||
* @param {Array} apis
|
||||
* @param {Object} data
|
||||
* @param {Array} apis
|
||||
* @returns {Array} Array composed of fields path for instance : [['plugins.users-permissions.user.fields.username', 'plugins.users-permissions.user.fields.email', 'plugins.users-permissions.user.fields.password'], [...]]
|
||||
*/
|
||||
const getApisKeys = (data, apis) => apis.map(apiPath => {
|
||||
@ -43,12 +44,12 @@ const getApisUploadRelations = (data, sameArray) => sameArray.map(apiPath => {
|
||||
.filter(relationName => {
|
||||
return _.get(data.models, [...relationPath, relationName, 'plugin' ]) === 'upload';
|
||||
});
|
||||
|
||||
|
||||
return relations.map(relation => `${apiPath.join('.')}.editDisplay.availableFields.${relation}`);
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param {String} attrPath
|
||||
* @returns {Array}
|
||||
*/
|
||||
|
||||
@ -105,9 +105,9 @@ module.exports = {
|
||||
_.set(schema, [...schemaPath, 'editDisplay', 'fields'], newList.toJS());
|
||||
}
|
||||
|
||||
Object.keys(attributes).map(attribute => {
|
||||
Object.keys(attributes).forEach(attribute => {
|
||||
const appearances = _.get(attributes, [attribute, 'appearance'], {});
|
||||
Object.keys(appearances).map(appearance => {
|
||||
Object.keys(appearances).forEach(appearance => {
|
||||
_.set(layout, ['attributes', attribute, 'appearance'], appearances[appearance] ? appearance : '' );
|
||||
});
|
||||
|
||||
|
||||
@ -373,14 +373,14 @@ module.exports = {
|
||||
source: association.plugin,
|
||||
};
|
||||
|
||||
if (association.type === 'model') {
|
||||
params.id = obj[association.alias];
|
||||
} else {
|
||||
// Get refering model.
|
||||
const ref = association.plugin
|
||||
? strapi.plugins[association.plugin].models[params.model]
|
||||
: strapi.models[params.model];
|
||||
// Get refering model.
|
||||
const ref = association.plugin
|
||||
? strapi.plugins[association.plugin].models[params.model]
|
||||
: strapi.models[params.model];
|
||||
|
||||
if (association.type === 'model') {
|
||||
params.id = _.get(obj, [association.alias, ref.primaryKey], obj[association.alias]);
|
||||
} else {
|
||||
// Apply optional arguments to make more precise nested request.
|
||||
const convertedParams = strapi.utils.models.convertParams(
|
||||
name,
|
||||
|
||||
@ -8,7 +8,7 @@ export default function checkFormValidity(settingType, data, providerToEdit = ''
|
||||
const isProviderEnabled = get(data, 'enabled');
|
||||
const keys = providerToEdit === 'email' ? [] : ['key', 'secret'];
|
||||
|
||||
keys.map(key => {
|
||||
keys.forEach(key => {
|
||||
if (isProviderEnabled && isEmpty(get(data, key))) {
|
||||
formErrors.push({ name: key, errors: [{ id: 'components.Input.error.validation.required' }] });
|
||||
}
|
||||
@ -16,9 +16,9 @@ export default function checkFormValidity(settingType, data, providerToEdit = ''
|
||||
break;
|
||||
}
|
||||
case 'email-templates': {
|
||||
Object.keys(data.options).map((value) => {
|
||||
Object.keys(data.options).forEach((value) => {
|
||||
if (isObject(data.options[value])) {
|
||||
Object.keys(data.options[value]).map(subValue => {
|
||||
Object.keys(data.options[value]).forEach(subValue => {
|
||||
if (isEmpty(get(data, ['options', value, subValue]))) {
|
||||
formErrors.push({ name: `options.${value}.${subValue}`, errors: [{ id: 'components.Input.error.validation.required' }] });
|
||||
}
|
||||
|
||||
@ -199,9 +199,9 @@ module.exports = {
|
||||
const prefix = curr.config.prefix;
|
||||
const path = prefix !== undefined ? `${prefix}${curr.path}` : `/${current}${curr.path}`;
|
||||
_.set(curr, 'path', path);
|
||||
|
||||
|
||||
return acc.concat(curr);
|
||||
}, []);
|
||||
}, []);
|
||||
|
||||
acc[current] = routes;
|
||||
|
||||
@ -221,7 +221,7 @@ module.exports = {
|
||||
// Aggregate first level actions.
|
||||
const appActions = Object.keys(strapi.api || {}).reduce((acc, api) => {
|
||||
Object.keys(_.get(strapi.api[api], 'controllers', {}))
|
||||
.map(controller => {
|
||||
.forEach(controller => {
|
||||
const actions = Object.keys(strapi.api[api].controllers[controller])
|
||||
.filter(action => _.isFunction(strapi.api[api].controllers[controller][action]))
|
||||
.map(action => `application.${controller}.${action.toLowerCase()}`);
|
||||
@ -235,7 +235,7 @@ module.exports = {
|
||||
// Aggregate plugins' actions.
|
||||
const pluginsActions = Object.keys(strapi.plugins).reduce((acc, plugin) => {
|
||||
Object.keys(strapi.plugins[plugin].controllers)
|
||||
.map(controller => {
|
||||
.forEach(controller => {
|
||||
const actions = Object.keys(strapi.plugins[plugin].controllers[controller])
|
||||
.filter(action => _.isFunction(strapi.plugins[plugin].controllers[controller][action]))
|
||||
.map(action => `${plugin}.${controller}.${action.toLowerCase()}`);
|
||||
|
||||
@ -368,7 +368,7 @@ const enableHookNestedDependencies = function (name, flattenHooksConfig, force =
|
||||
});
|
||||
|
||||
return apiModelsUsed.length !== 0;
|
||||
}) || 0; // Filter model with the right connector
|
||||
}); // Filter model with the right connector
|
||||
|
||||
flattenHooksConfig[name] = {
|
||||
enabled: force || modelsUsed.length > 0 // Will return false if there is no model, else true.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user