Merge branch 'master' into repo/issueTemplateLinks

This commit is contained in:
derrickmehaffy 2022-03-21 10:51:14 -07:00
commit a5cf340e15
88 changed files with 379 additions and 697 deletions

View File

@ -1,6 +1,6 @@
{
"name": "check-pr-status",
"version": "4.1.3",
"version": "4.1.5",
"main": "dist/index.js",
"license": "MIT",
"private": true,

View File

@ -1,7 +1,7 @@
{
"name": "getstarted",
"private": true,
"version": "4.1.3",
"version": "4.1.5",
"description": "A Strapi application.",
"scripts": {
"develop": "strapi develop",
@ -12,17 +12,17 @@
"strapi": "strapi"
},
"dependencies": {
"@strapi/admin": "4.1.3",
"@strapi/plugin-documentation": "4.1.3",
"@strapi/plugin-graphql": "4.1.3",
"@strapi/plugin-i18n": "4.1.3",
"@strapi/plugin-sentry": "4.1.3",
"@strapi/plugin-users-permissions": "4.1.3",
"@strapi/provider-email-mailgun": "4.1.3",
"@strapi/provider-upload-aws-s3": "4.1.3",
"@strapi/provider-upload-cloudinary": "4.1.3",
"@strapi/strapi": "4.1.3",
"@strapi/utils": "4.1.3",
"@strapi/admin": "4.1.5",
"@strapi/plugin-documentation": "4.1.5",
"@strapi/plugin-graphql": "4.1.5",
"@strapi/plugin-i18n": "4.1.5",
"@strapi/plugin-sentry": "4.1.5",
"@strapi/plugin-users-permissions": "4.1.5",
"@strapi/provider-email-mailgun": "4.1.5",
"@strapi/provider-upload-aws-s3": "4.1.5",
"@strapi/provider-upload-cloudinary": "4.1.5",
"@strapi/strapi": "4.1.5",
"@strapi/utils": "4.1.5",
"lodash": "4.17.21",
"mysql": "2.18.1",
"passport-google-oauth2": "0.2.0",

View File

@ -1,7 +1,7 @@
{
"name": "kitchensink",
"private": true,
"version": "4.1.3",
"version": "4.1.5",
"description": "A Strapi application.",
"scripts": {
"develop": "strapi develop",
@ -12,12 +12,12 @@
"strapi": "strapi"
},
"dependencies": {
"@strapi/admin": "4.1.3",
"@strapi/provider-email-mailgun": "4.1.3",
"@strapi/provider-upload-aws-s3": "4.1.3",
"@strapi/provider-upload-cloudinary": "4.1.3",
"@strapi/strapi": "4.1.3",
"@strapi/utils": "4.1.3",
"@strapi/admin": "4.1.5",
"@strapi/provider-email-mailgun": "4.1.5",
"@strapi/provider-upload-aws-s3": "4.1.5",
"@strapi/provider-upload-cloudinary": "4.1.5",
"@strapi/strapi": "4.1.5",
"@strapi/utils": "4.1.5",
"lodash": "4.17.21",
"mysql": "2.18.1",
"passport-google-oauth2": "0.2.0",

View File

@ -1,5 +1,5 @@
{
"version": "4.1.3",
"version": "4.1.5",
"packages": [
"packages/*",
"examples/*"

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/admin-test-utils",
"version": "4.1.3",
"version": "4.1.5",
"private": true,
"description": "Test utilities for the Strapi administration panel",
"license": "MIT",

View File

@ -1,6 +1,6 @@
{
"name": "create-strapi-app",
"version": "4.1.3",
"version": "4.1.5",
"description": "Generate a new Strapi application.",
"keywords": [
"create-strapi-app",
@ -38,7 +38,7 @@
"test": "echo \"no tests yet\""
},
"dependencies": {
"@strapi/generate-new": "4.1.3",
"@strapi/generate-new": "4.1.5",
"commander": "6.1.0",
"inquirer": "8.2.0"
},

View File

@ -1,6 +1,6 @@
{
"name": "create-strapi-starter",
"version": "4.1.3",
"version": "4.1.5",
"description": "Generate a new Strapi application.",
"keywords": [
"create-strapi-starter",
@ -38,7 +38,7 @@
"test": "echo \"no tests yet\""
},
"dependencies": {
"@strapi/generate-new": "4.1.3",
"@strapi/generate-new": "4.1.5",
"chalk": "4.1.1",
"ci-info": "3.1.1",
"commander": "7.1.0",

View File

@ -57,10 +57,13 @@ const ComponentInitializer = ({ error, isReadOnly, onClick }) => {
</Box>
{error?.id && (
<Typography textColor="danger600" variant="pi">
{formatMessage({
{formatMessage(
{
id: error.id,
defaultMessage: error.id,
})}
},
{ ...error.values }
)}
</Typography>
)}
</>
@ -75,6 +78,8 @@ ComponentInitializer.defaultProps = {
ComponentInitializer.propTypes = {
error: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}),
isReadOnly: PropTypes.bool,
onClick: PropTypes.func.isRequired,

View File

@ -92,7 +92,7 @@ const AccordionGroupCustom = ({ children, footer, label, labelAction, error }) =
{error && (
<Box paddingTop={1}>
<Typography variant="pi" textColor="danger600">
{formatMessage({ id: error.id, defaultMessage: error.id })}
{formatMessage({ id: error.id, defaultMessage: error.id }, { ...error.values })}
</Typography>
</Box>
)}
@ -111,6 +111,8 @@ AccordionGroupCustom.propTypes = {
children: PropTypes.node.isRequired,
error: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}),
footer: PropTypes.node,
label: PropTypes.string,

View File

@ -242,9 +242,14 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => {
};
const redirectToPreviousLocation = () => {
const locationBeforeAuthenticated = decodeURIComponent(query.get('redirectTo'));
const redirectUrl = locationBeforeAuthenticated || '/';
if (authType === 'login') {
const redirectTo = query.get('redirectTo');
const redirectUrl = redirectTo ? decodeURIComponent(redirectTo) : '/';
push(redirectUrl);
} else {
push('/');
}
};
// Redirect the user to the login page if

View File

@ -30,9 +30,6 @@ const StyledReddit = styled(Reddit)`
> path:first-child {
fill: #ff4500;
}
> path:last-child {
fill: ${({ theme }) => theme.colors.neutral0};
}
`;
const StyledStrapi = styled(Strapi)`
> path:first-child {

View File

@ -633,10 +633,6 @@ describe('Homepage', () => {
fill: #ff4500;
}
.c52 > path:last-child {
fill: #ffffff;
}
.c55 > path:first-child {
fill: #8e75ff;
}

View File

@ -1,15 +1,24 @@
{
"Analytics": "Phân Tích",
"Auth.components.Oops.text": "Tài khoản của bạn đã bị khoá",
"Auth.components.Oops.text.admin": "Nếu có sự nhầm lẫn, hãy liên hệ người quản trị",
"Auth.form.button.forgot-password": "Gửi Email",
"Auth.form.button.go-home": "QUAY VỀ TRANG CHỦ",
"Auth.form.button.login": "Đăng nhập",
"Auth.form.button.login.providers.error": "Không thể kết nối bạn với dịch vụ đã chọn.",
"Auth.form.button.login.providers.see-more": "Xem thêm",
"Auth.form.button.login.strapi": "Đăng nhập với Strapi",
"Auth.form.button.password-recovery": "Khôi phục mật khẩu",
"Auth.form.button.register": "Sẵn sàng để bắt đầu",
"Auth.form.button.reset-password": "Đổi mật khẩu",
"Auth.form.confirmPassword.label": "Nhập lại mật khẩu",
"Auth.form.currentPassword.label": "Mật khẩu hiện tại",
"Auth.form.email.label": "Email",
"Auth.form.email.placeholder": "kai@doe.com",
"Auth.form.error.blocked": "Tài khoản của bạn bị khóa bởi người quản trị",
"Auth.form.error.blocked": "Tài khoản của bạn bị khóa bởi người quản trị.",
"Auth.form.error.code.provide": "Mã sai đã được cung cấp.",
"Auth.form.error.confirmed": "Email của tài khoản của bạn chưa được xác nhận.",
"Auth.form.error.email.invalid": "Eemail sai.",
"Auth.form.error.email.invalid": "Email sai.",
"Auth.form.error.email.provide": "Vui lòng cung cấp tên đăng nhập hoặc email.",
"Auth.form.error.email.taken": "Email đã được dùng.",
"Auth.form.error.invalid": "Định danh hoặc mật khẩu sai.",
@ -21,18 +30,35 @@
"Auth.form.error.ratelimit": "Thử quá nhiều lần, vui lòng thử lại trong một phút",
"Auth.form.error.user.not-exist": "Email này chưa tồn tại.",
"Auth.form.error.username.taken": "Tên đăng nhập đã bị lấy.",
"Auth.form.firstname.label": "Họ",
"Auth.form.firstname.placeholder": "v.d. Kai",
"Auth.form.forgot-password.email.label": "Nhập email của bạn",
"Auth.form.forgot-password.email.label.success": "Email đã gửi thành công đến",
"Auth.form.lastname.label": "Tên",
"Auth.form.lastname.placeholder": "v.d. Doe",
"Auth.form.password.hide-password": "Ẩn mật khẩu",
"Auth.form.password.hint": "Mật khẩu phải chứa ít nhất 8 ký tự, 1 viết hoa, 1 viết thường, và 1 số",
"Auth.form.password.label": "Mật khẩu",
"Auth.form.password.show-password": "Hiển thị password",
"Auth.form.register.news.label": "Cập nhật cho tôi về chức năng mới và những cải thiện sắp tới (thông qua việc này bạn đã chấp nhận {terms} và {policy}).",
"Auth.form.register.subtitle": "Thông tin của bạn chỉ được sử dụng để đăng nhập vào trang quản trị. Tất cả các dữ liệu được lưu ở cơ sở dữ liệu của bạn.",
"Auth.form.rememberMe.label": "Nhớ tôi",
"Auth.form.username.label": "Tên đăng nhập",
"Auth.form.username.placeholder": "Kai Doe",
"Auth.link.forgot-password": "Quên mật khẩu của bạn?",
"Auth.form.welcome.subtitle": "Đăng nhập vào tài khoản Strapi của bạn",
"Auth.form.welcome.title": "Chào mừng!",
"Auth.link.forgot-password": "Quên mật khẩu?",
"Auth.link.ready": "Sẵn sàng đăng nhập?",
"Auth.link.signin": "Đăng nhập",
"Auth.link.signin.account": "Đã có tài khoản?",
"Auth.login.sso.divider": "Hoặc đăng nhập với",
"Auth.login.sso.loading": "Đang tải các dịch vụ cung cấp...",
"Auth.login.sso.subtitle": "Đăng nhập qua SSO",
"Auth.privacy-policy-agreement.policy": "chính sách bảo mật",
"Auth.privacy-policy-agreement.terms": "các điều khoản",
"Auth.reset-password.title": "Đặt lại mật khẩu",
"Content Manager": "Quản Lý Nội Dung",
"Documentation": "Tài liệu",
"Email": "Email",
"Files Upload": "Tải Tâp Tin Lên",
"HomePage.helmet.title": "Trang chủ",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/admin",
"version": "4.1.3",
"version": "4.1.5",
"description": "Strapi Admin",
"repository": {
"type": "git",
@ -52,11 +52,11 @@
"@fortawesome/free-brands-svg-icons": "^5.15.3",
"@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/react-fontawesome": "^0.1.14",
"@strapi/babel-plugin-switch-ee-ce": "4.1.3",
"@strapi/babel-plugin-switch-ee-ce": "4.1.5",
"@strapi/design-system": "0.0.1-alpha.79",
"@strapi/helper-plugin": "4.1.3",
"@strapi/helper-plugin": "4.1.5",
"@strapi/icons": "0.0.1-alpha.79",
"@strapi/utils": "4.1.3",
"@strapi/utils": "4.1.5",
"axios": "0.24.0",
"babel-loader": "8.2.3",
"babel-plugin-styled-components": "2.0.2",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/plugin-content-manager",
"version": "4.1.3",
"version": "4.1.5",
"description": "A powerful UI to easily manage your data.",
"repository": {
"type": "git",
@ -24,7 +24,7 @@
},
"dependencies": {
"@sindresorhus/slugify": "1.1.0",
"@strapi/utils": "4.1.3",
"@strapi/utils": "4.1.5",
"lodash": "4.17.21"
},
"engines": {

View File

@ -107,7 +107,8 @@ const baseForm = {
metadatas: {
intlLabel: {
id: getTrad('form.attribute.item.date.type.date'),
defaultMessage: 'date',
defaultMessage: 'date (ex: 01/01/{currentYear})',
values: { currentYear: new Date().getFullYear() },
},
},
},
@ -117,7 +118,8 @@ const baseForm = {
metadatas: {
intlLabel: {
id: getTrad('form.attribute.item.date.type.datetime'),
defaultMessage: 'datetime',
defaultMessage: 'datetime (ex: 01/01/{currentYear} 00:00 AM)',
values: { currentYear: new Date().getFullYear() },
},
},
},
@ -127,7 +129,7 @@ const baseForm = {
metadatas: {
intlLabel: {
id: getTrad('form.attribute.item.date.type.time'),
defaultMessage: 'time',
defaultMessage: 'time (ex: 00:00 AM)',
},
},
},

View File

@ -56,12 +56,12 @@ function List({
<Tr>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({ id: 'table.headers.name', defaultMessage: 'Name' })}
{formatMessage({ id: getTrad('table.headers.name'), defaultMessage: 'Name' })}
</Typography>
</Th>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({ id: 'table.headers.type', defaultMessage: 'Type' })}
{formatMessage({ id: getTrad('table.headers.type'), defaultMessage: 'Type' })}
</Typography>
</Th>
</Tr>
@ -84,12 +84,12 @@ function List({
<Tr>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({ id: 'table.headers.name', defaultMessage: 'Name' })}
{formatMessage({ id: getTrad('table.headers.name'), defaultMessage: 'Name' })}
</Typography>
</Th>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({ id: 'table.headers.type', defaultMessage: 'Type' })}
{formatMessage({ id: getTrad('table.headers.type'), defaultMessage: 'Type' })}
</Typography>
</Th>
</Tr>
@ -134,12 +134,12 @@ function List({
<tr>
<th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({ id: 'table.headers.name', defaultMessage: 'Name' })}
{formatMessage({ id: getTrad('table.headers.name'), defaultMessage: 'Name' })}
</Typography>
</th>
<th colSpan="2">
<Typography variant="sigma" textColor="neutral600">
{formatMessage({ id: 'table.headers.type', defaultMessage: 'Type' })}
{formatMessage({ id: getTrad('table.headers.type'), defaultMessage: 'Type' })}
</Typography>
</th>
</tr>

View File

@ -142,7 +142,7 @@ function ListRow({
onClick={handleClick}
label={`${formatMessage({
id: 'app.utils.edit',
formatMessage: 'Edit',
defaultMessage: 'Edit',
})} ${name}`}
noBorder
icon={<Pencil />}

View File

@ -38,7 +38,10 @@ const SelectDateType = ({ intlLabel, error, modifiedData, name, onChange, option
{options.map(({ metadatas: { intlLabel, disabled, hidden }, key, value }) => {
return (
<Option key={key} value={value} disabled={disabled} hidden={hidden}>
{formatMessage(intlLabel)}
{formatMessage(
{ id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
intlLabel.values
)}
</Option>
);
})}

View File

@ -148,7 +148,7 @@ const ListView = () => {
!isCreatingFirstContentType && (
<Button startIcon={<Pencil />} variant="tertiary" onClick={onEdit}>
{formatMessage({
id: getTrad('app.utils.edit'),
id: 'app.utils.edit',
defaultMessage: 'Edit',
})}
</Button>

View File

@ -55,9 +55,6 @@
"form.attribute.component.option.single.description": "Vhodné pro seskupení políček, např. celá adresa",
"form.attribute.item.customColumnName": "Vlastné názvy stĺpcov",
"form.attribute.item.customColumnName.description": "Umožňuje přejmenovat databázový sloupec pro potřeby API",
"form.attribute.item.date.type.date": "datum",
"form.attribute.item.date.type.datetime": "datum a čas",
"form.attribute.item.date.type.time": "čas",
"form.attribute.item.defineRelation.fieldName": "Název pole",
"form.attribute.item.enumeration.graphql": "Název pole pro GraphQL",
"form.attribute.item.enumeration.graphql.description": "Umožňuje přepsat přednastavené názvy názvy pro GraphQL",

View File

@ -65,9 +65,6 @@
"form.attribute.component.option.single.description": "Nützlich um Felder wie volle Addresse, Hauptinformationen, etc. zu grupppieren",
"form.attribute.item.customColumnName": "Eigener Spaltenname",
"form.attribute.item.customColumnName.description": "Dies ist nützlich, um Spalten in der Datenbank für Antworten der API umzubenennen",
"form.attribute.item.date.type.date": "Datum",
"form.attribute.item.date.type.datetime": "Datum und Uhrzeit",
"form.attribute.item.date.type.time": "Uhrzeit",
"form.attribute.item.defineRelation.fieldName": "Feldname",
"form.attribute.item.enumeration.graphql": "Namensüberschreibung für GraphQL",
"form.attribute.item.enumeration.graphql.description": "Ermöglicht, den standardmäßig generierten Namen für GraphQL zu überschreiben",

View File

@ -75,9 +75,6 @@
"form.attribute.component.option.single.description": "Bedst til at gruppere felter som fulde adresse, primær information osv...",
"form.attribute.item.customColumnName": "Specielle kolonne navne",
"form.attribute.item.customColumnName.description": "Dette er brugbart til at omdøbe database kolonne navne i et mere omfattende format til API svar",
"form.attribute.item.date.type.date": "dato",
"form.attribute.item.date.type.datetime": "dato - tid",
"form.attribute.item.date.type.time": "tid",
"form.attribute.item.defineRelation.fieldName": "Felt navn",
"form.attribute.item.enumeration.graphql": "Navn overskrivning til GraphQL",
"form.attribute.item.enumeration.graphql.description": "Tillader dig at overskrive standard genereret navn til GraphQL",

View File

@ -76,9 +76,9 @@
"form.attribute.component.option.single.description": "Best for grouping fields like full address, main information, etc...",
"form.attribute.item.customColumnName": "Custom column names",
"form.attribute.item.customColumnName.description": "This is useful to rename database column names in a more comprehensive format for the API's responses",
"form.attribute.item.date.type.date": "date",
"form.attribute.item.date.type.datetime": "datetime",
"form.attribute.item.date.type.time": "time",
"form.attribute.item.date.type.date": "date (ex: 01/01/{currentYear})",
"form.attribute.item.date.type.datetime": "datetime (ex: 01/01/{currentYear} 00:00 AM)",
"form.attribute.item.date.type.time": "time (ex: 00:00 AM)",
"form.attribute.item.defineRelation.fieldName": "Field name",
"form.attribute.item.enumeration.graphql": "Name override for GraphQL",
"form.attribute.item.enumeration.graphql.description": "Allows you to override the default generated name for GraphQL",

View File

@ -75,9 +75,6 @@
"form.attribute.component.option.single.description": "Lo mejor para agrupar campos como dirección completa, información principal...",
"form.attribute.item.customColumnName": "Nombres de columna personalizados",
"form.attribute.item.customColumnName.description": "Esto es útil para renombrar los nombres de las columnas de la base de datos en un formato más completo para las respuestas de la API.",
"form.attribute.item.date.type.date": "fecha",
"form.attribute.item.date.type.datetime": "fecha y hora",
"form.attribute.item.date.type.time": "hora",
"form.attribute.item.defineRelation.fieldName": "Nombre del campo",
"form.attribute.item.enumeration.graphql": "Sobreescritura de nombre para GraphQL",
"form.attribute.item.enumeration.graphql.description": "Le permite redefinir el nombre generado por defecto para GraphQL",

View File

@ -65,9 +65,6 @@
"form.attribute.component.option.single.description": "Paling baik untuk mengelompokkan bidang seperti alamat lengkap, informasi utama, dll ...",
"form.attribute.item.customColumnName": "Nama kolom kustom",
"form.attribute.item.customColumnName.description": "Ini berguna untuk mengganti nama kolom database dalam format yang lebih komprehensif untuk respons API",
"form.attribute.item.date.type.date": "tanggal",
"form.attribute.item.date.type.datetime": "tanggalwaktu",
"form.attribute.item.date.type.time": "waktu",
"form.attribute.item.defineRelation.fieldName": "Nama bidang",
"form.attribute.item.enumeration.graphql": "Nama pengganti untuk GraphQL",
"form.attribute.item.enumeration.graphql.description": "Memungkinkan Anda untuk mengganti nama default yang dibuat untuk GraphQL ",

View File

@ -65,9 +65,6 @@
"form.attribute.component.option.single.description": "Utile per raggruppare campi correlati come quelli di un indirizzo",
"form.attribute.item.customColumnName": "Nome della colonna personalizzato",
"form.attribute.item.customColumnName.description": "Utile per rinominare le colonne del database e mantenere consistente il formato delle risposte API",
"form.attribute.item.date.type.date": "data",
"form.attribute.item.date.type.datetime": "data e ora",
"form.attribute.item.date.type.time": "orario",
"form.attribute.item.defineRelation.fieldName": "Nome del campo",
"form.attribute.item.enumeration.graphql": "Override del nome GraphQL",
"form.attribute.item.enumeration.graphql.description": "Consente di ignorare l'impostazione predefinita del nome generato per GraphQL",

View File

@ -75,9 +75,6 @@
"form.attribute.component.option.single.description": "전체 주소지, 기본 정보 등과 같은 필드를 그룹화하는 데 적합합니다.",
"form.attribute.item.customColumnName": "커스텀 컬럼 이름",
"form.attribute.item.customColumnName.description": "API 응답을 위해 데이터베이스 컬럼 이름을 포괄적인 형식으로 변경하는데 유용합니다.",
"form.attribute.item.date.type.date": "date",
"form.attribute.item.date.type.datetime": "datetime",
"form.attribute.item.date.type.time": "time",
"form.attribute.item.defineRelation.fieldName": "필드 이름",
"form.attribute.item.enumeration.graphql": "GraphQL에서 사용할 이름",
"form.attribute.item.enumeration.graphql.description": "기본 생성된 이름을 GraphQL에서 사용합니다.",

View File

@ -62,9 +62,6 @@
"form.attribute.component.option.single.description": "Sesuai untuk ruang kumpulan seperti alamat penuh, maklumat utama dan lain-lain ...",
"form.attribute.item.customColumnName": "Gubah nama lajur",
"form.attribute.item.customColumnName.description": "Ini berguna untuk menamakan semula nama lajur didalam pangkalan data dengan format yang lebih komprehensif untuk respons API",
"form.attribute.item.date.type.date": "tarikh",
"form.attribute.item.date.type.datetime": "masa dan tarikh",
"form.attribute.item.date.type.time": "masa",
"form.attribute.item.defineRelation.fieldName": "Nama ruang",
"form.attribute.item.enumeration.graphql": "Ganti nama untuk GraphQL",
"form.attribute.item.enumeration.graphql.description": "Membolehkan anda menggantikan nama yang dihasilkan secara lalai untuk GraphQL",

View File

@ -61,9 +61,6 @@
"form.attribute.component.option.single.description": "het beste voor het groeperen van velden zoals volledig adres, hoofdinformatie, enz",
"form.attribute.item.customColumnName": "Aangepaste kolom namen",
"form.attribute.item.customColumnName.description": "Dit is handig om database kolom namen te hernoemen in een meer uitgebreid formaat voor de API responses",
"form.attribute.item.date.type.date": "datum",
"form.attribute.item.date.type.datetime": "datum-tijd",
"form.attribute.item.date.type.time": "tijd",
"form.attribute.item.defineRelation.fieldName": "Veld naam",
"form.attribute.item.enumeration.graphql": "Naam overschreven voor GraphQL",
"form.attribute.item.enumeration.graphql.description": "Zorgt ervoor dat je de standaard gegenereerde naam voor GraphQL kan overschrijven",

View File

@ -56,9 +56,6 @@
"form.attribute.component.option.single.description": "Najlepsze do grupowania pól takich jak pełny adres, główne informacje itp.",
"form.attribute.item.customColumnName": "Własne nazwy tabel",
"form.attribute.item.customColumnName.description": "Jest to przydatne do zmiany nazwy tabel bazy danych w bardziej wszechstronnym formacie odpowiedzi API",
"form.attribute.item.date.type.date": "data",
"form.attribute.item.date.type.datetime": "data i czas",
"form.attribute.item.date.type.time": "czas",
"form.attribute.item.defineRelation.fieldName": "Atrybut",
"form.attribute.item.enumeration.graphql": "Nadpisanie nazwy dla GraphQL",
"form.attribute.item.enumeration.graphql.description": "Pozwalaj na nadpisanie domyślnie wygenerowanej nazwy dla GraphQL.",

View File

@ -66,9 +66,6 @@
"form.attribute.component.option.single.description": "Применимо для группировки полей, таких как полный адрес, основная информация и т.д.",
"form.attribute.item.customColumnName": "Названия столбцов",
"form.attribute.item.customColumnName.description": "Может быть полезно переименовать названия столбцов для более читаемых ответов API.",
"form.attribute.item.date.type.date": "дата",
"form.attribute.item.date.type.datetime": "дата/время",
"form.attribute.item.date.type.time": "время",
"form.attribute.item.defineRelation.fieldName": "Название поля",
"form.attribute.item.enumeration.graphql": "Название поля в GraphQL",
"form.attribute.item.enumeration.graphql.description": "Позволяет переопределить название поля в GraphQL, сгенерированное по умолчанию",

View File

@ -65,9 +65,6 @@
"form.attribute.component.option.single.description": "Vhodné pre zoskúpenie políčok, napr. celá adresa",
"form.attribute.item.customColumnName": "Vlastné názvy stĺpcov",
"form.attribute.item.customColumnName.description": "Umožňuje premenovať databázový stĺpček pre potreby API",
"form.attribute.item.date.type.date": "dátum",
"form.attribute.item.date.type.datetime": "dátum a čas",
"form.attribute.item.date.type.time": "čas",
"form.attribute.item.defineRelation.fieldName": "Názov políčka",
"form.attribute.item.enumeration.graphql": "Názov políčka pre GraphQL",
"form.attribute.item.enumeration.graphql.description": "Umožňuje prepísať predvolené názvy pre GraphQL",

View File

@ -63,9 +63,6 @@
"form.attribute.component.option.single.description": "ดีที่สุดสำหรับการจัดกลุ่มฟิลด์เช่นแอดเดรสแบบเต็มข้อมูลหลักและอื่นๆ",
"form.attribute.item.customColumnName": "ชื่อคอลัมน์แบบกำหนดเอง",
"form.attribute.item.customColumnName.description": "สิ่งนี้มีประโยชน์ในการเปลี่ยนชื่อคอลัมน์ฐานข้อมูลในรูปแบบที่ครอบคลุมมากขึ้นสำหรับการตอบกลับของ API",
"form.attribute.item.date.type.date": "วันที่",
"form.attribute.item.date.type.datetime": "วันที่เวลา",
"form.attribute.item.date.type.time": "เวลา",
"form.attribute.item.defineRelation.fieldName": "ชื่อฟิลด์",
"form.attribute.item.enumeration.graphql": "การเขียนทับชื่อสำหรับ GraphQL",
"form.attribute.item.enumeration.graphql.description": "อนุญาตให้คุณเขียนทับชื่อที่สร้างขึ้นพื้นฐานสำหรับ GraphQL",

View File

@ -63,9 +63,6 @@
"form.attribute.component.option.single.description": "Підходить для групування полей, наприклад, повна адреса, основна інформація тощо...",
"form.attribute.item.customColumnName": "Власні назви стовпців",
"form.attribute.item.customColumnName.description": "Корисно для перейменування назв стовпців у базі даних для підтримки більш зрозумілого формату відповідей API",
"form.attribute.item.date.type.date": "дата",
"form.attribute.item.date.type.datetime": "дата та час",
"form.attribute.item.date.type.time": "час",
"form.attribute.item.defineRelation.fieldName": "Назва поля",
"form.attribute.item.enumeration.graphql": "Назва поля для GraphQL",
"form.attribute.item.enumeration.graphql.description": "Дозволяє перейменувати згенеровану для GraphQL назву поля",

View File

@ -56,9 +56,6 @@
"form.attribute.component.option.single.description": "最适合的对完整地址,主要信息等字段进行分组...",
"form.attribute.item.customColumnName": "自定义列名称",
"form.attribute.item.customColumnName.description": "修改数据库列名使得API返回更容易理解。",
"form.attribute.item.date.type.date": "日期",
"form.attribute.item.date.type.datetime": "日期与时间",
"form.attribute.item.date.type.time": "时间",
"form.attribute.item.defineRelation.fieldName": "字段名称",
"form.attribute.item.enumeration.graphql": "GraphQL 的名称重写",
"form.attribute.item.enumeration.graphql.description": "允许您覆盖 GraphQL 的默认生成名称",

View File

@ -62,9 +62,6 @@
"form.attribute.component.option.single.description": "適用於組合型欄位群,如:完整地址,基本完整資訊 ......等",
"form.attribute.item.customColumnName": "自訂欄位名稱",
"form.attribute.item.customColumnName.description": "將資料庫欄位名稱以更易懂的格式重新命名,對 API 回應很有用。",
"form.attribute.item.date.type.date": "日期",
"form.attribute.item.date.type.datetime": "日期及時間",
"form.attribute.item.date.type.time": "時間",
"form.attribute.item.defineRelation.fieldName": "欄位名稱",
"form.attribute.item.enumeration.graphql": "GraphQL 名稱覆寫",
"form.attribute.item.enumeration.graphql.description": "可以讓您覆寫 GraphQL 的預設名稱",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/plugin-content-type-builder",
"version": "4.1.3",
"version": "4.1.5",
"description": "Strapi plugin to create content type",
"repository": {
"type": "git",
@ -28,9 +28,9 @@
},
"dependencies": {
"@sindresorhus/slugify": "1.1.0",
"@strapi/generators": "4.1.3",
"@strapi/helper-plugin": "4.1.3",
"@strapi/utils": "4.1.3",
"@strapi/generators": "4.1.5",
"@strapi/helper-plugin": "4.1.5",
"@strapi/utils": "4.1.5",
"fs-extra": "10.0.0",
"lodash": "4.17.21",
"pluralize": "^8.0.0",

View File

@ -1 +0,0 @@
data

View File

@ -1,36 +0,0 @@
'use strict';
const postgres = {
client: 'postgres',
connection: {
database: 'strapi',
user: 'strapi',
password: 'strapi',
},
// debug: true,
};
const mysql = {
client: 'mysql',
connection: {
database: 'strapi',
user: 'strapi',
password: 'strapi',
},
// debug: true,
};
const sqlite = {
client: 'sqlite',
connection: {
filename: 'data.sqlite',
},
useNullAsDefault: true,
// debug: true,
};
module.exports = {
sqlite,
postgres,
mysql,
};

View File

@ -1,29 +0,0 @@
version: '3'
services:
postgres:
image: postgres
restart: always
volumes:
- ./data/postgresql:/var/lib/postgresql/data
environment:
POSTGRES_USER: strapi
POSTGRES_PASSWORD: strapi
POSTGRES_DB: strapi
ports:
- '5432:5432'
mysql:
image: mysql
restart: always
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_DATABASE: strapi
MYSQL_USER: strapi
MYSQL_PASSWORD: strapi
MYSQL_ROOT_HOST: '%'
MYSQL_ROOT_PASSWORD: strapi
volumes:
- ./data/mysql:/var/lib/mysql
ports:
- '3306:3306'

View File

@ -1,73 +0,0 @@
'use strict';
const util = require('util');
const { Database } = require('../lib/index');
const models = require('./models');
const connections = require('./connections');
async function main(connection) {
const orm = await Database.init({
connection,
models: Database.transformContentTypes(models),
});
try {
// await orm.schema.drop();
// await orm.schema.create();
await orm.schema.reset();
let res;
const c1 = await orm.query('comment').create({
data: {
title: 'coucou',
},
});
const c2 = await orm.query('video-comment').create({
data: {
title: 'coucou',
},
});
res = await orm.query('article').create({
data: {
dz: [
{
__type: 'comment',
id: c1.id,
},
{
__type: 'video-comment',
id: c2.id,
},
],
},
populate: {
dz: true,
},
});
log(res);
res = await orm.query('article').findMany({
populate: {
dz: true,
},
});
log(res);
// await tests(orm);
} finally {
orm.destroy();
}
}
function log(res) {
console.log(util.inspect(res, null, null, true));
}
main(connections.sqlite);

View File

@ -1,341 +0,0 @@
'use strict';
const category = {
modelName: 'category',
uid: 'category',
collectionName: 'categories',
attributes: {
title: {
type: 'string',
},
price: {
type: 'integer',
required: true,
default: 12,
column: {
unique: true,
nonNullable: true,
unsigned: true,
defaultTo: 12,
},
},
articles: {
type: 'relation',
relation: 'oneToMany',
target: 'article',
mappedBy: 'category',
},
compo: {
type: 'component',
component: 'compo',
},
},
};
const article = {
modelName: 'article',
uid: 'article',
collectionName: 'articles',
attributes: {
title: {
type: 'string',
},
category: {
type: 'relation',
relation: 'manyToOne',
target: 'category',
inversedBy: 'articles',
// useJoinTable: false,
},
// tags: {
// type: 'relation',
// relation: 'manyToMany',
// target: 'tag',
// inversedBy: 'articles',
// },
// compo: {
// type: 'component',
// component: 'compo',
// // repeatable: true,
// },
// cover: {
// type: 'media',
// single: true,
// },
// gallery: {
// type: 'media',
// multiple: true,
// },
},
};
const tags = {
modelName: 'tag',
uid: 'tag',
collectionName: 'tags',
attributes: {
name: {
type: 'string',
},
articles: {
type: 'relation',
relation: 'manyToMany',
target: 'article',
mappedBy: 'tag',
},
},
};
const compo = {
modelName: 'compo',
uid: 'compo',
collectionName: 'compos',
attributes: {
key: {
type: 'string',
},
value: {
type: 'string',
},
},
};
const user = {
modelName: 'user',
uid: 'user',
collectionName: 'users',
attributes: {
address: {
type: 'relation',
relation: 'oneToOne',
target: 'address',
inversedBy: 'user',
// useJoinTable: false,
},
},
};
const address = {
modelName: 'address',
uid: 'address',
collectionName: 'addresses',
attributes: {
name: {
type: 'string',
},
user: {
type: 'relation',
relation: 'oneToOne',
target: 'user',
mappedBy: 'address',
},
},
};
const file = {
modelName: 'file',
uid: 'file',
collectionName: 'files',
attributes: {
name: {
type: 'string',
},
alternativeText: {
type: 'string',
},
caption: {
type: 'string',
},
width: {
type: 'integer',
},
height: {
type: 'integer',
},
formats: {
type: 'json',
},
hash: {
type: 'string',
},
ext: {
type: 'string',
},
mime: {
type: 'string',
},
size: {
type: 'decimal',
},
url: {
type: 'string',
},
previewUrl: {
type: 'string',
},
provider: {
type: 'string',
},
provider_metadata: {
type: 'json',
},
// related: {
// type: 'relation',
// relation: 'oneToMany',
// target: 'file_morph',
// mappedBy: 'file',
// },
// related: {
// type: 'relation',
// realtion: 'morphTo',
// },
},
};
const fileMorph = {
modelName: 'file-morph',
uid: 'file-morph',
collectionName: 'file_morphs',
attributes: {
// file: {
// type: 'relation',
// relation: 'manyToOne',
// target: 'file',
// inversedBy: 'related',
// useJoinTable: false,
// },
},
};
const blogPost = {
modelName: 'blogPost',
uid: 'blogPost',
collectionName: 'blog_posts',
attributes: {
passwordField: {
type: 'password',
},
emailField: {
type: 'email',
},
stringField: {
type: 'string',
},
uidField: {
type: 'uid',
},
richtextField: {
type: 'richtext',
},
textField: {
type: 'text',
},
enumerationField: {
type: 'enumeration',
enum: ['A', 'B'],
},
jsonField: {
type: 'json',
},
bigintegerField: {
type: 'biginteger',
},
integerField: {
type: 'integer',
},
floatField: {
type: 'float',
},
decimalField: {
type: 'decimal',
},
dateField: {
type: 'date',
},
timeField: {
type: 'time',
},
datetimeField: {
type: 'datetime',
},
timestampField: {
type: 'timestamp',
},
booleanField: {
type: 'boolean',
},
},
};
module.exports = [category, article, tags, compo, user, address, file, fileMorph, blogPost];
// const article = {
// modelName: 'article',
// uid: 'article',
// collectionName: 'articles',
// attributes: {
// commentable: {
// type: 'relation',
// relation: 'morphToOne',
// },
// reportables: {
// type: 'relation',
// relation: 'morphToMany',
// },
// dz: {
// type: 'dynamiczone',
// components: ['comment', 'video-comment'],
// },
// },
// };
// const comment = {
// modelName: 'comment',
// uid: 'comment',
// collectionName: 'comments',
// attributes: {
// article: {
// type: 'relation',
// relation: 'morphOne',
// target: 'article',
// morphBy: 'commentable',
// },
// title: {
// type: 'string',
// },
// },
// };
// const videoComment = {
// modelName: 'video-comment',
// uid: 'video-comment',
// collectionName: 'video_comments',
// attributes: {
// articles: {
// type: 'relation',
// relation: 'morphMany',
// target: 'article',
// morphBy: 'commentable',
// },
// title: {
// type: 'string',
// },
// },
// };
// const folder = {
// modelName: 'folder',
// uid: 'folder',
// collectionName: 'folders',
// attributes: {
// articles: {
// type: 'relation',
// relation: 'morphMany',
// target: 'article',
// morphBy: 'reportables',
// },
// },
// };
// module.exports = [article, comment, videoComment, folder];

View File

@ -1,17 +0,0 @@
type ID = number | string;
interface Category {
id: ID;
title: string;
}
interface Article {
id: ID;
title: string;
category: Category | ID;
}
interface AllTypes {
article: Article;
category: Category;
}

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/database",
"version": "4.1.3",
"version": "4.1.5",
"description": "Strapi's database layer",
"homepage": "https://strapi.io",
"bugs": {

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/plugin-email",
"version": "4.1.3",
"version": "4.1.5",
"description": "Easily configure your Strapi application to send emails.",
"repository": {
"type": "git",
@ -26,12 +26,12 @@
"test:front:watch:ce": "cross-env IS_EE=false jest --config ./jest.config.front.js --watchAll"
},
"dependencies": {
"@strapi/provider-email-sendmail": "4.1.3",
"@strapi/utils": "4.1.3",
"@strapi/provider-email-sendmail": "4.1.5",
"@strapi/utils": "4.1.5",
"lodash": "4.17.21"
},
"devDependencies": {
"@strapi/helper-plugin": "4.1.3"
"@strapi/helper-plugin": "4.1.5"
},
"engines": {
"node": ">=12.22.0 <=16.x.x",

View File

@ -8,7 +8,7 @@ import { Box } from '@strapi/design-system/Box';
import { Flex } from '@strapi/design-system/Flex';
import { BaseCheckbox } from '@strapi/design-system/BaseCheckbox';
import { Dialog, DialogBody, DialogFooter } from '@strapi/design-system/Dialog';
import { Tbody, Td, Tr } from '@strapi/design-system/Table';
import { Tbody, Td, Tr, TFooter } from '@strapi/design-system/Table';
import { Typography } from '@strapi/design-system/Typography';
import { IconButton } from '@strapi/design-system/IconButton';
import { Plus, Pencil, Trash } from '@strapi/icons';
@ -93,6 +93,43 @@ import { DynamicTable } from '@strapi/helper-plugin';
</Story>
</Canvas>
## Usage No content with footer
<Canvas>
<Story name="no-content-with-footer">
{() => {
const headers = [
{
name: 'firstname',
metadatas: { label: 'Firstname', sortable: false },
key: '__firstname_key__',
},
{
name: 'lastname',
metadatas: { label: 'Email', sortable: false },
key: '__lastname_key__',
},
{
name: 'email',
metadatas: { label: 'Email', sortable: false },
key: '__email_key__',
},
];
const [{ query }, setQuery] = useQueryParams();
useEffect(() => {
setQuery({ filters: { $and: [{ firstname: { $eq: 'soupette' } }] } });
}, []);
return (
<Main>
<Box paddingTop={6}>
<DynamicTable headers={headers} contentType="users" footer={<TFooter icon={<Plus />}>Add another user</TFooter>}/>
</Box>
</Main>
);
}}
</Story>
</Canvas>
## Usage No content with filters
<Canvas>

View File

@ -23,10 +23,11 @@ const BlockActions = styled(Flex)`
`;
const Table = ({
action,
children,
contentType,
components,
action,
footer,
headers,
isLoading,
onConfirmDeleteAll,
@ -159,7 +160,7 @@ const Table = ({
</Box>
</Box>
)}
<TableCompo colCount={COL_COUNT} rowCount={ROW_COUNT}>
<TableCompo colCount={COL_COUNT} rowCount={ROW_COUNT} footer={footer}>
<TableHead
areAllEntriesSelected={areAllEntriesSelected}
entriesToDelete={entriesToDelete}
@ -207,12 +208,13 @@ const Table = ({
};
Table.defaultProps = {
action: undefined,
children: undefined,
components: {
ConfirmDialogDeleteAll: undefined,
ConfirmDialogDelete: undefined,
},
action: undefined,
footer: undefined,
headers: [],
isLoading: false,
onConfirmDeleteAll: () => {},
@ -224,13 +226,14 @@ Table.defaultProps = {
};
Table.propTypes = {
action: PropTypes.node,
children: PropTypes.node,
contentType: PropTypes.string.isRequired,
components: PropTypes.shape({
ConfirmDialogDelete: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
ConfirmDialogDeleteAll: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
}),
action: PropTypes.node,
footer: PropTypes.node,
headers: PropTypes.arrayOf(
PropTypes.shape({
cellFormatter: PropTypes.func,

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/helper-plugin",
"version": "4.1.3",
"version": "4.1.5",
"description": "Helper for Strapi plugins development",
"repository": {
"type": "git",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/strapi",
"version": "4.1.3",
"version": "4.1.5",
"description": "An open source headless CMS solution to create and manage your own API. It provides a powerful dashboard and features to make your life easier. Databases supported: MySQL, MariaDB, PostgreSQL, SQLite",
"keywords": [
"strapi",
@ -80,16 +80,16 @@
"dependencies": {
"@koa/cors": "3.1.0",
"@koa/router": "10.1.1",
"@strapi/admin": "4.1.3",
"@strapi/database": "4.1.3",
"@strapi/generate-new": "4.1.3",
"@strapi/generators": "4.1.3",
"@strapi/logger": "4.1.3",
"@strapi/plugin-content-manager": "4.1.3",
"@strapi/plugin-content-type-builder": "4.1.3",
"@strapi/plugin-email": "4.1.3",
"@strapi/plugin-upload": "4.1.3",
"@strapi/utils": "4.1.3",
"@strapi/admin": "4.1.5",
"@strapi/database": "4.1.5",
"@strapi/generate-new": "4.1.5",
"@strapi/generators": "4.1.5",
"@strapi/logger": "4.1.5",
"@strapi/plugin-content-manager": "4.1.5",
"@strapi/plugin-content-type-builder": "4.1.5",
"@strapi/plugin-email": "4.1.5",
"@strapi/plugin-upload": "4.1.5",
"@strapi/utils": "4.1.5",
"bcryptjs": "2.4.3",
"boxen": "5.1.2",
"chalk": "4.1.2",

View File

@ -48,7 +48,8 @@ export const VideoAssetCard = ({
}) => {
const { formatMessage } = useIntl();
const [duration, setDuration] = useState();
const formattedDuration = duration ? formatDuration(duration) : undefined;
const formattedDuration = duration && formatDuration(duration);
return (
<Card>

View File

@ -17,7 +17,7 @@ export const SelectedStep = ({ selectedAssets, onSelectAsset, onReorderAsset })
{
id: getTrad('list.assets.selected'),
defaultMessage:
'{number, plural, =0 {No asset} one {1 asset} other {# assets}} selected',
'{number, plural, =0 {No asset} one {1 asset} other {# assets}} ready to upload',
},
{ number: selectedAssets.length }
)}
@ -25,7 +25,7 @@ export const SelectedStep = ({ selectedAssets, onSelectAsset, onReorderAsset })
<Typography variant="pi" textColor="neutral600">
{formatMessage({
id: getTrad('modal.upload-list.sub-header-subtitle'),
defaultMessage: 'Manage the assets before uploading them to the Media Library',
defaultMessage: 'Manage the assets before adding them to the Media Library',
})}
</Typography>
</Stack>

View File

@ -78,7 +78,7 @@ export const PendingAssetStep = ({
{
id: getTrad('list.assets.selected'),
defaultMessage:
'{number, plural, =0 {No asset} one {1 asset} other {# assets}} selected',
'{number, plural, =0 {No asset} one {1 asset} other {# assets}} ready to upload',
},
{ number: assets.length }
)}
@ -86,7 +86,7 @@ export const PendingAssetStep = ({
<Typography variant="pi" textColor="neutral600">
{formatMessage({
id: getTrad('modal.upload-list.sub-header-subtitle'),
defaultMessage: 'Manage the assets before uploading them to the Media Library',
defaultMessage: 'Manage the assets before adding them to the Media Library',
})}
</Typography>
</Stack>

View File

@ -768,7 +768,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
<span
class="c12"
>
Manage the assets before uploading them to the Media Library
Manage the assets before adding them to the Media Library
</span>
</div>
<button

View File

@ -101,7 +101,7 @@ describe('UploadAssetDialog', () => {
)
).toBeInTheDocument();
expect(
screen.getByText('Manage the assets before uploading them to the Media Library')
screen.getByText('Manage the assets before adding them to the Media Library')
).toBeInTheDocument();
expect(screen.getAllByText(`test.${ext}`).length).toBe(number);
expect(screen.getByText(ext)).toBeInTheDocument();
@ -199,7 +199,7 @@ describe('UploadAssetDialog', () => {
);
expect(screen.getAllByText(`Add new assets`).length).toBe(2);
expect(
screen.getByText('Manage the assets before uploading them to the Media Library')
screen.getByText('Manage the assets before adding them to the Media Library')
).toBeInTheDocument();
assets.forEach(asset => {

View File

@ -68,7 +68,7 @@
"modal.remove.success-label": "The asset has been successfully removed.",
"modal.selected-list.sub-header-subtitle": "Drag & drop to reorder the assets in the field",
"modal.upload-list.footer.button": "Upload {number, plural, one {# asset} other {# assets}} to the library",
"modal.upload-list.sub-header-subtitle": "Manage the assets before uploading them to the Media Library",
"modal.upload-list.sub-header-subtitle": "Manage the assets before adding them to the Media Library",
"modal.upload-list.sub-header.button": "Add more assets",
"modal.upload.cancelled": "Upload manually aborted.",
"page.title": "Settings - Media Library",

View File

@ -1,12 +1,9 @@
import { intervalToDuration } from 'date-fns';
const zeroPad = num => String(num).padStart(2, '0');
export const formatDuration = durationInSecond => {
const formatter = new Intl.DateTimeFormat('default', {
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
});
const duration = intervalToDuration({ start: 0, end: durationInSecond * 1000 });
const date = new Date(1970, 0, 1);
date.setSeconds(durationInSecond);
return formatter.format(date);
return `${zeroPad(duration.hours)}:${zeroPad(duration.minutes)}:${zeroPad(duration.seconds)}`;
};

View File

@ -0,0 +1,9 @@
import { formatDuration } from '../formatDuration';
describe('formatDuration', () => {
test('properly format seconds', () => {
expect(formatDuration(1)).toBe('00:00:01');
expect(formatDuration(60)).toBe('00:01:00');
expect(formatDuration(3600)).toBe('01:00:00');
});
});

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/plugin-upload",
"version": "4.1.3",
"version": "4.1.5",
"description": "Makes it easy to upload images and files to your Strapi Application.",
"license": "SEE LICENSE IN LICENSE",
"author": {
@ -23,9 +23,9 @@
"test:front:watch:ce": "cross-env IS_EE=false jest --config ./jest.config.front.js --watchAll"
},
"dependencies": {
"@strapi/helper-plugin": "4.1.3",
"@strapi/provider-upload-local": "4.1.3",
"@strapi/utils": "4.1.3",
"@strapi/helper-plugin": "4.1.5",
"@strapi/provider-upload-local": "4.1.5",
"@strapi/utils": "4.1.5",
"byte-size": "7.0.1",
"cropperjs": "1.5.11",
"fs-extra": "10.0.0",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/utils",
"version": "4.1.3",
"version": "4.1.5",
"description": "Shared utilities for the Strapi packages",
"keywords": [
"strapi",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/generate-new",
"version": "4.1.3",
"version": "4.1.5",
"description": "Generate a new Strapi application.",
"keywords": [
"generate",

View File

@ -1,5 +1,5 @@
const pluginPkg = require('../../package.json');
const pluginId = pluginPkg.name.replace(/^@strapi\/plugin-/i, '');
const pluginId = pluginPkg.name.replace(/^(@[^-,.][\w,-]+\/|strapi-)plugin-/i, '');
module.exports = pluginId;

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/generators",
"version": "4.1.3",
"version": "4.1.5",
"description": "Interactive API generator.",
"keywords": [
"strapi",
@ -30,7 +30,7 @@
"main": "lib/index.js",
"dependencies": {
"@sindresorhus/slugify": "1.1.0",
"@strapi/utils": "4.1.3",
"@strapi/utils": "4.1.5",
"chalk": "4.1.2",
"fs-extra": "10.0.0",
"node-plop": "0.26.3",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/plugin-documentation",
"version": "4.1.3",
"version": "4.1.5",
"description": "Create an OpenAPI Document and visualize your API with SWAGGER UI.",
"repository": {
"type": "git",
@ -24,8 +24,8 @@
"test": "echo \"no tests yet\""
},
"dependencies": {
"@strapi/helper-plugin": "4.1.3",
"@strapi/utils": "4.1.3",
"@strapi/helper-plugin": "4.1.5",
"@strapi/utils": "4.1.5",
"bcryptjs": "2.4.3",
"cheerio": "^1.0.0-rc.5",
"fs-extra": "10.0.0",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/plugin-graphql",
"version": "4.1.3",
"version": "4.1.5",
"description": "Adds GraphQL endpoint with default API methods.",
"repository": {
"type": "git",
@ -30,7 +30,7 @@
"@apollo/federation": "^0.28.0",
"@graphql-tools/schema": "8.1.2",
"@graphql-tools/utils": "^8.0.2",
"@strapi/utils": "4.1.3",
"@strapi/utils": "4.1.5",
"apollo-server-core": "3.1.2",
"apollo-server-koa": "3.1.2",
"glob": "^7.1.7",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/plugin-i18n",
"version": "4.1.3",
"version": "4.1.5",
"description": "This plugin enables to create, to read and to update content in different languages, both from the Admin Panel and from the API",
"repository": {
"type": "git",
@ -24,7 +24,7 @@
"test:unit": "jest --verbose"
},
"dependencies": {
"@strapi/utils": "4.1.3",
"@strapi/utils": "4.1.5",
"lodash": "4.17.21"
},
"engines": {

View File

@ -1 +1,4 @@
{}
{
"plugin.description.long": "Gửi lỗi Strapi lên Sentry.",
"plugin.description.short": "Gửi lỗi Strapi lên Sentry."
}

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/plugin-sentry",
"version": "4.1.3",
"version": "4.1.5",
"description": "Send Strapi error events to Sentry",
"repository": {
"type": "git",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/plugin-users-permissions",
"version": "4.1.3",
"version": "4.1.5",
"description": "Protect your API with a full-authentication process based on JWT",
"repository": {
"type": "git",
@ -28,8 +28,8 @@
},
"dependencies": {
"@purest/providers": "^1.0.2",
"@strapi/helper-plugin": "4.1.3",
"@strapi/utils": "4.1.3",
"@strapi/helper-plugin": "4.1.5",
"@strapi/utils": "4.1.5",
"bcryptjs": "2.4.3",
"grant-koa": "5.4.8",
"jsonwebtoken": "^8.1.0",

View File

@ -17,7 +17,7 @@ const {
validateSendEmailConfirmationBody,
} = require('./validation/auth');
const { sanitize } = utils;
const { getAbsoluteAdminUrl, getAbsoluteServerUrl, sanitize } = utils;
const { ApplicationError, ValidationError } = utils.errors;
const emailRegExp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
@ -243,6 +243,8 @@ module.exports = {
settings.message = await getService('users-permissions').template(settings.message, {
URL: advanced.email_reset_password,
SERVER_URL: getAbsoluteServerUrl(strapi.config),
ADMIN_URL: getAbsoluteAdminUrl(strapi.config),
USER: userInfo,
TOKEN: resetPasswordToken,
});

View File

@ -3,7 +3,16 @@
const _ = require('lodash');
const invalidPatternsRegexes = [/<%[^=]([^<>%]*)%>/m, /\${([^{}]*)}/m];
const authorizedKeys = ['URL', 'CODE', 'USER', 'USER.email', 'USER.username', 'TOKEN'];
const authorizedKeys = [
'URL',
'ADMIN_URL',
'SERVER_URL',
'CODE',
'USER',
'USER.email',
'USER.username',
'TOKEN',
];
const matchAll = (pattern, src) => {
const matches = [];

View File

@ -10,7 +10,7 @@ const crypto = require('crypto');
const bcrypt = require('bcryptjs');
const urlJoin = require('url-join');
const { getAbsoluteServerUrl, sanitize } = require('@strapi/utils');
const { getAbsoluteAdminUrl, getAbsoluteServerUrl, sanitize } = require('@strapi/utils');
const { getService } = require('../utils');
module.exports = ({ strapi }) => ({
@ -118,6 +118,8 @@ module.exports = ({ strapi }) => ({
const apiPrefix = strapi.config.get('api.rest.prefix');
settings.message = await userPermissionService.template(settings.message, {
URL: urlJoin(getAbsoluteServerUrl(strapi.config), apiPrefix, '/auth/email-confirmation'),
SERVER_URL: getAbsoluteServerUrl(strapi.config),
ADMIN_URL: getAbsoluteAdminUrl(strapi.config),
USER: sanitizedUserInfo,
CODE: confirmationToken,
});

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/provider-email-amazon-ses",
"version": "4.1.3",
"version": "4.1.5",
"description": "Amazon SES provider for strapi email",
"keywords": [
"email",
@ -36,7 +36,7 @@
"test": "echo \"no tests yet\""
},
"dependencies": {
"@strapi/utils": "4.1.3",
"@strapi/utils": "4.1.5",
"node-ses": "^3.0.3"
},
"engines": {

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/provider-email-mailgun",
"version": "4.1.3",
"version": "4.1.5",
"description": "Mailgun provider for strapi email plugin",
"keywords": [
"email",
@ -36,7 +36,7 @@
"test": "echo \"no tests yet\""
},
"dependencies": {
"@strapi/utils": "4.1.3",
"@strapi/utils": "4.1.5",
"mailgun-js": "0.22.0"
},
"engines": {

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/provider-email-nodemailer",
"version": "4.1.3",
"version": "4.1.5",
"description": "Nodemailer provider for Strapi 3",
"keywords": [
"strapi",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/provider-email-sendgrid",
"version": "4.1.3",
"version": "4.1.5",
"description": "Sendgrid provider for strapi email",
"keywords": [
"email",
@ -37,7 +37,7 @@
},
"dependencies": {
"@sendgrid/mail": "7.4.7",
"@strapi/utils": "4.1.3"
"@strapi/utils": "4.1.5"
},
"engines": {
"node": ">=12.22.0 <=16.x.x",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/provider-email-sendmail",
"version": "4.1.3",
"version": "4.1.5",
"description": "Sendmail provider for strapi email",
"keywords": [
"email",
@ -35,7 +35,7 @@
"test": "echo \"no tests yet\""
},
"dependencies": {
"@strapi/utils": "4.1.3",
"@strapi/utils": "4.1.5",
"sendmail": "^1.6.1"
},
"engines": {

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/provider-upload-aws-s3",
"version": "4.1.3",
"version": "4.1.5",
"description": "AWS S3 provider for strapi upload",
"keywords": [
"upload",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/provider-upload-cloudinary",
"version": "4.1.3",
"version": "4.1.5",
"description": "Cloudinary provider for strapi upload",
"keywords": [
"upload",
@ -36,7 +36,7 @@
"test": "echo \"no tests yet\""
},
"dependencies": {
"@strapi/utils": "4.1.3",
"@strapi/utils": "4.1.5",
"cloudinary": "^1.25.1",
"into-stream": "^5.1.0"
},

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/provider-upload-local",
"version": "4.1.3",
"version": "4.1.5",
"description": "Local provider for strapi upload",
"keywords": [
"upload",
@ -35,7 +35,7 @@
"test": "echo \"no tests yet\""
},
"dependencies": {
"@strapi/utils": "4.1.3"
"@strapi/utils": "4.1.5"
},
"engines": {
"node": ">=12.22.0 <=16.x.x",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/provider-upload-rackspace",
"version": "4.1.3",
"version": "4.1.5",
"description": "Rackspace provider for strapi upload",
"repository": {
"type": "git",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/babel-plugin-switch-ee-ce",
"version": "4.1.3",
"version": "4.1.5",
"private": false,
"description": "Babel plugin to switch from CE to EE at runtime",
"repository": "git://github.com/strapi/strapi.git",

View File

@ -1,6 +1,6 @@
{
"name": "@strapi/logger",
"version": "4.1.3",
"version": "4.1.5",
"description": "Strapi's logger",
"homepage": "https://strapi.io",
"bugs": {

View File

@ -0,0 +1,33 @@
'use strict';
const fs = require('fs-extra');
const { updateMissingKeysToJSON } = require('../add-missing-keys-to-other-language');
describe('updateMissingKeysToJSON', () => {
it('should add missing keys from en.json to translation file', async () => {
const TARGET_TRANSLATION_FILE_PATH = 'scripts/front/__tests__/vi.json';
const SOURCE_TRANSLATION_FILE_PATH = 'scripts/front/__tests__/en.json';
// Save original `vi.json` file content
const originalTargetTranslationFileContent = fs.readFileSync(
TARGET_TRANSLATION_FILE_PATH,
'utf8'
);
const originalTargetTranslationFileJSON = JSON.parse(originalTargetTranslationFileContent);
const mainTranslationFileJSON = await fs.readJSON(SOURCE_TRANSLATION_FILE_PATH);
// Add missing keys for `vi.json`
const updatedTargetTranslationFileJSON = await updateMissingKeysToJSON(
TARGET_TRANSLATION_FILE_PATH
);
// `vi.json` should have all keys from `en.json`
Object.keys(mainTranslationFileJSON).forEach(key => {
expect(key in updatedTargetTranslationFileJSON).toBe(true);
});
// `vi.json` should keep the current translation
Object.keys(originalTargetTranslationFileContent).forEach(key => {
expect(updatedTargetTranslationFileJSON[key]).toEqual(originalTargetTranslationFileJSON[key]);
});
});
});

View File

@ -0,0 +1,8 @@
{
"Analytics": "Analytics",
"Auth.components.Oops.text": "Your account has been suspended.",
"Auth.components.Oops.text.admin": "If this is a mistake, please contact your administrator.",
"Auth.components.Oops.title": "Oops...",
"Auth.form.button.forgot-password": "Send Email",
"Auth.form.button.go-home": "GO BACK HOME"
}

View File

@ -0,0 +1,6 @@
{
"Analytics": "Phân Tích",
"Auth.components.Oops.text.admin": "Nếu có sự nhầm lẫn, hãy liên hệ người quản trị",
"Auth.components.Oops.title": "Oops...",
"Auth.form.button.go-home": "QUAY VỀ TRANG CHỦ"
}

View File

@ -0,0 +1,81 @@
// Add missing keys to non-english languages from `en.json`.
// This script eases the process of translating strapi to other languages.
// Usage:
// node scripts/front/add-missing-keys-to-other-language.js [language]
// Example:
// node scripts/front/add-missing-keys-to-other-language.js vi
'use strict';
const { join, dirname } = require('path');
const { promisify } = require('util');
const fs = require('fs-extra');
const glob = promisify(require('glob').glob);
const chalk = require('chalk');
const updateMissingKeysToJSON = async filePath => {
// Read translation file
const currentTranslationFileJSON = await fs.readJSON(filePath);
// Read en.json
const mainTranslationFile = join(dirname(filePath), 'en.json');
const mainTranslationFileJSON = await fs.readJSON(mainTranslationFile);
// Add missing keys from en.json to translation file
const updatedFileJSON = Object.keys(mainTranslationFileJSON).reduce((acc, current) => {
if (currentTranslationFileJSON[current]) {
acc[current] = currentTranslationFileJSON[current];
} else {
acc[current] = mainTranslationFileJSON[current];
}
return acc;
}, {});
return updatedFileJSON;
};
const addMissingKeyForSingleFile = async filePath => {
console.log('Start adding missing keys to', filePath);
try {
const updatedFileJSON = await updateMissingKeysToJSON(filePath);
await fs.writeJson(filePath, updatedFileJSON, { spaces: 2 });
console.log('Added missing keys to', filePath);
return Promise.resolve();
} catch (err) {
return Promise.reject(err);
}
};
const addMissingKeys = async lang => {
// Get translation files
const corePackageDirs = await glob('packages/core/*');
const pluginsPackageDirs = await glob('packages/plugins/*');
const packageDirs = [...corePackageDirs, ...pluginsPackageDirs];
const pathToTranslationsFolder = ['admin', 'src', 'translations'];
const translationFiles = packageDirs
.filter(dir => {
return fs.existsSync(join(dir, ...pathToTranslationsFolder, `${lang}.json`));
})
.map(dir => {
return join(dir, ...pathToTranslationsFolder, `${lang}.json`);
});
console.log('List of files to add missing keys', translationFiles, '\n');
// For each file run addMissingKeyForSingleFile
translationFiles.forEach(addMissingKeyForSingleFile);
};
if (process.argv.length < 3) {
console.warn(
chalk.yellow(
'Please provide a language. For example:\nnode scripts/front/add-missing-keys-to-other-language.js vi'
)
);
process.exit(1);
}
if (require.main === module) {
addMissingKeys(process.argv[2]).catch(err => console.error(err));
}
module.exports = {
updateMissingKeysToJSON,
};

View File

@ -26,7 +26,7 @@ const cleanFile = async filePath => {
return Promise.resolve();
} catch (err) {
return Promise.reject();
return Promise.reject(err);
}
};