Merge branch 'features/media-lib' of github.com:strapi/strapi into features/media-lib-settings-view

This commit is contained in:
soupette 2020-02-29 07:59:42 +01:00
commit efe0b1a424
101 changed files with 1527 additions and 910 deletions

View File

@ -3,17 +3,13 @@ services:
- mysql
addons:
postgresql: '10'
apt:
packages:
- postgresql-10
- postgresql-client-10
postgresql: '11.2'
env:
global:
- PGPORT=5433
sudo: required
dist: trusty
dist: xenial
language: node_js
@ -33,14 +29,6 @@ e2e_tests: &e2e_tests
- yarn run -s test:start-app & wait-on http://localhost:1337
- yarn run -s test:e2e
install_mongo: &install_mongo
before_install:
- wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.6.tgz
- tar -zxvf mongodb-linux-x86_64-3.6.6.tgz
- mkdir -p ./data/db/27017
- mkdir -p ./data/db/27000
- ./mongodb-linux-x86_64-3.6.6/bin/mongod --fork --dbpath ./data/db/27017 --syslog --port 27017
before_script:
- yarn build
- yarn global add -g wait-on
@ -50,11 +38,17 @@ jobs:
include:
- stage: test
name: Snyk
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash
- export PATH="$HOME/.yarn/bin:$PATH"
script: yarn run -s test:snyk
if: fork = false
- stage: test
name: 'Lint / Unit Tests '
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash
- export PATH="$HOME/.yarn/bin:$PATH"
script:
- yarn run -s lint
- yarn run -s test:unit --coverage && codecov -C -F unit
@ -63,8 +57,13 @@ jobs:
- <<: *e2e_tests
name: 'E2E Postgresql'
before_install:
- sudo cp /etc/postgresql/{9.6,10}/main/pg_hba.conf
- sudo /etc/init.d/postgresql restart
- curl -o- -L https://yarnpkg.com/install.sh | bash
- export PATH="$HOME/.yarn/bin:$PATH"
- sudo apt-get update
- sudo apt-get --yes remove postgresql-*
- sudo apt-get install -y postgresql-11 postgresql-client-11
- sudo cp /etc/postgresql/{9.6,11}/main/pg_hba.conf
- sudo service postgresql restart 11
- psql -c 'create database strapi_test;' -U postgres
env:
- DB_STRING='--dbclient=postgres --dbhost=localhost --dbport=5433 --dbname=strapi_test --dbusername=postgres --dbpassword='
@ -72,6 +71,8 @@ jobs:
- <<: *e2e_tests
name: 'E2E Mysql'
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash
- export PATH="$HOME/.yarn/bin:$PATH"
- sudo cp $TRAVIS_BUILD_DIR/_travis/mysql.cnf /etc/mysql/conf.d/
- sudo service mysql restart
- mysql -e 'CREATE DATABASE strapi_test;'
@ -80,21 +81,21 @@ jobs:
- <<: *e2e_tests
name: 'E2E Sqlite'
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash
- export PATH="$HOME/.yarn/bin:$PATH"
env:
- DB_STRING='--dbclient=sqlite --dbfile=./tmp/data.db'
- <<: *e2e_tests
name: 'E2E MongoDB'
<<: *install_mongo
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash
- export PATH="$HOME/.yarn/bin:$PATH"
- wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.6.tgz
- tar -zxvf mongodb-linux-x86_64-3.6.6.tgz
- mkdir -p ./data/db/27017
- mkdir -p ./data/db/27000
- ./mongodb-linux-x86_64-3.6.6/bin/mongod --fork --dbpath ./data/db/27017 --syslog --port 27017
env:
- DB_STRING='--dbclient=mongo --dbhost=localhost --dbport=27017 --dbname=strapi_test --dbusername= --dbpassword='
# - name: 'Cypress tests'
# <<: *install_mongo
# install:
# - yarn run -s bootstrap
# - yarn global add -g wait-on
# - cypress install
# script:
# - yarn run -s test:generate-app -- --dbclient=mongo --dbhost=localhost --dbport=27017 --dbname=strapi_test --dbusername= --dbpassword=
# - yarn run -s test:start-app & wait-on http://localhost:1337
# - node test/cypress.js

View File

@ -9,7 +9,9 @@ const Wrapper = styled.div`
bottom: 0;
left: 0;
overflow-y: auto;
height: calc(100vh - (${props => props.theme.main.sizes.leftMenu.height} + 10.2rem));
height: calc(
100vh - (${props => props.theme.main.sizes.leftMenu.height} + 10.2rem)
);
box-sizing: border-box;
.title {

View File

@ -431,7 +431,6 @@ exports[`Admin | containers | EditView should match the snapshot 1`] = `
font-size: 2.4rem;
font-weight: 600;
margin-bottom: 1px;
text-transform: capitalize;
padding-right: 18px;
}

View File

@ -168,7 +168,6 @@ exports[`Admin | containers | ListView should match the snapshot 1`] = `
font-size: 2.4rem;
font-weight: 600;
margin-bottom: 1px;
text-transform: capitalize;
padding-right: 18px;
}

View File

@ -97,6 +97,14 @@
"app.utils.placeholder.defaultMessage": " ",
"components.AutoReloadBlocker.header": "مطلوب ميزة إعادة التحميل لهذه الإضافة.",
"components.ErrorBoundary.title": "هناك خطأ ما...",
"components.FilterOptions.FILTER_TYPES.=": "هو",
"components.FilterOptions.FILTER_TYPES._contains": "يحتوي",
"components.FilterOptions.FILTER_TYPES._containss": "يحتوي (حساس لحالة الأحرف)",
"components.FilterOptions.FILTER_TYPES._gt": "اكبر من",
"components.FilterOptions.FILTER_TYPES._gte": "اكبر من او يساوي",
"components.FilterOptions.FILTER_TYPES._lt": "اقل من",
"components.FilterOptions.FILTER_TYPES._lte": "اقل من او يساوي",
"components.FilterOptions.FILTER_TYPES._ne": "ليس",
"components.Input.error.attribute.key.taken": "هذه القيمة موجودة مسبقًا",
"components.Input.error.attribute.sameKeyAndName": "لا تتطابق",
"components.Input.error.attribute.taken": "اسم الحقل هذا مستخدم مسبقًا",

View File

@ -114,6 +114,16 @@
"components.AutoReloadBlocker.description": "Spusťte Strapi jedním z následujících příkazů:",
"components.AutoReloadBlocker.header": "Pro tento zásuvný modul musí být zapnuta funkce znovu načítání.",
"components.ErrorBoundary.title": "Něco se pokazilo...",
"components.FilterOptions.FILTER_TYPES.=": "je",
"components.FilterOptions.FILTER_TYPES._contains": "obsahuje",
"components.FilterOptions.FILTER_TYPES._containss": "obsahuje (citlivé na velká písmena)",
"components.FilterOptions.FILTER_TYPES._gt": "je větší než",
"components.FilterOptions.FILTER_TYPES._gte": "je větší nebo rovno než",
"components.FilterOptions.FILTER_TYPES._lt": "je menší než",
"components.FilterOptions.FILTER_TYPES._lte": "je menší nebo rovno než",
"components.FilterOptions.FILTER_TYPES._ne": "není",
"components.FilterOptions.FILTER_TYPES._in": "odpovídá jakékoliv hodnotě v poli hodnot",
"components.FilterOptions.FILTER_TYPES._nin": "neodpovídá ani jedné hodnotě v poli hodnot",
"components.Input.error.attribute.key.taken": "Tato hodnota již existuje",
"components.Input.error.attribute.sameKeyAndName": "Hodnoty nesmí být stejné",
"components.Input.error.attribute.taken": "Název tohoto pole již existuje",

View File

@ -111,6 +111,14 @@
"components.AutoReloadBlocker.description": "Führen Sie Strapi mit einem der folgenden Befehle aus:",
"components.AutoReloadBlocker.header": "Dieses Plugin benötigt das Neuladen-Feature.",
"components.ErrorBoundary.title": "Etwas ist falsch gelaufen...",
"components.FilterOptions.FILTER_TYPES.=": "ist",
"components.FilterOptions.FILTER_TYPES._contains": "enthält",
"components.FilterOptions.FILTER_TYPES._containss": "enthält (Groß-/Kleinschreibung beachten)",
"components.FilterOptions.FILTER_TYPES._gt": "ist größer als",
"components.FilterOptions.FILTER_TYPES._gte": "ist größer oder gleich als",
"components.FilterOptions.FILTER_TYPES._lt": "ist kleiner als",
"components.FilterOptions.FILTER_TYPES._lte": "ist kleiner oder gleich als",
"components.FilterOptions.FILTER_TYPES._ne": "ist nicht",
"components.Input.error.attribute.key.taken": "Dieser Wert existiert bereits",
"components.Input.error.attribute.sameKeyAndName": "Darf nicht gleich sein",
"components.Input.error.attribute.taken": "Dieser Feldname ist bereits vergeben",

View File

@ -117,6 +117,16 @@
"components.AutoReloadBlocker.description": "Run Strapi with one of the following commands:",
"components.AutoReloadBlocker.header": "Reload feature is required for this plugin.",
"components.ErrorBoundary.title": "Something went wrong...",
"components.FilterOptions.FILTER_TYPES.=": "is",
"components.FilterOptions.FILTER_TYPES._contains": "contains",
"components.FilterOptions.FILTER_TYPES._containss": "contains (case sensitive)",
"components.FilterOptions.FILTER_TYPES._gt": "is greater than",
"components.FilterOptions.FILTER_TYPES._gte": "is greater than or equal to",
"components.FilterOptions.FILTER_TYPES._lt": "is lower than",
"components.FilterOptions.FILTER_TYPES._lte": "is lower than or equal to",
"components.FilterOptions.FILTER_TYPES._ne": "is not",
"components.FilterOptions.FILTER_TYPES._in": "matches any value in the array of values",
"components.FilterOptions.FILTER_TYPES._nin": "doesn't match any value in the array of values",
"components.Input.error.attribute.key.taken": "This value already exists",
"components.Input.error.attribute.sameKeyAndName": "Can't be equal",
"components.Input.error.attribute.taken": "This field name already exists",

View File

@ -110,6 +110,16 @@
"components.AutoReloadBlocker.description": "Inicia Strapi con uno de los siguientes comandos:",
"components.AutoReloadBlocker.header": "Es necesario recargar para este plugin.",
"components.ErrorBoundary.title": "Algo salió mal...",
"components.FilterOptions.FILTER_TYPES.=": "es",
"components.FilterOptions.FILTER_TYPES._contains": "contiene",
"components.FilterOptions.FILTER_TYPES._containss": "contiene (distinguiendo mayúsculas y minúsculas)",
"components.FilterOptions.FILTER_TYPES._gt": "es mayor que",
"components.FilterOptions.FILTER_TYPES._gte": "es mayor o igual que",
"components.FilterOptions.FILTER_TYPES._lt": "es menor que",
"components.FilterOptions.FILTER_TYPES._lte": "es menor o igual que",
"components.FilterOptions.FILTER_TYPES._ne": "no es",
"components.FilterOptions.FILTER_TYPES._in": "coincide con cualquier valor de la lista de registros",
"components.FilterOptions.FILTER_TYPES._nin": "no coincide con ningún valor de la lista de registros",
"components.Input.error.attribute.key.taken": "Este valor ya existe",
"components.Input.error.attribute.sameKeyAndName": "No puede ser igual",
"components.Input.error.attribute.taken": "Este nombre de campo ya existe",

View File

@ -116,6 +116,14 @@
"components.AutoReloadBlocker.description": "Démarrez Strapi avec l'une des commandes suivantes:",
"components.AutoReloadBlocker.header": "L'autoReload doit être activé pour ce plugin.",
"components.ErrorBoundary.title": "Une erreur est survenue...",
"components.FilterOptions.FILTER_TYPES.=": "est",
"components.FilterOptions.FILTER_TYPES._contains": "contient",
"components.FilterOptions.FILTER_TYPES._containss": "contient (sensible à la casse)",
"components.FilterOptions.FILTER_TYPES._gt": "supérieur à",
"components.FilterOptions.FILTER_TYPES._gte": "supérieur ou égal à",
"components.FilterOptions.FILTER_TYPES._lt": "inférieur à",
"components.FilterOptions.FILTER_TYPES._lte": "inférieur ou égal à",
"components.FilterOptions.FILTER_TYPES._ne": "n'est pas",
"components.Input.error.attribute.key.taken": "Cette valeur existe déjà",
"components.Input.error.attribute.sameKeyAndName": "Ne peuvent pas être égaux",
"components.Input.error.attribute.taken": "Ce champ existe déjà",

View File

@ -111,6 +111,14 @@
"components.AutoReloadBlocker.description": "Avvia Strapi con uno dei seguenti comandi:",
"components.AutoReloadBlocker.header": "Ricarica funzionalità è richiesto per questo plugin.",
"components.ErrorBoundary.title": "Qualcosa è andato storto...",
"components.FilterOptions.FILTER_TYPES.=": "si",
"components.FilterOptions.FILTER_TYPES._contains": "contiene",
"components.FilterOptions.FILTER_TYPES._containss": "contiene (maiuscole e minuscole)",
"components.FilterOptions.FILTER_TYPES._gt": "è maggiore di",
"components.FilterOptions.FILTER_TYPES._gte": "è maggiore o uguale a",
"components.FilterOptions.FILTER_TYPES._lt": "è inferiore",
"components.FilterOptions.FILTER_TYPES._lte": "è inferiore o uguale a",
"components.FilterOptions.FILTER_TYPES._ne": "non è",
"components.Input.error.attribute.key.taken": "Valore già esistente",
"components.Input.error.attribute.sameKeyAndName": "Non può essere uguale",
"components.Input.error.attribute.taken": "Nome campo già esistente",

View File

@ -98,6 +98,14 @@
"app.utils.SelectOption.defaultMessage": " ",
"components.AutoReloadBlocker.header": "プラグインを有効化するにはリロードが必要です",
"components.ErrorBoundary.title": "なにかが間違っています...",
"components.FilterOptions.FILTER_TYPES.=": "は",
"components.FilterOptions.FILTER_TYPES._contains": "含まれる",
"components.FilterOptions.FILTER_TYPES._containss": "含まれる(大文字と小文字を区別)",
"components.FilterOptions.FILTER_TYPES._gt": "より大きい",
"components.FilterOptions.FILTER_TYPES._gte": "より大きい、もしくは、等しい",
"components.FilterOptions.FILTER_TYPES._lt": "より低い",
"components.FilterOptions.FILTER_TYPES._lte": "より低い、もしくは、等しい",
"components.FilterOptions.FILTER_TYPES._ne": "ではない",
"components.Input.error.attribute.key.taken": "この値はすでに存在しています",
"components.Input.error.attribute.sameKeyAndName": "等しくありません",
"components.Input.error.attribute.taken": "このフィールド名はすでに存在します",

View File

@ -111,6 +111,16 @@
"components.AutoReloadBlocker.description": "다음 명령어 중 하나를 사용하여 Strapi를 실행합니다:",
"components.AutoReloadBlocker.header": "이 플러그인은 리로드 기능이 필요합니다.",
"components.ErrorBoundary.title": "에러가 발생했습니다.",
"components.FilterOptions.FILTER_TYPES.=": "같음",
"components.FilterOptions.FILTER_TYPES._contains": "포함",
"components.FilterOptions.FILTER_TYPES._containss": "포함(대소문자 구분)",
"components.FilterOptions.FILTER_TYPES._gt": "큼",
"components.FilterOptions.FILTER_TYPES._gte": "크거나 같음",
"components.FilterOptions.FILTER_TYPES._lt": "작음",
"components.FilterOptions.FILTER_TYPES._lte": "작거나 같음",
"components.FilterOptions.FILTER_TYPES._ne": "같지 않음",
"components.FilterOptions.FILTER_TYPES._in": "배열중에 일치하는 값이 있음",
"components.FilterOptions.FILTER_TYPES._nin": "배열중에 일치하는 값이 없음",
"components.Input.error.attribute.key.taken": "이미 사용중인 키입니다.",
"components.Input.error.attribute.sameKeyAndName": "같은 값을 사용할 수 없습니다.",
"components.Input.error.attribute.taken": "이미 사용중인 이름입니다.",
@ -216,4 +226,4 @@
"components.Input.error.password.noMatch": "패스워드가 일치하지 않습니다.",
"form.button.done": "확인",
"notification.form.error.fields": "잘못 입력된 필드가 존재합니다."
}
}

View File

@ -98,6 +98,14 @@
"app.utils.placeholder.defaultMessage": " ",
"components.AutoReloadBlocker.header": "De herlaad feature is nodig voor deze extensie",
"components.ErrorBoundary.title": "Er is iets fout gegaan...",
"components.FilterOptions.FILTER_TYPES.=": "is",
"components.FilterOptions.FILTER_TYPES._contains": "bevat",
"components.FilterOptions.FILTER_TYPES._containss": "bevat (hoofdletter gevoelig)",
"components.FilterOptions.FILTER_TYPES._gt": "is groter dan",
"components.FilterOptions.FILTER_TYPES._gte": "is groter dan of gelijk aan",
"components.FilterOptions.FILTER_TYPES._lt": "is lager dan",
"components.FilterOptions.FILTER_TYPES._lte": "is lager dan of gelijk aan",
"components.FilterOptions.FILTER_TYPES._ne": "is niet",
"components.Input.error.attribute.key.taken": "Deze waarde bestaat al.",
"components.Input.error.attribute.sameKeyAndName": "Mag niet gelijk zijn.",
"components.Input.error.attribute.taken": "Deze veld naam bestaat al",

View File

@ -117,6 +117,16 @@
"components.AutoReloadBlocker.description": "Uruchom Strapi z jedną z poniższych komend:",
"components.AutoReloadBlocker.header": "Do tej wtyczki wymagana jest funkcja przeładowania.",
"components.ErrorBoundary.title": "Coś poszło nie tak...",
"components.FilterOptions.FILTER_TYPES.=": "jest identyczne z",
"components.FilterOptions.FILTER_TYPES._contains": "zawiera",
"components.FilterOptions.FILTER_TYPES._containss": "zawiera (rozróżnianie wielkości liter)",
"components.FilterOptions.FILTER_TYPES._gt": "jest większe od",
"components.FilterOptions.FILTER_TYPES._gte": "jest większe od lub równe",
"components.FilterOptions.FILTER_TYPES._in": "dopasuj jakąkolwiek wartość z tablicy wartości",
"components.FilterOptions.FILTER_TYPES._lt": "jest mniejsze od",
"components.FilterOptions.FILTER_TYPES._lte": "jest mniejsze od lub równe",
"components.FilterOptions.FILTER_TYPES._ne": "jest różne od",
"components.FilterOptions.FILTER_TYPES._nin": "nie znaleziono pasującej wartości w tablicy wartości",
"components.Input.error.attribute.key.taken": "Ta wartość już istnieje",
"components.Input.error.attribute.sameKeyAndName": "Nie mogą być takie same",
"components.Input.error.attribute.taken": "Ta nazwa pola już istnieje",

View File

@ -111,6 +111,14 @@
"components.AutoReloadBlocker.description": "Execute o Strapi com um dos seguintes comandos:",
"components.AutoReloadBlocker.header": "Auto recarregamento é necessário para esta extensão.",
"components.ErrorBoundary.title": "Algo deu errado...",
"components.FilterOptions.FILTER_TYPES.=": "é",
"components.FilterOptions.FILTER_TYPES._contains": "contém",
"components.FilterOptions.FILTER_TYPES._containss": "contém (case sensitive)",
"components.FilterOptions.FILTER_TYPES._gt": "é maior que",
"components.FilterOptions.FILTER_TYPES._gte": "é maior que ou igual à",
"components.FilterOptions.FILTER_TYPES._lt": "é menor que",
"components.FilterOptions.FILTER_TYPES._lte": "é menor que ou igual à",
"components.FilterOptions.FILTER_TYPES._ne": "não é",
"components.Input.error.attribute.key.taken": "Este valor já existe",
"components.Input.error.attribute.sameKeyAndName": "Não pode ser igual",
"components.Input.error.attribute.taken": "O nome deste campo já existe",

View File

@ -97,6 +97,14 @@
"app.utils.placeholder.defaultMessage": " ",
"components.AutoReloadBlocker.header": "Recurso de recarga é necessário para esta extensão.",
"components.ErrorBoundary.title": "Algo deu errado...",
"components.FilterOptions.FILTER_TYPES.=": "é",
"components.FilterOptions.FILTER_TYPES._contains": "contém",
"components.FilterOptions.FILTER_TYPES._containss": "contém (case sensitive)",
"components.FilterOptions.FILTER_TYPES._gt": "é maior que",
"components.FilterOptions.FILTER_TYPES._gte": "é maior que ou igual à",
"components.FilterOptions.FILTER_TYPES._lt": "é menor que",
"components.FilterOptions.FILTER_TYPES._lte": "é menor que ou igual à",
"components.FilterOptions.FILTER_TYPES._ne": "não é",
"components.Input.error.attribute.key.taken": "Este valor já existe",
"components.Input.error.attribute.sameKeyAndName": "Não pode ser igual",
"components.Input.error.attribute.taken": "O nome deste campo já existe",

View File

@ -115,6 +115,14 @@
"components.AutoReloadBlocker.description": "Запустите Strapi с помощью одной из следующих команд:",
"components.AutoReloadBlocker.header": "Функционал перезапуска необходим для этого плагина.",
"components.ErrorBoundary.title": "Что-то пошло не так...",
"components.FilterOptions.FILTER_TYPES.=": "равно",
"components.FilterOptions.FILTER_TYPES._contains": "содержит",
"components.FilterOptions.FILTER_TYPES._containss": "содержит (с учетом регистра)",
"components.FilterOptions.FILTER_TYPES._gt": "больше чем",
"components.FilterOptions.FILTER_TYPES._gte": "больше или равно",
"components.FilterOptions.FILTER_TYPES._lt": "меньше чем",
"components.FilterOptions.FILTER_TYPES._lte": "меньше или равно",
"components.FilterOptions.FILTER_TYPES._ne": "не равно",
"components.Input.error.attribute.key.taken": "Это значение уже существует",
"components.Input.error.attribute.sameKeyAndName": "Не может быть одинаковым",
"components.Input.error.attribute.taken": "Поле с таким названием уже существует",

View File

@ -115,6 +115,16 @@
"components.AutoReloadBlocker.description": "Spustite Strapi s jedným z nasledujúcich príkazov:",
"components.AutoReloadBlocker.header": "Pre tento plugin je požadované opätovné načítanie stránky.",
"components.ErrorBoundary.title": "Niečo sa pokazilo...",
"components.FilterOptions.FILTER_TYPES.=": "je",
"components.FilterOptions.FILTER_TYPES._contains": "obsahuje",
"components.FilterOptions.FILTER_TYPES._containss": "obsahuje (záleží na veľkosti písmen)",
"components.FilterOptions.FILTER_TYPES._gt": "je väčšie ako",
"components.FilterOptions.FILTER_TYPES._gte": "je väčšie ako alebo rovné",
"components.FilterOptions.FILTER_TYPES._lt": "je menšie ako",
"components.FilterOptions.FILTER_TYPES._lte": "je menšie ako alebo rovné",
"components.FilterOptions.FILTER_TYPES._ne": "nie je",
"components.FilterOptions.FILTER_TYPES._in": "obsahuje hodnotu z poľa",
"components.FilterOptions.FILTER_TYPES._nin": "neobsahuje žiadnu hodnotu z poľa",
"components.Input.error.attribute.key.taken": "Táto hodnota už existuje",
"components.Input.error.attribute.sameKeyAndName": "Nemôže sa rovnať",
"components.Input.error.attribute.taken": "Názov tohto políčka už existuje",

View File

@ -27,14 +27,14 @@
"app.components.DownloadInfo.text": "Det kan ta en minut. Tack för ditt tålamod.",
"app.components.EmptyAttributes.title": "Det finns inga fält än ",
"app.components.HomePage.button.blog": "SE MER PÅ BLOGGEN",
  "app.components.HomePage.button.quickStart": "Snabb introduktion",
  "app.components.HomePage.community": "Hitta gemenskapen på webben",
  "app.components.HomePage.community.content": "Diskutera med teammedlemmar, bidragsgivare och utvecklare på olika kanaler.",
  "app.components.HomePage.create": "Skapa din första innehållstyp",
  "app.components.HomePage.createBlock.content.first": "De",
  "app.components.HomePage.createBlock.content.second": "plugin hjälper dig att definiera datastrukturen för dina modeller. Om du är ny här rekommenderar vi dig starkt att följa vår",
  "app.components.HomePage.createBlock.content.tutorial": "snabbguide.",
  "app.components.HomePage.cta": "BEKRÄFTA",
"app.components.HomePage.button.quickStart": "Snabb introduktion",
"app.components.HomePage.community": "Hitta gemenskapen på webben",
"app.components.HomePage.community.content": "Diskutera med teammedlemmar, bidragsgivare och utvecklare på olika kanaler.",
"app.components.HomePage.create": "Skapa din första innehållstyp",
"app.components.HomePage.createBlock.content.first": "De",
"app.components.HomePage.createBlock.content.second": "plugin hjälper dig att definiera datastrukturen för dina modeller. Om du är ny här rekommenderar vi dig starkt att följa vår",
"app.components.HomePage.createBlock.content.tutorial": "snabbguide.",
"app.components.HomePage.cta": "BEKRÄFTA",
"app.components.HomePage.newsLetter": "Prenumerera på nyhetsbrevet för att hålla dig uppdaterad om Strapi",
"app.components.HomePage.support": "STÖD OSS",
"app.components.HomePage.support.content": "Genom att köpa en T-shirt hjälper du oss att fortsätta vårt arbete med projektet för att ge dig bästa möjliga upplevelse! ",

View File

@ -115,6 +115,14 @@
"components.AutoReloadBlocker.description": "Strapi'yi aşağıdaki komutlardan biri ile çalıştırın:",
"components.AutoReloadBlocker.header": "Bu eklenti için tekrar yükleme özelliği gerekiyor.",
"components.ErrorBoundary.title": "Bir şeyler yanlış gitti...",
"components.FilterOptions.FILTER_TYPES.=": "eşit",
"components.FilterOptions.FILTER_TYPES._contains": "içermek",
"components.FilterOptions.FILTER_TYPES._containss": "içermek (büyük-küçük harfe duyarlı)",
"components.FilterOptions.FILTER_TYPES._gt": "daha yüksek",
"components.FilterOptions.FILTER_TYPES._gte": "daha yüksek ya da eşit",
"components.FilterOptions.FILTER_TYPES._lt": "daha düşük",
"components.FilterOptions.FILTER_TYPES._lte": "daha düşük ya da eşit",
"components.FilterOptions.FILTER_TYPES._ne": "eşit değil",
"components.Input.error.attribute.key.taken": "Bu değer zaten var.",
"components.Input.error.attribute.sameKeyAndName": "Eşit olamaz",
"components.Input.error.attribute.taken": "Bu alan ismi zaten var.",

View File

@ -111,6 +111,16 @@
"components.AutoReloadBlocker.description": "Chạy Strapi với một trong các lệnh sau:",
"components.AutoReloadBlocker.header": "Tính năng Tải lại bị bắt buộc cho plugin này.",
"components.ErrorBoundary.title": "Điều gì đó không ổn...",
"components.FilterOptions.FILTER_TYPES.=": "là",
"components.FilterOptions.FILTER_TYPES._contains": "chứa",
"components.FilterOptions.FILTER_TYPES._containss": "chứa (phân biệt chữ hoa thường)",
"components.FilterOptions.FILTER_TYPES._gt": "lớn hơn",
"components.FilterOptions.FILTER_TYPES._gte": "lớn hơn hoặc bằng",
"components.FilterOptions.FILTER_TYPES._lt": "nhỏ hơn",
"components.FilterOptions.FILTER_TYPES._lte": "nhỏ hơn hoặc bằng",
"components.FilterOptions.FILTER_TYPES._ne": "không bằng",
"components.FilterOptions.FILTER_TYPES._in": "khớp với bất cứ giá trị nào có trong mảng giá trị",
"components.FilterOptions.FILTER_TYPES._nin": "không khớp với bất cứ giá trị nào có trong mảng giá trị",
"components.Input.error.attribute.key.taken": "Giá trị này đã tồn tại",
"components.Input.error.attribute.sameKeyAndName": "Không thể bằng nhau",
"components.Input.error.attribute.taken": "Trường nhập liệu này đã tồn tại",

View File

@ -108,7 +108,7 @@
"app.components.listPlugins.title.plural": "{number} 个插件已安装",
"app.components.listPlugins.title.singular": "{number} 个插件已安装",
"app.components.listPluginsPage.deletePlugin.error": "卸载插件时出错",
"app.links.configure-view": "配置视图",
"app.utils.SelectOption.defaultMessage": " ",
@ -117,6 +117,16 @@
"components.AutoReloadBlocker.description": "使用以下命令中的一个来运行 Strapi",
"components.AutoReloadBlocker.header": "这个插件需要重新加载特性。",
"components.ErrorBoundary.title": "哪里出问题了…",
"components.FilterOptions.FILTER_TYPES.=": "等于",
"components.FilterOptions.FILTER_TYPES._contains": "包含",
"components.FilterOptions.FILTER_TYPES._containss": "包含(区分大小写)",
"components.FilterOptions.FILTER_TYPES._gt": "大于",
"components.FilterOptions.FILTER_TYPES._gte": "大于等于",
"components.FilterOptions.FILTER_TYPES._lt": "小于",
"components.FilterOptions.FILTER_TYPES._lte": "小于等于",
"components.FilterOptions.FILTER_TYPES._ne": "不等于",
"components.FilterOptions.FILTER_TYPES._in": "包含在指定数组中",
"components.FilterOptions.FILTER_TYPES._nin": "不包含在指定数组中",
"components.Input.error.attribute.key.taken": "此值已经存在",
"components.Input.error.attribute.sameKeyAndName": "不能相等",
"components.Input.error.attribute.taken": "此字段名称已经存在",

View File

@ -97,6 +97,14 @@
"app.utils.placeholder.defaultMessage": " ",
"components.AutoReloadBlocker.header": "這個擴充功能需要自動重新整理功能才能載入",
"components.ErrorBoundary.title": "有錯誤發生...",
"components.FilterOptions.FILTER_TYPES.=": "等於",
"components.FilterOptions.FILTER_TYPES._contains": "包含",
"components.FilterOptions.FILTER_TYPES._containss": "包含(區分大小寫)",
"components.FilterOptions.FILTER_TYPES._gt": "大於",
"components.FilterOptions.FILTER_TYPES._gte": "大於等於",
"components.FilterOptions.FILTER_TYPES._lt": "小於",
"components.FilterOptions.FILTER_TYPES._lte": "小於等於",
"components.FilterOptions.FILTER_TYPES._ne": "不等於",
"components.Input.error.attribute.key.taken": "這個數值已經存在了",
"components.Input.error.attribute.sameKeyAndName": "不能等於",
"components.Input.error.attribute.taken": "這個欄位名稱已經存在了",

View File

@ -22,11 +22,11 @@
"@babel/preset-env": "^7.4.3",
"@babel/preset-react": "^7.0.0",
"@babel/runtime": "^7.4.3",
"@buffetjs/core": "3.0.0-next.1",
"@buffetjs/custom": "3.0.0-next.1",
"@buffetjs/hooks": "3.0.0-next.1",
"@buffetjs/icons": "3.0.0-next.1",
"@buffetjs/styles": "3.0.0-next.1",
"@buffetjs/core": "3.0.0-next.3",
"@buffetjs/custom": "3.0.0-next.3",
"@buffetjs/hooks": "3.0.0-next.3",
"@buffetjs/icons": "3.0.0-next.3",
"@buffetjs/styles": "3.0.0-next.3",
"@buffetjs/utils": "^2.0.0",
"@fortawesome/fontawesome-free": "^5.11.2",
"@fortawesome/fontawesome-svg-core": "^1.2.25",

View File

@ -0,0 +1,13 @@
import styled from 'styled-components';
const RemoveButton = styled.button`
display: flex;
justify-items: center;
height: 13px;
padding-left: 10px;
padding-right: 10px;
margin-left: 10px;
border-left: 2px solid rgba(0, 126, 255, 0.1);
`;
export default RemoveButton;

View File

@ -0,0 +1,22 @@
import styled from 'styled-components';
const Wrapper = styled.div`
display: flex;
align-items: center;
height: 30px;
margin-bottom: 6px;
margin-right: 10px;
padding-left: 10px;
background: rgba(0, 126, 255, 0.08);
border: 1px solid rgba(0, 126, 255, 0.24);
border-radius: 2px;
line-height: 28px;
color: #007eff;
font-size: 13px;
-webkit-font-smoothing: antialiased;
> span:nth-child(2) {
font-weight: 700;
}
`;
export default Wrapper;

View File

@ -0,0 +1,42 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { upperFirst } from 'lodash';
import Wrapper from './Wrapper';
import RemoveButton from './RemoveButton';
import Close from '../../svgs/Close';
function Filter({ label, onClick }) {
const { name, filter, value } = label;
return (
<Wrapper>
<span>{upperFirst(name)}&nbsp;</span>
<FormattedMessage
id={`components.FilterOptions.FILTER_TYPES.${filter}`}
/>
<span>&nbsp;{value}</span>
<RemoveButton type="button" onClick={onClick}>
<Close width="11px" height="11px" fill="#007eff" />
</RemoveButton>
</Wrapper>
);
}
Filter.defaultProps = {
children: null,
onClick: () => {},
};
Filter.propTypes = {
children: PropTypes.node,
label: PropTypes.shape({
name: PropTypes.string,
filter: PropTypes.string,
value: PropTypes.string,
}),
onClick: PropTypes.func,
};
export default Filter;

View File

@ -15,6 +15,7 @@ export { default as ContainerFluid } from './components/ContainerFluid';
export { default as EmptyAttributesBlock } from './components/EmptyAttributesBlock';
export { default as ErrorBoundary } from './components/ErrorBoundary';
export { default as ExtendComponent } from './components/ExtendComponent';
export { default as FilterButton } from './components/FilterButton';
export { default as GlobalPagination } from './components/GlobalPagination';
export { default as HeaderNav } from './components/HeaderNav';
export { default as HeaderModal } from './components/HeaderModal';
@ -94,8 +95,10 @@ export { default as useQuery } from './hooks/useQuery';
export { default as auth } from './utils/auth';
export { default as cleanData } from './utils/cleanData';
export { default as difference } from './utils/difference';
export { default as dateFormats } from './utils/dateFormats';
export { default as translatedErrors } from './utils/translatedErrors';
export { darken } from './utils/colors';
export { default as getFilterType } from './utils/getFilterType';
export { default as getQueryParameters } from './utils/getQueryParameters';
export { default as injectHooks } from './utils/injectHooks';
export { default as validateInput } from './utils/inputsValidations';

View File

@ -1,8 +1,8 @@
const DATE_FORMATS = {
const dateFormats = {
date: 'dddd, MMMM Do YYYY',
datetime: 'dddd, MMMM Do YYYY HH:mm',
time: 'HH:mm A',
timestamp: 'dddd, MMMM Do YYYY HH:mm',
};
export default DATE_FORMATS;
export default dateFormats;

View File

@ -0,0 +1,108 @@
const getFilterType = type => {
switch (type) {
case 'string':
case 'text':
case 'password':
case 'email':
return [
{
id: 'components.FilterOptions.FILTER_TYPES.=',
value: '=',
},
{
id: 'components.FilterOptions.FILTER_TYPES._ne',
value: '_ne',
},
{
id: 'components.FilterOptions.FILTER_TYPES._lt',
value: '_lt',
},
{
id: 'components.FilterOptions.FILTER_TYPES._lte',
value: '_lte',
},
{
id: 'components.FilterOptions.FILTER_TYPES._gt',
value: '_gt',
},
{
id: 'components.FilterOptions.FILTER_TYPES._gte',
value: '_gte',
},
{
id: 'components.FilterOptions.FILTER_TYPES._contains',
value: '_contains',
},
{
id: 'components.FilterOptions.FILTER_TYPES._containss',
value: '_containss',
},
{
id: 'components.FilterOptions.FILTER_TYPES._in',
value: '_in',
},
{
id: 'components.FilterOptions.FILTER_TYPES._nin',
value: '_nin',
},
];
case 'integer':
case 'biginteger':
case 'float':
case 'decimal':
case 'date':
case 'datetime':
case 'time':
case 'timestamp':
case 'timestampUpdate':
return [
{
id: 'components.FilterOptions.FILTER_TYPES.=',
value: '=',
},
{
id: 'components.FilterOptions.FILTER_TYPES._ne',
value: '_ne',
},
{
id: 'components.FilterOptions.FILTER_TYPES._lt',
value: '_lt',
},
{
id: 'components.FilterOptions.FILTER_TYPES._lte',
value: '_lte',
},
{
id: 'components.FilterOptions.FILTER_TYPES._gt',
value: '_gt',
},
{
id: 'components.FilterOptions.FILTER_TYPES._gte',
value: '_gte',
},
// FIXME: commenting these filters as I am not sure if the UI
// corresponds to the filter
// {
// id: 'components.FilterOptions.FILTER_TYPES._in',
// value: '_in',
// },
// {
// id: 'components.FilterOptions.FILTER_TYPES._nin',
// value: '_nin',
// },
];
default:
return [
{
id: 'components.FilterOptions.FILTER_TYPES.=',
value: '=',
},
{
id: 'components.FilterOptions.FILTER_TYPES._ne',
value: '_ne',
},
];
}
};
export default getFilterType;

View File

@ -3,9 +3,12 @@ import { withRouter } from 'react-router';
import PropTypes from 'prop-types';
import { get, isEmpty, isNull, isObject, toLower, toString } from 'lodash';
import moment from 'moment';
import { IcoContainer, useGlobalContext } from 'strapi-helper-plugin';
import {
IcoContainer,
useGlobalContext,
dateFormats,
} from 'strapi-helper-plugin';
import useListView from '../../hooks/useListView';
import DATE_FORMATS from '../../utils/DATE_FORMATS';
import CustomInputCheckbox from '../CustomInputCheckbox';
import MediaPreviewList from '../MediaPreviewList';
import { ActionContainer, Truncate, Truncated } from './styledComponents';
@ -42,7 +45,7 @@ const getDisplayedValue = (type, value, name) => {
? JSON.stringify(value)
: value;
return dateToUtcTime(date).format(DATE_FORMATS[type]);
return dateToUtcTime(date).format(dateFormats[type]);
}
case 'password':
return '••••••••';
@ -63,7 +66,7 @@ const getDisplayedValue = (type, value, name) => {
};
const date = moment().set(timeObj);
return date.format(DATE_FORMATS.time);
return date.format(dateFormats.time);
}
default:
return '-';

View File

@ -63,7 +63,7 @@ function TableHeader({ headers, isBulkable }) {
{header.label}
{sortBy === header.name && (
<Arrow className={`${sortOrder === 'ASC' && 'isAsc'}`} />
<Arrow fill="#212529" isUp={sortOrder === 'ASC' && 'isAsc'} />
)}
</span>
</th>

View File

@ -1,6 +1,7 @@
/* eslint-disable */
import React from 'react';
import styled, { css } from 'styled-components';
import { Carret } from '@buffetjs/icons';
const Table = styled.table`
border-radius: 3px;
@ -94,21 +95,14 @@ const TableRow = styled.tr`
}
`;
const Arrow = styled.div`
&:after {
content: '\f0d8';
font-family: 'FontAwesome';
font-size: 13px;
font-weight: 600;
position: absolute;
top: 0px;
right: -12px;
}
&.isAsc {
&:after {
transform: rotateZ(180deg);
}
}
const Arrow = styled(props => <Carret {...props} />)`
margin-left: 5px;
${({ isUp }) =>
isUp &&
`
transform: rotateZ(180deg);
`}
`;
const Truncate = styled.div``;

View File

@ -4,13 +4,12 @@ import PropTypes from 'prop-types';
import { capitalize, get } from 'lodash';
import { Collapse } from 'reactstrap';
import { FormattedMessage } from 'react-intl';
import { PluginHeader } from 'strapi-helper-plugin';
import { PluginHeader, getFilterType } from 'strapi-helper-plugin';
import pluginId from '../../pluginId';
import useListView from '../../hooks/useListView';
import Container from '../Container';
import getFilterType from '../FilterPickerOption/utils';
import FilterPickerOption from '../FilterPickerOption';
import { Flex, Span, Wrapper } from './components';

View File

@ -1,5 +1,5 @@
import { fromJS } from 'immutable';
import getFilterType from '../FilterPickerOption/utils';
import { getFilterType } from 'strapi-helper-plugin';
function init(initialState, { name, type }) {
// Create the first filter

View File

@ -40,7 +40,7 @@ const getInputType = attrType => {
function Input({ type, ...rest }) {
const Component = getInputType(type);
let style = type !== 'time' ? { width: '210px', paddingTop: '4px' } : {};
let style = type !== 'time' ? { width: '210px' } : {};
if (['integer', 'biginteger', 'float', 'decimal'].includes(type)) {
style = { marginRight: '20px' };

View File

@ -1,13 +1,12 @@
import React, { memo } from 'react';
import { get, isEmpty } from 'lodash';
import PropTypes from 'prop-types';
import { CircleButton } from 'strapi-helper-plugin';
import { CircleButton, getFilterType } from 'strapi-helper-plugin';
import { Select } from '@buffetjs/core';
import { InputWrapper, Wrapper } from './components';
import Input from './Input';
import Option from './Option';
import getFilters from './utils';
const styles = {
select: {
@ -20,11 +19,6 @@ const styles = {
marginLeft: '10px',
marginRight: '10px',
},
input: {
width: '210px',
marginRight: '10px',
paddingTop: '4px',
},
};
function FilterPickerOption({
@ -38,7 +32,7 @@ function FilterPickerOption({
showAddButton,
type,
}) {
const filtersOptions = getFilters(type);
const filtersOptions = getFilterType(type);
return (
<Wrapper borderLeft={!isEmpty(value)}>

View File

@ -1,109 +0,0 @@
const getFilters = type => {
switch (type) {
case 'string':
case 'text':
case 'password':
case 'email':
return [
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES.=',
value: '=',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._ne',
value: '_ne',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._lt',
value: '_lt',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._lte',
value: '_lte',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._gt',
value: '_gt',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._gte',
value: '_gte',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._contains',
value: '_contains',
},
{
id:
'content-manager.components.FilterOptions.FILTER_TYPES._containss',
value: '_containss',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._in',
value: '_in',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._nin',
value: '_nin',
},
];
case 'integer':
case 'biginteger':
case 'float':
case 'decimal':
case 'date':
case 'datetime':
case 'time':
case 'timestamp':
case 'timestampUpdate':
return [
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES.=',
value: '=',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._ne',
value: '_ne',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._lt',
value: '_lt',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._lte',
value: '_lte',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._gt',
value: '_gt',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._gte',
value: '_gte',
},
// FIXME: commenting these filters as I am not sure if the UI
// corresponds to the filter
// {
// id: 'content-manager.components.FilterOptions.FILTER_TYPES._in',
// value: '_in',
// },
// {
// id: 'content-manager.components.FilterOptions.FILTER_TYPES._nin',
// value: '_nin',
// },
];
default:
return [
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES.=',
value: '=',
},
{
id: 'content-manager.components.FilterOptions.FILTER_TYPES._ne',
value: '_ne',
},
];
}
};
export default getFilters;

View File

@ -1,12 +1,11 @@
import React, { forwardRef } from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import { Grab } from '@buffetjs/icons';
import { Carret, Grab } from '@buffetjs/icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import pluginId from '../../pluginId';
import PreviewCarret from '../PreviewCarret';
import BannerWrapper from './BannerWrapper';
import CarretTop from './CarretTop';
/* eslint-disable jsx-a11y/no-static-element-interactions */
@ -45,7 +44,7 @@ const Banner = forwardRef(
{isDragging && <PreviewCarret isComponent />}
<>
<span className="img-wrapper" style={{ display }}>
<CarretTop isOpen={isOpen} hasErrors={hasErrors} />
<Carret isOpen={isOpen} hasErrors={hasErrors} />
</span>
<FormattedMessage

View File

@ -1,11 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { get, toString, upperFirst } from 'lodash';
import { get, toString } from 'lodash';
import moment from 'moment';
import pluginId from '../../pluginId';
import DATE_FORMATS from '../../utils/DATE_FORMATS';
import { FilterWrapper, Remove, Separator } from './components';
import { dateFormats, FilterButton } from 'strapi-helper-plugin';
function Filter({
changeParams,
@ -27,9 +24,9 @@ function Filter({
let format;
if (type === 'date' || type === 'timestamp') {
format = DATE_FORMATS.date;
format = dateFormats.date;
} else {
format = DATE_FORMATS.datetime;
format = dateFormats.datetime;
}
displayedValue = moment
@ -38,25 +35,25 @@ function Filter({
.format(format);
}
return (
<FilterWrapper>
<span>{upperFirst(name)}&nbsp;</span>
<FormattedMessage
id={`${pluginId}.components.FilterOptions.FILTER_TYPES.${filter}`}
/>
<span>&nbsp;{displayedValue}</span>
<Separator />
<Remove
onClick={() => {
const updatedFilters = filters.slice().filter((_, i) => i !== index);
const label = {
name,
filter,
value: displayedValue,
};
if (isFilterPickerOpen) {
toggleFilterPickerState();
}
changeParams({ target: { name: 'filters', value: updatedFilters } });
}}
/>
</FilterWrapper>
return (
<FilterButton
onClick={() => {
const updatedFilters = filters.slice().filter((_, i) => i !== index);
if (isFilterPickerOpen) {
toggleFilterPickerState();
}
changeParams({ target: { name: 'filters', value: updatedFilters } });
}}
label={label}
type={type}
/>
);
}

View File

@ -5,14 +5,6 @@
"components.DraggableAttr.edit": "اضغط لتعديل",
"components.EmptyAttributesBlock.button": "الذهاب الى صفحة الإعدادات",
"components.EmptyAttributesBlock.description": "يمكنك تغيير إعداداتك",
"components.FilterOptions.FILTER_TYPES.=": "هو",
"components.FilterOptions.FILTER_TYPES._contains": "يحتوي",
"components.FilterOptions.FILTER_TYPES._containss": "يحتوي (حساس لحالة الأحرف)",
"components.FilterOptions.FILTER_TYPES._gt": "اكبر من",
"components.FilterOptions.FILTER_TYPES._gte": "اكبر من او يساوي",
"components.FilterOptions.FILTER_TYPES._lt": "اقل من",
"components.FilterOptions.FILTER_TYPES._lte": "اقل من او يساوي",
"components.FilterOptions.FILTER_TYPES._ne": "ليس",
"components.FilterOptions.button.apply": "تطبيق",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "تطبيق",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "مسح الكل",

View File

@ -14,16 +14,6 @@
"components.EmptyAttributesBlock.button": "Přejít k nastavení",
"components.EmptyAttributesBlock.description": "Můžete upravit svá nastavení",
"components.FieldItem.linkToComponentLayout": "Nastavit rozložení komponentu",
"components.FilterOptions.FILTER_TYPES.=": "je",
"components.FilterOptions.FILTER_TYPES._contains": "obsahuje",
"components.FilterOptions.FILTER_TYPES._containss": "obsahuje (citlivé na velká písmena)",
"components.FilterOptions.FILTER_TYPES._gt": "je větší než",
"components.FilterOptions.FILTER_TYPES._gte": "je větší nebo rovno než",
"components.FilterOptions.FILTER_TYPES._lt": "je menší než",
"components.FilterOptions.FILTER_TYPES._lte": "je menší nebo rovno než",
"components.FilterOptions.FILTER_TYPES._ne": "není",
"components.FilterOptions.FILTER_TYPES._in": "odpovídá jakékoliv hodnotě v poli hodnot",
"components.FilterOptions.FILTER_TYPES._nin": "neodpovídá ani jedné hodnotě v poli hodnot",
"components.FilterOptions.button.apply": "Aplikovat",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Aplikovat",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Smazat vše",

View File

@ -5,14 +5,6 @@
"components.DraggableAttr.edit": "Klicken zum Bearbeiten",
"components.EmptyAttributesBlock.button": "Geh zu den Einstellungen",
"components.EmptyAttributesBlock.description": "Du kannst deine Einstellungen ändern",
"components.FilterOptions.FILTER_TYPES.=": "ist",
"components.FilterOptions.FILTER_TYPES._contains": "enthält",
"components.FilterOptions.FILTER_TYPES._containss": "enthält (Groß-/Kleinschreibung beachten)",
"components.FilterOptions.FILTER_TYPES._gt": "ist größer als",
"components.FilterOptions.FILTER_TYPES._gte": "ist größer oder gleich als",
"components.FilterOptions.FILTER_TYPES._lt": "ist kleiner als",
"components.FilterOptions.FILTER_TYPES._lte": "ist kleiner oder gleich als",
"components.FilterOptions.FILTER_TYPES._ne": "ist nicht",
"components.FilterOptions.button.apply": "Anwenden",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Anwenden",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Alle löschen",

View File

@ -14,16 +14,6 @@
"components.EmptyAttributesBlock.button": "Go to settings page",
"components.EmptyAttributesBlock.description": "You can change your settings",
"components.FieldItem.linkToComponentLayout": "Set the component's layout",
"components.FilterOptions.FILTER_TYPES.=": "is",
"components.FilterOptions.FILTER_TYPES._contains": "contains",
"components.FilterOptions.FILTER_TYPES._containss": "contains (case sensitive)",
"components.FilterOptions.FILTER_TYPES._gt": "is greater than",
"components.FilterOptions.FILTER_TYPES._gte": "is greater than or equal to",
"components.FilterOptions.FILTER_TYPES._lt": "is lower than",
"components.FilterOptions.FILTER_TYPES._lte": "is lower than or equal to",
"components.FilterOptions.FILTER_TYPES._ne": "is not",
"components.FilterOptions.FILTER_TYPES._in": "matches any value in the array of values",
"components.FilterOptions.FILTER_TYPES._nin": "doesn't match any value in the array of values",
"components.FilterOptions.button.apply": "Apply",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Apply",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Clear all",

View File

@ -5,16 +5,6 @@
"components.DraggableAttr.edit": "Click para editar",
"components.EmptyAttributesBlock.button": "Ir a la página de configuraciones",
"components.EmptyAttributesBlock.description": "Usted puede cambiar sus configuraciones",
"components.FilterOptions.FILTER_TYPES.=": "es",
"components.FilterOptions.FILTER_TYPES._contains": "contiene",
"components.FilterOptions.FILTER_TYPES._containss": "contiene (distinguiendo mayúsculas y minúsculas)",
"components.FilterOptions.FILTER_TYPES._gt": "es mayor que",
"components.FilterOptions.FILTER_TYPES._gte": "es mayor o igual que",
"components.FilterOptions.FILTER_TYPES._lt": "es menor que",
"components.FilterOptions.FILTER_TYPES._lte": "es menor o igual que",
"components.FilterOptions.FILTER_TYPES._ne": "no es",
"components.FilterOptions.FILTER_TYPES._in": "coincide con cualquier valor de la lista de registros",
"components.FilterOptions.FILTER_TYPES._nin": "no coincide con ningún valor de la lista de registros",
"components.FilterOptions.button.apply": "Aplicar",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Aplicar",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Limpiar todo",

View File

@ -14,14 +14,6 @@
"components.EmptyAttributesBlock.button": "Voir la page des configurations",
"components.EmptyAttributesBlock.description": "Vous pouvez modifiez vos paramètres",
"components.FieldItem.linkToComponentLayout": "Modifier le layout du composant",
"components.FilterOptions.FILTER_TYPES.=": "est",
"components.FilterOptions.FILTER_TYPES._contains": "contient",
"components.FilterOptions.FILTER_TYPES._containss": "contient (sensible à la casse)",
"components.FilterOptions.FILTER_TYPES._gt": "supérieur à",
"components.FilterOptions.FILTER_TYPES._gte": "supérieur ou égal à",
"components.FilterOptions.FILTER_TYPES._lt": "inférieur à",
"components.FilterOptions.FILTER_TYPES._lte": "inférieur ou égal à",
"components.FilterOptions.FILTER_TYPES._ne": "n'est pas",
"components.FilterOptions.button.apply": "Appliquer",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Appliquer",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Tout supprimer",

View File

@ -4,15 +4,7 @@
"components.AddFilterCTA.hide": "Filtri",
"components.DraggableAttr.edit": "Clicca per modificare",
"components.EmptyAttributesBlock.button": "Vai alla pagina delle impostazioni",
"components.EmptyAttributesBlock.description" : "Puoi cambiare le tue impostazioni",
"components.FilterOptions.FILTER_TYPES.=": "si",
"components.FilterOptions.FILTER_TYPES._contains": "contiene",
"components.FilterOptions.FILTER_TYPES._containss": "contiene (maiuscole e minuscole)",
"components.FilterOptions.FILTER_TYPES._gt": "è maggiore di",
"components.FilterOptions.FILTER_TYPES._gte": "è maggiore o uguale a",
"components.FilterOptions.FILTER_TYPES._lt": "è inferiore",
"components.FilterOptions.FILTER_TYPES._lte": "è inferiore o uguale a",
"components.FilterOptions.FILTER_TYPES._ne": "non è",
"components.EmptyAttributesBlock.description": "Puoi cambiare le tue impostazioni",
"components.FilterOptions.button.apply": "Applica",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Applica",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Cancella tutto",

View File

@ -5,14 +5,6 @@
"components.DraggableAttr.edit": "クリックして編集",
"components.EmptyAttributesBlock.button": "設定ページに移動",
"components.EmptyAttributesBlock.description": "設定を変更することができます",
"components.FilterOptions.FILTER_TYPES.=": "は",
"components.FilterOptions.FILTER_TYPES._contains": "含まれる",
"components.FilterOptions.FILTER_TYPES._containss": "含まれる(大文字と小文字を区別)",
"components.FilterOptions.FILTER_TYPES._gt": "より大きい",
"components.FilterOptions.FILTER_TYPES._gte": "より大きい、もしくは、等しい",
"components.FilterOptions.FILTER_TYPES._lt": "より低い",
"components.FilterOptions.FILTER_TYPES._lte": "より低い、もしくは、等しい",
"components.FilterOptions.FILTER_TYPES._ne": "ではない",
"components.FilterOptions.button.apply": "適用",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "適用",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "すべてクリア",

View File

@ -10,16 +10,6 @@
"components.EmptyAttributesBlock.button": "설정 페이지 이동",
"components.EmptyAttributesBlock.description": "설정을 변경할 수 있습니다.",
"components.FieldItem.linkToGroupLayout": "그룹 레이아웃 설정",
"components.FilterOptions.FILTER_TYPES.=": "같음",
"components.FilterOptions.FILTER_TYPES._contains": "포함",
"components.FilterOptions.FILTER_TYPES._containss": "포함(대소문자 구분)",
"components.FilterOptions.FILTER_TYPES._gt": "큼",
"components.FilterOptions.FILTER_TYPES._gte": "크거나 같음",
"components.FilterOptions.FILTER_TYPES._lt": "작음",
"components.FilterOptions.FILTER_TYPES._lte": "작거나 같음",
"components.FilterOptions.FILTER_TYPES._ne": "같지 않음",
"components.FilterOptions.FILTER_TYPES._in": "배열중에 일치하는 값이 있음",
"components.FilterOptions.FILTER_TYPES._nin": "배열중에 일치하는 값이 없음",
"components.FilterOptions.button.apply": "적용",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "적용",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "모두 재설정",
@ -139,4 +129,4 @@
"success.record.save": "저장",
"notification.info.minimumFields": "표시될 필드가 최소 하나 이상 필요합니다.",
"notification.upload.error": "파일 업로드 중에 에러가 발생했습니다."
}
}

View File

@ -5,14 +5,6 @@
"components.DraggableAttr.edit": "Klik om aan te passen",
"components.EmptyAttributesBlock.button": "Ga naar instellingen",
"components.EmptyAttributesBlock.description": "U kunt uw instellingen aanpassen",
"components.FilterOptions.FILTER_TYPES.=": "is",
"components.FilterOptions.FILTER_TYPES._contains": "bevat",
"components.FilterOptions.FILTER_TYPES._containss": "bevat (hoofdletter gevoelig)",
"components.FilterOptions.FILTER_TYPES._gt": "is groter dan",
"components.FilterOptions.FILTER_TYPES._gte": "is groter dan of gelijk aan",
"components.FilterOptions.FILTER_TYPES._lt": "is lager dan",
"components.FilterOptions.FILTER_TYPES._lte": "is lager dan of gelijk aan",
"components.FilterOptions.FILTER_TYPES._ne": "is niet",
"components.FilterOptions.button.apply": "Toepassen",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Toepassen",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Alles legen",

View File

@ -11,16 +11,6 @@
"components.EmptyAttributesBlock.button": "Przejdź do ustawień",
"components.EmptyAttributesBlock.description": "Możesz zmienić ustawienia",
"components.FieldItem.linkToComponentLayout": "Ustaw układ komponentu",
"components.FilterOptions.FILTER_TYPES.=": "jest identyczne z",
"components.FilterOptions.FILTER_TYPES._contains": "zawiera",
"components.FilterOptions.FILTER_TYPES._containss": "zawiera (rozróżnianie wielkości liter)",
"components.FilterOptions.FILTER_TYPES._gt": "jest większe od",
"components.FilterOptions.FILTER_TYPES._gte": "jest większe od lub równe",
"components.FilterOptions.FILTER_TYPES._in": "dopasuj jakąkolwiek wartość z tablicy wartości",
"components.FilterOptions.FILTER_TYPES._lt": "jest mniejsze od",
"components.FilterOptions.FILTER_TYPES._lte": "jest mniejsze od lub równe",
"components.FilterOptions.FILTER_TYPES._ne": "jest różne od",
"components.FilterOptions.FILTER_TYPES._nin": "nie znaleziono pasującej wartości w tablicy wartości",
"components.FilterOptions.button.apply": "Zastosuj",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Zastosuj",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Wyczyść",
@ -74,7 +64,7 @@
"containers.SettingPage.listSettings.title": "Lista (ustawienia)",
"containers.SettingPage.editSettings.entry.title": "Tytuł wpisu",
"containers.SettingPage.editSettings.entry.title.description": "Ustaw wyświetlane pole swojego wpisu",
"containers.SettingsPage.Block.generalSettings.title": "Ogólne",
"containers.SettingsPage.Block.generalSettings.title": "Ogólne",
"containers.SettingPage.layout": "Układ",
"containers.SettingPage.addField": "Dodaj nowy atrybut",
"containers.SettingPage.editSettings.description": "Przeciągnij i upuś pola by zbudować układ",

View File

@ -5,14 +5,6 @@
"components.DraggableAttr.edit": "Clique para editar",
"components.EmptyAttributesBlock.button": "Ir para página de configurações",
"components.EmptyAttributesBlock.description": "Você pode alterar suas configurações",
"components.FilterOptions.FILTER_TYPES.=": "é",
"components.FilterOptions.FILTER_TYPES._contains": "contém",
"components.FilterOptions.FILTER_TYPES._containss": "contém (case sensitive)",
"components.FilterOptions.FILTER_TYPES._gt": "é maior que",
"components.FilterOptions.FILTER_TYPES._gte": "é maior que ou igual à",
"components.FilterOptions.FILTER_TYPES._lt": "é menor que",
"components.FilterOptions.FILTER_TYPES._lte": "é menor que ou igual à",
"components.FilterOptions.FILTER_TYPES._ne": "não é",
"components.FilterOptions.button.apply": "Aplicar",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Aplicar",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Limpar tudo",

View File

@ -5,14 +5,6 @@
"components.EmptyAttributesBlock.button": "Ir para a página de configurações",
"components.EmptyAttributesBlock.description": "Pode alterar as configurações",
"components.FilterOptions.button.apply": "Aplicar",
"components.FilterOptions.FILTER_TYPES.=": "é",
"components.FilterOptions.FILTER_TYPES._contains": "contém",
"components.FilterOptions.FILTER_TYPES._containss": "contém (case sensitive)",
"components.FilterOptions.FILTER_TYPES._gt": "é maior que",
"components.FilterOptions.FILTER_TYPES._gte": "é maior que ou igual à",
"components.FilterOptions.FILTER_TYPES._lt": "é menor que",
"components.FilterOptions.FILTER_TYPES._lte": "é menor que ou igual à",
"components.FilterOptions.FILTER_TYPES._ne": "não é",
"components.FiltersPickWrapper.hide": "Esconder",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Aplicar",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Limpar tudo",

View File

@ -8,14 +8,6 @@
"containers.Edit.addAnItem": "Добавить элемент",
"containers.Edit.clickToJump": "Нажмите для перехода к записи",
"containers.Edit.seeDetails": "Подробнее",
"components.FilterOptions.FILTER_TYPES.=": "равно",
"components.FilterOptions.FILTER_TYPES._contains": "содержит",
"components.FilterOptions.FILTER_TYPES._containss": "содержит (с учетом регистра)",
"components.FilterOptions.FILTER_TYPES._gt": "больше чем",
"components.FilterOptions.FILTER_TYPES._gte": "больше или равно",
"components.FilterOptions.FILTER_TYPES._lt": "меньше чем",
"components.FilterOptions.FILTER_TYPES._lte": "меньше или равно",
"components.FilterOptions.FILTER_TYPES._ne": "не равно",
"components.FilterOptions.button.apply": "Применить",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Применить",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Очистить все",

View File

@ -14,16 +14,6 @@
"components.EmptyAttributesBlock.button": "Prejsť do nastavení",
"components.EmptyAttributesBlock.description": "Môžte upravovať nastavenia",
"components.FieldItem.linkToComponentLayout": "Nastaviť rozloženie komponenty",
"components.FilterOptions.FILTER_TYPES.=": "je",
"components.FilterOptions.FILTER_TYPES._contains": "obsahuje",
"components.FilterOptions.FILTER_TYPES._containss": "obsahuje (záleží na veľkosti písmen)",
"components.FilterOptions.FILTER_TYPES._gt": "je väčšie ako",
"components.FilterOptions.FILTER_TYPES._gte": "je väčšie ako alebo rovné",
"components.FilterOptions.FILTER_TYPES._lt": "je menšie ako",
"components.FilterOptions.FILTER_TYPES._lte": "je menšie ako alebo rovné",
"components.FilterOptions.FILTER_TYPES._ne": "nie je",
"components.FilterOptions.FILTER_TYPES._in": "obsahuje hodnotu z poľa",
"components.FilterOptions.FILTER_TYPES._nin": "neobsahuje žiadnu hodnotu z poľa",
"components.FilterOptions.button.apply": "Použiť",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Použiť",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Zmazať všetko",

View File

@ -5,14 +5,6 @@
"components.DraggableAttr.edit": "Düzenlemek için tıklayın",
"components.EmptyAttributesBlock.button": "Ayarlar sayfasına git",
"components.EmptyAttributesBlock.description": "Ayarlarınızı değiştirebilirsiniz",
"components.FilterOptions.FILTER_TYPES.=": "eşit",
"components.FilterOptions.FILTER_TYPES._contains": "içermek",
"components.FilterOptions.FILTER_TYPES._containss": "içermek (büyük-küçük harfe duyarlı)",
"components.FilterOptions.FILTER_TYPES._gt": "daha yüksek",
"components.FilterOptions.FILTER_TYPES._gte": "daha yüksek ya da eşit",
"components.FilterOptions.FILTER_TYPES._lt": "daha düşük",
"components.FilterOptions.FILTER_TYPES._lte": "daha düşük ya da eşit",
"components.FilterOptions.FILTER_TYPES._ne": "eşit değil",
"components.FilterOptions.button.apply": "Uygula",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Uygula",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Hepsini temizle",

View File

@ -10,16 +10,6 @@
"components.EmptyAttributesBlock.button": "Đến trang cài đặt",
"components.EmptyAttributesBlock.description": "Bạn có thể thay đổi cài đặt của bạn",
"components.FieldItem.linkToGroupLayout": "Cài đặt bố cục của nhóm",
"components.FilterOptions.FILTER_TYPES.=": "là",
"components.FilterOptions.FILTER_TYPES._contains": "chứa",
"components.FilterOptions.FILTER_TYPES._containss": "chứa (phân biệt chữ hoa thường)",
"components.FilterOptions.FILTER_TYPES._gt": "lớn hơn",
"components.FilterOptions.FILTER_TYPES._gte": "lớn hơn hoặc bằng",
"components.FilterOptions.FILTER_TYPES._lt": "nhỏ hơn",
"components.FilterOptions.FILTER_TYPES._lte": "nhỏ hơn hoặc bằng",
"components.FilterOptions.FILTER_TYPES._ne": "không bằng",
"components.FilterOptions.FILTER_TYPES._in": "khớp với bất cứ giá trị nào có trong mảng giá trị",
"components.FilterOptions.FILTER_TYPES._nin": "không khớp với bất cứ giá trị nào có trong mảng giá trị",
"components.FilterOptions.button.apply": "Áp dụng",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "Áp dụng",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Xóa tất cả",

View File

@ -14,16 +14,6 @@
"components.EmptyAttributesBlock.button": "前往设置页面",
"components.EmptyAttributesBlock.description": "您可以更改设置",
"components.FieldItem.linkToComponentLayout": "设置组件的布局",
"components.FilterOptions.FILTER_TYPES.=": "等于",
"components.FilterOptions.FILTER_TYPES._contains": "包含",
"components.FilterOptions.FILTER_TYPES._containss": "包含(区分大小写)",
"components.FilterOptions.FILTER_TYPES._gt": "大于",
"components.FilterOptions.FILTER_TYPES._gte": "大于等于",
"components.FilterOptions.FILTER_TYPES._lt": "小于",
"components.FilterOptions.FILTER_TYPES._lte": "小于等于",
"components.FilterOptions.FILTER_TYPES._ne": "不等于",
"components.FilterOptions.FILTER_TYPES._in": "包含在指定数组中",
"components.FilterOptions.FILTER_TYPES._nin": "不包含在指定数组中",
"components.FilterOptions.button.apply": "应用",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "应用",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "清除",

View File

@ -5,14 +5,6 @@
"components.DraggableAttr.edit": "點擊以編輯",
"components.EmptyAttributesBlock.button": "前往設定頁面",
"components.EmptyAttributesBlock.description": "您可以變更設定",
"components.FilterOptions.FILTER_TYPES.=": "等於",
"components.FilterOptions.FILTER_TYPES._contains": "包含",
"components.FilterOptions.FILTER_TYPES._containss": "包含(區分大小寫)",
"components.FilterOptions.FILTER_TYPES._gt": "大於",
"components.FilterOptions.FILTER_TYPES._gte": "大於等於",
"components.FilterOptions.FILTER_TYPES._lt": "小於",
"components.FilterOptions.FILTER_TYPES._lte": "小於等於",
"components.FilterOptions.FILTER_TYPES._ne": "不等於",
"components.FilterOptions.button.apply": "套用",
"components.FiltersPickWrapper.PluginHeader.actions.apply": "套用",
"components.FiltersPickWrapper.PluginHeader.actions.clearAll": "清除",

View File

@ -1,35 +0,0 @@
import styled from 'styled-components';
const Wrapper = styled.button`
display: flex;
height: 32px;
margin-right: 10px;
padding: 0 10px;
text-align: center;
background-color: #FFFFFF;
border: 1px solid #E3E9F3;
border-radius: 2px;
line-height: 30px;
font-size: 13px;
font-weight: 500;
font-family: Lato;
-webkit-font-smoothing-antialiased;
cursor: pointer;
&:hover {
background: #F7F8F8;
}
&:focus, &:active {
outline:0;
}
> span {
margin-left: 10px;
}
> svg {
margin: auto;
> g {
stroke: #282b2c;
}
}
`;
export default Wrapper;

View File

@ -1,15 +0,0 @@
import React from 'react';
import { FilterIcon } from 'strapi-helper-plugin';
import { FormattedMessage } from 'react-intl';
import Wrapper from './Wrapper';
const AddFilterCTA = () => {
return (
<Wrapper type="button">
<FilterIcon />
<FormattedMessage id="app.utils.filters" />
</Wrapper>
);
};
export default AddFilterCTA;

View File

@ -2,8 +2,11 @@ import styled from 'styled-components';
const ControlsWrapper = styled.div`
display: flex;
flex-wrap: wrap;
padding-top: 1px;
> div {
margin-right: 10px;
margin-bottom: 6px;
}
`;

View File

@ -5,7 +5,7 @@ import { themePropTypes } from 'strapi-helper-plugin';
import Text from '../Text';
const SortButton = styled(props => (
const DropdownButton = styled(props => (
<Text
as="button"
fontWeight="semiBold"
@ -13,9 +13,10 @@ const SortButton = styled(props => (
{...props}
/>
))`
height: 32px;
display: flex;
align-items: center;
height: 30px;
padding: 0 10px;
line-height: 30px;
background-color: ${({ theme }) => theme.main.colors.white};
border: 1px solid ${({ theme }) => theme.main.colors.darkGrey};
border-radius: ${({ theme }) => theme.main.sizes.borderRadius};
@ -24,26 +25,40 @@ const SortButton = styled(props => (
outline: 0;
}
> svg + span,
> span + svg {
margin-left: 10px;
}
> svg g {
stroke: ${({ theme }) => theme.main.colors.greyDark};
}
${({ isActive, theme }) =>
isActive
? `
background-color: ${theme.main.colors.lightBlue};
border: 1px solid ${theme.main.colors.darkBlue};
`
background-color: ${theme.main.colors.lightBlue};
border: 1px solid ${theme.main.colors.darkBlue};
color: ${theme.main.colors.mediumBlue};
> svg g {
stroke: ${theme.main.colors.mediumBlue};
}
`
: `
&:hover {
background-color: ${theme.main.colors.lightestGrey};
}
`}
&:hover {
background-color: ${theme.main.colors.lightestGrey};
}
`}
`;
SortButton.defaultProps = {
DropdownButton.defaultProps = {
isActive: false,
type: 'button',
};
SortButton.propTypes = {
DropdownButton.propTypes = {
isActive: PropTypes.bool,
type: PropTypes.string,
...themePropTypes,
};
export default SortButton;
export default DropdownButton;

View File

@ -0,0 +1,26 @@
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { themePropTypes } from 'strapi-helper-plugin';
const DropdownSection = styled.div`
display: none;
position: absolute;
top: 38px;
left: 0;
z-index: 1;
background-color: ${({ theme }) => theme.main.colors.white};
border: 1px solid ${({ theme }) => theme.main.colors.darkGrey};
box-shadow: 0 2px 4px ${({ theme }) => theme.main.colors.greyAlpha};
${({ isOpen }) => isOpen && 'display: block;'}
`;
DropdownSection.defaultProps = {
isOpen: false,
};
DropdownSection.propTypes = {
isOpen: PropTypes.bool,
...themePropTypes,
};
export default DropdownSection;

View File

@ -0,0 +1,37 @@
/**
*
* InputWithAutoFocus that programatically manage the autofocus of another one
*/
import React from 'react';
import PropTypes from 'prop-types';
import { DateTime } from '@buffetjs/custom';
import { InputText, Select } from '@buffetjs/core';
import SizeInput from '../SizeInput';
const getInputType = type => {
switch (type) {
case 'datetime':
return DateTime;
case 'size':
return SizeInput;
case 'enum':
return Select;
default:
return InputText;
}
};
function Input({ type, ...rest }) {
const Component = getInputType(type);
return <Component {...rest} autoComplete="off" />;
}
Input.propTypes = {
type: PropTypes.string.isRequired,
};
export default Input;

View File

@ -0,0 +1,8 @@
import styled from 'styled-components';
import { Button } from '@buffetjs/core';
const InputWrapper = styled(Button)`
width: 100%;
`;
export default InputWrapper;

View File

@ -0,0 +1,7 @@
import styled from 'styled-components';
const InputWrapper = styled.div`
margin-bottom: 11px;
`;
export default InputWrapper;

View File

@ -0,0 +1,8 @@
import styled from 'styled-components';
const Wrapper = styled.div`
width: 260px;
padding: 13px 15px;
`;
export default Wrapper;

View File

@ -0,0 +1,102 @@
import React, { useReducer } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { Select } from '@buffetjs/core';
import { getFilterType } from 'strapi-helper-plugin';
import getTrad from '../../utils/getTrad';
import reducer, { initialState } from './reducer';
import Wrapper from './Wrapper';
import Button from './Button';
import InputWrapper from './InputWrapper';
import Input from '../FilterInput';
const FiltersCard = ({ filters, onChange }) => {
const [state, dispatch] = useReducer(reducer, initialState);
const name = state.get('name');
const type = filters[name].type;
const defaultValue = filters[name].defaultValue;
const filtersOptions = getFilterType(type);
const handleChange = ({ target: { name, value } }) => {
dispatch({
type: 'ON_CHANGE',
name,
value,
});
};
const addFilter = () => {
onChange({ target: { value: state.toJS() } });
dispatch({
type: 'RESET_FORM',
});
};
return (
<Wrapper>
<InputWrapper>
<Select
onChange={e => {
// Change the attribute
handleChange(e);
// Change other inputs so it reset values
const {
target: { value },
} = e;
handleChange({ target: { name: 'filter', value: '=' } });
handleChange({
target: { name: 'value', value: filters[value].defaultValue },
});
}}
name="name"
options={Object.keys(filters)}
value={name}
/>
</InputWrapper>
<InputWrapper>
<Select
onChange={handleChange}
name="filter"
options={filtersOptions.map(({ id, value }) => (
<FormattedMessage id={id} key={id}>
{msg => <option value={value}>{msg}</option>}
</FormattedMessage>
))}
value={state.get('filter')}
/>
</InputWrapper>
<InputWrapper>
<Input
type={type}
onChange={handleChange}
name="value"
options={['image', 'video', 'files']}
value={state.get('value') || defaultValue}
/>
</InputWrapper>
<Button icon onClick={addFilter}>
<FormattedMessage id={getTrad('filter.add')} />
</Button>
</Wrapper>
);
};
FiltersCard.defaultProps = {
filters: {},
onChange: () => {},
};
FiltersCard.propTypes = {
filters: PropTypes.object,
onChange: PropTypes.func,
};
export default FiltersCard;

View File

@ -0,0 +1,22 @@
import { fromJS } from 'immutable';
import moment from 'moment';
const initialState = fromJS({
name: 'created_at',
filter: '=',
value: moment(),
});
function reducer(state, action) {
switch (action.type) {
case 'ON_CHANGE':
return state.update(action.name, () => action.value);
case 'RESET_FORM':
return initialState;
default:
return state;
}
}
export default reducer;
export { initialState };

View File

@ -0,0 +1,28 @@
import styled from 'styled-components';
const FiltersListItem = styled.div`
display: flex;
align-items: center;
height: 32px;
margin-bottom: 4px;
background: rgba(0, 126, 255, 0.08);
border: 1px solid rgba(0, 126, 255, 0.24);
border-radius: 2px;
color: #007eff;
font-size: 13px;
span {
padding-left: 15px;
padding-right: 15px;
line-height: 30px;
}
button {
display: flex;
justify-items: center;
height: 13px;
padding-left: 10px;
padding-right: 10px;
border-left: 2px solid rgba(0, 126, 255, 0.1);
}
`;
export default FiltersListItem;

View File

@ -0,0 +1,47 @@
import React from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import { dateFormats, FilterButton } from 'strapi-helper-plugin';
const FiltersList = ({ filters, onClick }) => {
return filters.map((filter, index) => {
const dateToUtcTime = date => moment.parseZone(date).utc();
const { value } = filter;
let displayedValue = filter;
if (dateToUtcTime(value)._isUTC === true) {
displayedValue = {
...filter,
value: dateToUtcTime(value).format(dateFormats.datetime),
};
}
return (
<FilterButton
onClick={() => onClick(index)}
key={JSON.stringify(filter)}
label={displayedValue}
/>
);
});
};
FiltersList.defaultProps = {
filters: [],
onClick: () => {},
};
FiltersList.propTypes = {
onClick: PropTypes.func,
filters: PropTypes.arrayOf(
PropTypes.shape({
name: PropTypes.string.isRequired,
filter: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
})
),
};
export default FiltersList;

View File

@ -0,0 +1,7 @@
import styled from 'styled-components';
const Wrapper = styled.div`
position: relative;
`;
export default Wrapper;

View File

@ -0,0 +1,63 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import { isObject } from 'lodash';
import { FormattedMessage } from 'react-intl';
import { FilterIcon } from 'strapi-helper-plugin';
import DropdownButton from '../DropdownButton';
import DropdownSection from '../DropdownSection';
import Wrapper from './Wrapper';
import FiltersCard from '../FiltersCard';
const FiltersPicker = ({ filters, onChange }) => {
const [isOpen, setIsOpen] = useState(false);
const handleChange = ({ target: { value } }) => {
if (value.value) {
let formattedValue = value;
if (value.value._isAMomentObject === true) {
formattedValue.value = moment(
value.value,
'YYYY-MM-DD HH:mm:ss'
).format();
} else if (isObject(value)) {
formattedValue.value = Object.values(value.value).join('');
}
onChange({ target: { value: formattedValue } });
}
hangleToggle();
};
const hangleToggle = () => {
setIsOpen(!isOpen);
};
return (
<Wrapper>
<DropdownButton onClick={hangleToggle} isActive={isOpen}>
<FilterIcon />
<FormattedMessage id="app.utils.filters" />
</DropdownButton>
<DropdownSection isOpen={isOpen}>
<FiltersCard onChange={handleChange} filters={filters} />
</DropdownSection>
</Wrapper>
);
};
FiltersPicker.defaultProps = {
filters: {},
onChange: () => {},
};
FiltersPicker.propTypes = {
filters: PropTypes.object,
onChange: PropTypes.func,
};
export default FiltersPicker;

View File

@ -2,7 +2,7 @@ import styled from 'styled-components';
const Wrapper = styled.div`
position: relative;
margin-top: 25px;
margin-top: 19px;
padding: 0;
.btn-wrapper {

View File

@ -3,7 +3,7 @@ import styled from 'styled-components';
const Wrapper = styled.div`
display: flex;
justify-content: center;
height: 32px;
height: 30px;
width: 35px;
background: #ffffff;
border: 1px solid #e3e9f3;

View File

@ -0,0 +1,9 @@
import styled from 'styled-components';
const Wrapper = styled.div`
.col-6:last-of-type {
padding-left: 0;
}
`;
export default Wrapper;

View File

@ -0,0 +1,79 @@
/**
*
* SizeInput
*/
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { InputNumber, Select } from '@buffetjs/core';
import Wrapper from './Wrapper';
function SizeInput({ onChange, value, ...rest }) {
const options = ['KB', 'MB', 'GB'];
const [size, setSize] = useState(0);
const [format, setFormat] = useState('KB');
const handleChangeValue = ({ target: { value } }) => {
setSize(value);
handleChange();
};
const handleChangeFormat = ({ target: { value } }) => {
setFormat(value);
handleChange();
};
const handleChange = () => {
onChange({
target: {
name: 'value',
value: {
size,
format,
},
},
});
};
return (
<Wrapper>
<div className="row">
<div className="col-6">
<InputNumber
{...rest}
name="size_value"
onChange={handleChangeValue}
value={value.size}
/>
</div>
<div className="col-6">
<Select
name="format_value"
onChange={handleChangeFormat}
options={options}
value={value.format}
/>
</div>
</div>
</Wrapper>
);
}
SizeInput.defaultProps = {
onChange: () => {},
value: {},
};
SizeInput.propTypes = {
onChange: PropTypes.func,
value: PropTypes.shape({
size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
format: PropTypes.string,
}),
};
export default SizeInput;

View File

@ -1,30 +1,18 @@
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { themePropTypes } from 'strapi-helper-plugin';
const Wrapper = styled.ul`
display: none;
position: absolute;
top: 38px;
left: 0;
margin-bottom: 0;
padding: 0;
min-width: 230px;
z-index: 1;
list-style-type: none;
font-size: ${({ theme }) => theme.main.fontSizes.md};
background-color: ${({ theme }) => theme.main.colors.white};
border: 1px solid ${({ theme }) => theme.main.colors.darkGrey};
box-shadow: 0 2px 4px ${({ theme }) => theme.main.colors.greyAlpha};
${({ isShown }) => isShown && 'display: block;'}
`;
Wrapper.defaultProps = {
isShown: false,
};
Wrapper.propTypes = {
isShown: PropTypes.bool,
...themePropTypes,
};

View File

@ -4,9 +4,9 @@ import PropTypes from 'prop-types';
import Wrapper from './Wrapper';
import SortListItem from '../SortListItem';
const SortList = ({ isShown, list, onClick, selectedItem }) => {
const SortList = ({ list, onClick, selectedItem }) => {
return (
<Wrapper isShown={isShown}>
<Wrapper>
{Object.keys(list).map(item => {
return (
<SortListItem
@ -24,14 +24,12 @@ const SortList = ({ isShown, list, onClick, selectedItem }) => {
SortList.defaultProps = {
list: {},
isShown: false,
onClick: () => {},
selectedItem: null,
};
SortList.propTypes = {
list: PropTypes.object,
isShown: PropTypes.bool,
onClick: PropTypes.func,
selectedItem: PropTypes.string,
};

View File

@ -2,11 +2,13 @@ import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { Carret } from '@buffetjs/icons';
import getTrad from '../../utils/getTrad';
import Wrapper from './Wrapper';
import SortButton from './SortButton';
import DropdownButton from '../DropdownButton';
import DropdownSection from '../DropdownSection';
import SortList from '../SortList';
import Wrapper from './Wrapper';
const SortPicker = ({ onChange, value }) => {
const [isOpen, setIsOpen] = useState(false);
@ -32,15 +34,18 @@ const SortPicker = ({ onChange, value }) => {
return (
<Wrapper>
<SortButton onClick={hangleToggle} isActive={isOpen}>
<DropdownButton onClick={hangleToggle} isActive={isOpen}>
<FormattedMessage id={getTrad('sort.label')} />
</SortButton>
<SortList
isShown={isOpen}
list={orders}
selectedItem={value}
onClick={handleChange}
/>
<Carret fill={isOpen ? '#007EFF' : '#292b2c'} />
</DropdownButton>
<DropdownSection isOpen={isOpen}>
<SortList
isShown={isOpen}
list={orders}
selectedItem={value}
onClick={handleChange}
/>
</DropdownSection>
</Wrapper>
);
};

View File

@ -1,9 +1,12 @@
import React, { useReducer, useState, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { includes } from 'lodash';
import { useHistory, useLocation } from 'react-router-dom';
import { Header } from '@buffetjs/custom';
import {
HeaderSearch,
PageFooter,
useGlobalContext,
generateFiltersFromSearch,
useQuery,
generateSearchFromFilters,
} from 'strapi-helper-plugin';
@ -12,22 +15,30 @@ import Container from '../../components/Container';
import ControlsWrapper from '../../components/ControlsWrapper';
import SelectAll from '../../components/SelectAll';
import SortPicker from '../../components/SortPicker';
import FiltersPicker from '../../components/FiltersPicker';
import FiltersList from '../../components/FiltersList';
// import List from '../../components/List';
import ListEmpty from '../../components/ListEmpty';
import ModalStepper from '../ModalStepper';
import getHeaderLabel from './utils/getHeaderLabel';
import {
filtersForm,
generatePageFromStart,
generateStartFromPage,
getHeaderLabel,
} from './utils';
import init from './init';
import reducer, { initialState } from './reducer';
import AddFilterCTA from '../../components/AddFilterCTA';
const HomePage = () => {
const { formatMessage } = useGlobalContext();
const [reducerState, dispatch] = useReducer(reducer, initialState, init);
const [isOpen, setIsOpen] = useState(false);
const { push } = useHistory();
const { search } = useLocation();
const query = useQuery();
const { data, dataToDelete } = reducerState.toJS();
const pluginName = formatMessage({ id: getTrad('plugin.name') });
const paramsKeys = ['_limit', '_page', '_q', '_sort'];
useEffect(() => {
// TODO - Retrieve data
@ -40,7 +51,9 @@ const HomePage = () => {
const getSearchParams = () => {
const params = {};
query.forEach((value, key) => {
params[key] = value;
if (includes(paramsKeys, key)) {
params[key] = value;
}
});
return params;
@ -53,6 +66,38 @@ const HomePage = () => {
};
};
const handleChangeFilters = ({ target: { value } }) => {
if (value) {
// Add filter
const updatedFilters = generateFiltersFromSearch(search);
updatedFilters.push(value);
handleChangeParams({
target: { name: 'filters', value: updatedFilters },
});
}
};
const handleDeleteFilter = index => {
// Remove filter
const updatedFilters = generateFiltersFromSearch(search);
updatedFilters.splice(index, 1);
handleChangeParams({
target: { name: 'filters', value: updatedFilters },
});
};
const handleChangeListParams = ({ target: { name, value } }) => {
if (name.includes('_page')) {
handleChangeParams({
target: { name: '_start', value: generateStartFromPage(value, limit) },
});
} else {
handleChangeParams({ target: { name: '_limit', value } });
}
};
const getQueryValue = key => {
const queryParams = getSearchParams();
@ -104,6 +149,14 @@ const HomePage = () => {
],
};
const limit = parseInt(getQueryValue('_limit'), 10) || 10;
const start = parseInt(getQueryValue('_start'), 10) || 0;
const params = {
_limit: parseInt(getQueryValue('_limit'), 10) || 10,
_page: generatePageFromStart(start, limit),
};
return (
<Container>
<Header {...headerProps} />
@ -122,10 +175,21 @@ const HomePage = () => {
onChange={handleChangeParams}
value={getQueryValue('_sort') || null}
/>
<AddFilterCTA />
<FiltersPicker onChange={handleChangeFilters} filters={filtersForm} />
<FiltersList
filters={generateFiltersFromSearch(search)}
onClick={handleDeleteFilter}
/>
</ControlsWrapper>
<ListEmpty onClick={handleClickToggleModal} />
{/* <List data={data} /> */}
<PageFooter
count={50}
context={{ emitEvent: () => {} }}
onChangeParams={handleChangeListParams}
params={params}
/>
<ModalStepper isOpen={isOpen} onToggle={handleClickToggleModal} />
</Container>
);

View File

@ -0,0 +1,25 @@
import moment from 'moment';
const filtersForm = {
created_at: {
type: 'datetime',
defaultValue: moment(),
},
updated_at: {
type: 'datetime',
defaultValue: moment(),
},
size: {
type: 'size',
defaultValue: {
size: 0,
format: 'KB',
},
},
file_type: {
type: 'enum',
defaultValue: 'image',
},
};
export default filtersForm;

View File

@ -0,0 +1,5 @@
const generatePageFromStart = (start, limit) => {
return Math.floor(start / limit) + 1;
};
export default generatePageFromStart;

View File

@ -0,0 +1,5 @@
const generateStartFromPage = (page, limit) => {
return page * limit - limit;
};
export default generateStartFromPage;

View File

@ -0,0 +1,4 @@
export { default as filtersForm } from './filtersForm';
export { default as generateStartFromPage } from './generateStartFromPage';
export { default as generatePageFromStart } from './generatePageFromStart';
export { default as getHeaderLabel } from './getHeaderLabel';

View File

@ -0,0 +1,61 @@
import generatePageFromStart from '../generatePageFromStart';
describe('MEDIA LIBRARY | containers | HomePage | utils', () => {
describe('generatePageFromStart', () => {
it('should return 1 if start is 0 and limit is 10', () => {
const start = 0;
const limit = 10;
const expected = 1;
expect(generatePageFromStart(start, limit)).toEqual(expected);
});
it('should return 2 if start is 10 and limit is 10', () => {
const start = 10;
const limit = 10;
const expected = 2;
expect(generatePageFromStart(start, limit)).toEqual(expected);
});
it('should return 3 if start is 20 and limit is 10', () => {
const start = 20;
const limit = 10;
const expected = 3;
expect(generatePageFromStart(start, limit)).toEqual(expected);
});
it('should return 1 if start is 10 and limit is 20', () => {
const start = 10;
const limit = 20;
const expected = 1;
expect(generatePageFromStart(start, limit)).toEqual(expected);
});
it('should return if start is 20 and limit is 20', () => {
const start = 20;
const limit = 20;
const expected = 2;
expect(generatePageFromStart(start, limit)).toEqual(expected);
});
it('should return if start is 50 and limit is 20', () => {
const start = 50;
const limit = 20;
const expected = 3;
expect(generatePageFromStart(start, limit)).toEqual(expected);
});
it('should return if start is 70 and limit is 20', () => {
const start = 70;
const limit = 20;
const expected = 4;
expect(generatePageFromStart(start, limit)).toEqual(expected);
});
});
});

View File

@ -0,0 +1,45 @@
import generateStartFromPage from '../generateStartFromPage';
describe('MEDIA LIBRARY | containers | HomePage | utils', () => {
describe('generateStartFromPage', () => {
it('should return 0 if page is 1 and limit is 10', () => {
const page = 1;
const limit = 10;
const expected = 0;
expect(generateStartFromPage(page, limit)).toEqual(expected);
});
it('should return 10 if page is 2 and limit is 10', () => {
const page = 2;
const limit = 10;
const expected = 10;
expect(generateStartFromPage(page, limit)).toEqual(expected);
});
it('should return 20 if page is 3 and limit is 10', () => {
const page = 3;
const limit = 10;
const expected = 20;
expect(generateStartFromPage(page, limit)).toEqual(expected);
});
it('should return 20 if page is 2 and limit is 20', () => {
const page = 2;
const limit = 20;
const expected = 20;
expect(generateStartFromPage(page, limit)).toEqual(expected);
});
it('should return 40 if page is 3 and limit is 20', () => {
const page = 3;
const limit = 20;
const expected = 40;
expect(generateStartFromPage(page, limit)).toEqual(expected);
});
});
});

View File

@ -7,6 +7,7 @@
"header.content.assets-empty": "No asset",
"header.content.assets-multiple": "{number} assets",
"header.content.assets-single": "1 asset",
"filter.add": "Add filter",
"input.label-bold": "Drag & drop",
"input.label-normal": "to upload or",
"input.button.label": "Browse files",

View File

@ -11,13 +11,18 @@ const _ = require('lodash');
module.exports = async () => {
// set plugin store
const pluginStore = strapi.store({
environment: strapi.config.environment,
const configurator = strapi.store({
type: 'plugin',
name: 'upload',
key: 'settings',
});
strapi.plugins.upload.config.providers = [];
Object.assign(strapi.plugins.upload.config, {
enabled: true,
provider: 'local',
sizeLimit: 1000000,
providers: [],
});
const installedProviders = Object.keys(strapi.config.info.dependencies)
.filter(d => d.includes('strapi-provider-upload-'))
@ -28,19 +33,15 @@ module.exports = async () => {
}
// if provider config does not exist set one by default
const config = await pluginStore.get({ key: 'provider' });
const config = await configurator.get();
if (!config) {
const provider = _.find(strapi.plugins.upload.config.providers, {
provider: 'local',
await configurator.set({
value: {
sizeOptimization: true,
responsiveDimensions: true,
videoPreview: true,
},
});
const value = _.assign({}, provider, {
enabled: true,
// by default limit size to 1 GB
sizeLimit: 1000000,
});
await pluginStore.set({ key: 'provider', value });
}
};

View File

@ -15,15 +15,7 @@
},
{
"method": "GET",
"path": "/environments",
"handler": "Upload.getEnvironments",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/settings/:environment",
"path": "/settings",
"handler": "Upload.getSettings",
"config": {
"policies": []
@ -31,7 +23,7 @@
},
{
"method": "PUT",
"path": "/settings/:environment",
"path": "/settings",
"handler": "Upload.updateSettings",
"config": {
"policies": []

View File

@ -40,13 +40,7 @@ module.exports = {
resolver: async (obj, { file: upload, ...fields }) => {
const file = await formatFile(upload, fields);
const config = await strapi
.store({
environment: strapi.config.environment,
type: 'plugin',
name: 'upload',
})
.get({ key: 'provider' });
const config = strapi.plugins.upload.config;
const uploadedFiles = await strapi.plugins.upload.services.upload.upload(
[file],
@ -66,13 +60,7 @@ module.exports = {
uploads.map(upload => formatFile(upload, fields))
);
const config = await strapi
.store({
environment: strapi.config.environment,
type: 'plugin',
name: 'upload',
})
.get({ key: 'provider' });
const config = strapi.plugins.upload.config;
const uploadedFiles = await strapi.plugins.upload.services.upload.upload(
files,

View File

@ -3,17 +3,17 @@
/**
* Upload.js controller
*
* @description: A set of functions called "actions" of the `upload` plugin.
*/
const _ = require('lodash');
const validateSettings = require('./validation/settings');
module.exports = {
async upload(ctx) {
const uploadService = strapi.plugins.upload.services.upload;
// Retrieve provider configuration.
const config = await uploadService.getConfig();
const config = strapi.plugins.upload.config;
// Verify if the file upload is enable.
if (config.enabled === false) {
@ -98,48 +98,32 @@ module.exports = {
ctx.send(uploadedFiles);
},
async getEnvironments(ctx) {
const environments = Object.keys(strapi.config.environments).map(
environment => ({
name: environment,
active: strapi.config.environment === environment,
})
);
ctx.send({ environments });
},
async getSettings(ctx) {
const config = await strapi
.store({
environment: ctx.params.environment,
type: 'plugin',
name: 'upload',
key: 'settings',
})
.get({ key: 'provider' });
.get();
ctx.send({
providers: strapi.plugins.upload.config.providers,
config,
data: config,
});
},
async updateSettings(ctx) {
const {
request: { body: newSettings },
} = ctx;
await strapi
.store({
environment: ctx.params.environment,
type: 'plugin',
name: 'upload',
})
.set({
key: 'provider',
value: { ...newSettings, sizeLimit: parseFloat(newSettings.sizeLimit) },
});
const configurator = strapi.store({
type: 'plugin',
name: 'upload',
key: 'settings',
});
ctx.send({ ok: true });
const data = await validateSettings(ctx.request.body);
await configurator.set({ key: 'settings', value: data });
ctx.body = { data };
},
async find(ctx) {
@ -173,13 +157,7 @@ module.exports = {
async destroy(ctx) {
const { id } = ctx.params;
const config = await strapi
.store({
environment: strapi.config.environment,
type: 'plugin',
name: 'upload',
})
.get({ key: 'provider' });
const config = strapi.plugins.upload.config;
const file = await strapi.plugins['upload'].services.upload.fetch({ id });

View File

@ -0,0 +1,23 @@
'use strict';
const { yup, formatYupErrors } = require('strapi-utils');
const settingsSchema = yup.object({
sizeOptimization: yup.boolean().required(),
responsiveDimensions: yup.boolean().required(),
videoPreview: yup.boolean().required(),
});
const validateSettings = data => {
return settingsSchema
.validate(data, {
abortEarly: false,
})
.catch(error => {
throw strapi.errors.badRequest('ValidationError', {
errors: formatYupErrors(error),
});
});
};
module.exports = validateSettings;

View File

@ -139,13 +139,7 @@ module.exports = {
async uploadToEntity(params, files, source) {
// Retrieve provider settings from database.
const config = await strapi
.store({
environment: strapi.config.environment,
type: 'plugin',
name: 'upload',
})
.get({ key: 'provider' });
const config = strapi.plugins.upload.config;
const model = strapi.getModel(params.model, source);

View File

@ -0,0 +1,36 @@
const bootstrap = require('../../config/functions/bootstrap');
describe('Upload plugin bootstrap function', () => {
test('Sets default config if id does not exist', async () => {
const setStore = jest.fn(() => {});
global.strapi = {
config: {
info: {
dependencies: {},
},
},
plugins: {
upload: { config: {} },
},
store() {
return {
get() {
return null;
},
set: setStore,
};
},
};
await bootstrap();
expect(setStore).toHaveBeenCalledWith({
value: {
sizeOptimization: true,
videoPreview: true,
responsiveDimensions: true,
},
});
});
});

View File

@ -8,85 +8,22 @@ const { createAuthRequest } = require('../../../test/helpers/request');
let rq;
const defaultProviderConfig = {
provider: 'local',
name: 'Local server',
enabled: true,
sizeLimit: 1000000,
};
const resetProviderConfigToDefault = () => {
return setConfigOptions(defaultProviderConfig);
};
const setConfigOptions = assign => {
return rq.put('/upload/settings/development', {
body: {
...defaultProviderConfig,
...assign,
},
});
};
describe('Upload plugin end to end tests', () => {
beforeAll(async () => {
const token = await registerAndLogin();
rq = createAuthRequest(token);
}, 60000);
afterEach(async () => {
await resetProviderConfigToDefault();
});
describe('GET /upload/environments => List available environments', () => {
test('Returns the list of envrionments and which one is currently active', async () => {
const res = await rq.get('/upload/environments');
describe('GET /upload/settings => Get settings for an environment', () => {
test('Returns the settings', async () => {
const res = await rq.get('/upload/settings');
expect(res.statusCode).toBe(200);
expect(res.body).toEqual({
environments: expect.arrayContaining([
{
name: 'development',
active: true,
},
{
name: 'staging',
active: false,
},
{
name: 'production',
active: false,
},
]),
});
});
});
describe('GET /upload/settings/:environment => Get settings for an environment', () => {
test('Lists the available providers', async () => {
const res = await rq.get('/upload/settings/development');
expect(res.statusCode).toBe(200);
expect(res.body).toMatchObject({
providers: [
{
provider: 'local',
name: 'Local server',
},
],
});
});
test('Return the default provider config', async () => {
const res = await rq.get('/upload/settings/development');
expect(res.statusCode).toBe(200);
expect(res.body).toMatchObject({
config: {
provider: 'local',
name: 'Local server',
enabled: true,
sizeLimit: 1000000,
data: {
sizeOptimization: true,
videoPreview: true,
responsiveDimensions: true,
},
});
});
@ -94,24 +31,32 @@ describe('Upload plugin end to end tests', () => {
describe('PUT /upload/settings/:environment', () => {
test('Updates an envrionment config correctly', async () => {
const updateRes = await rq.put('/upload/settings/development', {
const updateRes = await rq.put('/upload/settings', {
body: {
provider: 'test',
enabled: false,
sizeLimit: 1000,
sizeOptimization: true,
videoPreview: false,
responsiveDimensions: true,
},
});
expect(updateRes.statusCode).toBe(200);
expect(updateRes.body).toEqual({ ok: true });
expect(updateRes.body).toEqual({
data: {
sizeOptimization: true,
videoPreview: false,
responsiveDimensions: true,
},
});
const getRes = await rq.get('/upload/settings/development');
const getRes = await rq.get('/upload/settings');
expect(getRes.statusCode).toBe(200);
expect(getRes.body.config).toEqual({
provider: 'test',
enabled: false,
sizeLimit: 1000,
expect(getRes.body).toEqual({
data: {
sizeOptimization: true,
videoPreview: false,
responsiveDimensions: true,
},
});
});
});
@ -142,21 +87,6 @@ describe('Upload plugin end to end tests', () => {
);
});
test('Rejects when provider is not enabled', async () => {
await setConfigOptions({ enabled: false });
const res = await rq.post('/upload', {
formData: {
files: fs.createReadStream(__dirname + '/rec.jpg'),
},
});
expect(res.statusCode).toBe(400);
expect(res.body).toMatchObject({
message: [{ messages: [{ message: 'File upload is disabled' }] }],
});
});
test('Rejects when no files are provided', async () => {
const res = await rq.post('/upload', {
formData: {},
@ -167,27 +97,6 @@ describe('Upload plugin end to end tests', () => {
message: [{ messages: [{ message: 'Files are empty' }] }],
});
});
test('Rejects when any file if over the configured size limit', async () => {
await setConfigOptions({
sizeLimit: 0,
});
const res = await rq.post('/upload', {
formData: {
files: fs.createReadStream(__dirname + '/rec.jpg'),
},
});
expect(res.statusCode).toBe(400);
expect(res.body).toMatchObject({
message: [
{
messages: [{ message: 'rec.jpg file is bigger than limit size!' }],
},
],
});
});
});
describe('GET /upload/files => Find files', () => {});

View File

@ -471,7 +471,7 @@ class Strapi extends EventEmitter {
this.log.warn('Make sure you call it?');
}, timeoutMs);
async function execBootstrap(fn) {
const execBootstrap = async fn => {
if (!fn) return;
const timer = warnOnTimeout();
@ -480,7 +480,7 @@ class Strapi extends EventEmitter {
} finally {
clearTimeout(timer);
}
}
};
const pluginBoostraps = Object.keys(this.plugins).map(plugin => {
return execBootstrap(

View File

@ -51,7 +51,7 @@ const loadPlugins = async ({ installedPlugins }) => {
const files = await loadFiles(
pluginPath,
'{!(config|node_modules|test)//*.*(js|json),package.json}'
'{!(config|node_modules|test)/*.*(js|json),package.json}'
);
const conf = await loadConfig(pluginPath);

Some files were not shown because too many files have changed in this diff Show More