Compare commits

..

13 Commits

Author SHA1 Message Date
Elliot DeNolf
f754edc375 chore(release): v3.0.0-beta.89 [skip ci] 2024-08-21 20:54:18 -04:00
Paul
d2571e10d6 feat: upload hasmany (#7796)
Supports `hasMany` upload fields, similar to how `hasMany` works in
other fields, i.e.:

```ts
{
  type: 'upload',
  relationTo: 'media',
  hasMany: true
}
```

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
Co-authored-by: James <james@trbl.design>
2024-08-21 20:44:04 -04:00
Alessio Gravili
a687cb9c5b Merge PR: Lexical migration and validation improvements 2024-08-21 18:31:53 -04:00
Alessio Gravili
cf6634111f fix(richtext-lexical): ensure errors during slate => lexical migration are caught and do not halt migration progress 2024-08-21 17:52:45 -04:00
Jarrod Flesch
1ee19d3016 feat: bulk upload (#7800)
## Description

Adds bulk upload functionality to upload enabled configs.

You can disable the ability by defining `upload.bulkUpload: false` in
your upload enabled config.

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-21 17:44:34 -04:00
Alessio Gravili
9beaa281dc feat: log document id in ValidationError cause, if present 2024-08-21 17:31:31 -04:00
Alessio Gravili
5174c7092f fix(richtext-lexical): inaccurate detection of whether the editor is empty or not 2024-08-21 17:26:02 -04:00
Alessio Gravili
d894ac75f0 fix(richtext-lexical): migrate scripts not working due to migration hooks running during migrate script 2024-08-21 16:43:56 -04:00
Alessio Gravili
af0105ced5 fix: no longer handle disabling node deprecation warnings within bin script shebangs, as it errored on some systems (#7797)
Fixes https://github.com/payloadcms/payload/issues/7741

I have no idea why it broke and was not able to reproduce this at all.
But given the amount of people reporting this issue, it's not worth
keeping this around for the small benefit this brings
2024-08-21 17:01:57 +00:00
Tylan Davis
93e81314df fix(ui, richtext-lexical): corrects clickable areas on block headers (#7791)
## Description

Fixes an issue where Block component section titles were taking up the
entire clickable area of block headers.

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

<!-- Please delete options that are not relevant. -->

- [x] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-21 10:45:05 -04:00
Jarrod Flesch
163d1c85da chore: corrects icon color styles (#7792) 2024-08-21 10:28:01 -04:00
Jacob Fletcher
cb9b80aaf9 fix!: handles custom collection description components (#7789)
## Description

Closes #7784 by properly handling custom collection description
components via `admin.components.Description`. This component was
incorrectly added to the `admin.components.edit` key, and also was never
handled on the front-end. This was especially misleading because the
client-side config had a duplicative key in the proper position.

## Breaking Changes

This PR is only labeled as a breaking change because the key has changed
position within the config. If you were previously defining a custom
description component on a collection, simply move it into the correct
position:

Old:
```ts
{
  admin: {
    components: {
      edit: {
        Description: ''
      }
    }
  }
}
```

New:

```ts
{
  admin: {
    components: {
      Description: ''
    }
  }
}
```

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)
- [x] This change requires a documentation update

## Checklist:

- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [x] I have made corresponding changes to the documentation
2024-08-21 10:20:22 -04:00
Jarrod Flesch
cad1906725 feat: extends Button and extracts ListHeader components (#7777) 2024-08-21 09:37:11 -04:00
193 changed files with 4050 additions and 692 deletions

View File

@@ -31,7 +31,7 @@ The following options are available:
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Collection from navigation and admin routing. |
| **`hooks`** | Admin-specific hooks for this Collection. [More details](../hooks/collections). |
| **`useAsTitle`** | Specify a top-level field to use for a document title throughout the Admin Panel. If no field is defined, the ID of the document is used as the title. |
| **`description`** | Text or React component to display below the Collection label in the List View to give editors more information. |
| **`description`** | Text to display below the Collection label in the List View to give editors more information. Alternatively, you can use the `admin.components.Description` to render a React component. [More details](#components). |
| **`defaultColumns`** | Array of field names that correspond to which columns to show by default in this Collection's List View. |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this Collection. |
| **`enableRichTextLink`** | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
@@ -69,7 +69,8 @@ The following options are available:
| **`beforeList`** | An array of components to inject _before_ the built-in List View |
| **`beforeListTable`** | An array of components to inject _before_ the built-in List View's table |
| **`afterList`** | An array of components to inject _after_ the built-in List View |
| **`afterListTable`** | An array of components to inject _after_ the built-in List View's table |
| **`afterListTable`** | An array of components to inject _after_ the built-in List View's table
| **`Description`** | A component to render below the Collection label in the List View. An alternative to the `admin.description` property. |
| **`edit.SaveButton`** | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. |
| **`edit.SaveDraftButton`** | Replace the default Save Draft Button with a Custom Component. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. |
| **`edit.PublishButton`** | Replace the default Publish Button with a Custom Component. [Drafts](../versions/drafts) must be enabled. |

View File

@@ -18,6 +18,7 @@ IMPORTANT: This will overwrite all slate data. We recommend doing the following
1. Take a backup of your entire database. If anything goes wrong and you do not have a backup, you are on your own and will not receive any support.
2. Make every richText field a lexical editor. This script will only convert lexical richText fields with old Slate data
3. Add the SlateToLexicalFeature (as seen below) first, and test it out by loading up the Admin Panel, to see if the migrator works as expected. You might have to build some custom converters for some fields first in order to convert custom Slate nodes. The SlateToLexicalFeature is where the converters are stored. Only fields with this feature added will be migrated.
4. If this works as expected, add the `disableHooks: true` prop everywhere you're initializing `SlateToLexicalFeature`. Example: `SlateToLexicalFeature({ disableHooks: true })`. Once you did that, you're ready to run the migration script.
```ts
import { migrateSlateToLexical } from '@payloadcms/richtext-lexical/migrate'

View File

@@ -92,6 +92,7 @@ _An asterisk denotes that an option is required._
| Option | Description |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`adminThumbnail`** | Set the way that the [Admin Panel](../admin/overview) will display thumbnails for this Collection. [More](#admin-thumbnails) |
| **`bulkUpload`** | Allow users to upload in bulk from the list view, default is true |
| **`crop`** | Set to `false` to disable the cropping tool in the [Admin Panel](../admin/overview). Crop is enabled by default. [More](#crop-and-focal-point-selector) |
| **`disableLocalStorage`** | Completely disable uploading files to disk locally. [More](#disabling-local-upload-storage) |
| **`displayPreview`** | Enable displaying preview of the uploaded file in Upload fields related to this Collection. Can be locally overridden by `displayPreview` option in Upload field. [More](/docs/fields/upload#config-options). |

View File

@@ -1,6 +1,6 @@
{
"name": "payload-monorepo",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,6 +1,6 @@
{
"name": "create-payload-app",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-mongodb",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "The officially supported MongoDB database adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -595,14 +595,77 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
config: SanitizedConfig,
buildSchemaOptions: BuildSchemaOptions,
): void => {
const baseSchema = {
...formatBaseSchema(field, buildSchemaOptions),
type: mongoose.Schema.Types.Mixed,
ref: field.relationTo,
const hasManyRelations = Array.isArray(field.relationTo)
let schemaToReturn: { [key: string]: any } = {}
if (field.localized && config.localization) {
schemaToReturn = {
type: config.localization.localeCodes.reduce((locales, locale) => {
let localeSchema: { [key: string]: any } = {}
if (hasManyRelations) {
localeSchema = {
...formatBaseSchema(field, buildSchemaOptions),
_id: false,
type: mongoose.Schema.Types.Mixed,
relationTo: { type: String, enum: field.relationTo },
value: {
type: mongoose.Schema.Types.Mixed,
refPath: `${field.name}.${locale}.relationTo`,
},
}
} else {
localeSchema = {
...formatBaseSchema(field, buildSchemaOptions),
type: mongoose.Schema.Types.Mixed,
ref: field.relationTo,
}
}
return {
...locales,
[locale]: field.hasMany
? { type: [localeSchema], default: formatDefaultValue(field) }
: localeSchema,
}
}, {}),
localized: true,
}
} else if (hasManyRelations) {
schemaToReturn = {
...formatBaseSchema(field, buildSchemaOptions),
_id: false,
type: mongoose.Schema.Types.Mixed,
relationTo: { type: String, enum: field.relationTo },
value: {
type: mongoose.Schema.Types.Mixed,
refPath: `${field.name}.relationTo`,
},
}
if (field.hasMany) {
schemaToReturn = {
type: [schemaToReturn],
default: formatDefaultValue(field),
}
}
} else {
schemaToReturn = {
...formatBaseSchema(field, buildSchemaOptions),
type: mongoose.Schema.Types.Mixed,
ref: field.relationTo,
}
if (field.hasMany) {
schemaToReturn = {
type: [schemaToReturn],
default: formatDefaultValue(field),
}
}
}
schema.add({
[field.name]: localizeSchema(field, baseSchema, config.localization),
[field.name]: schemaToReturn,
})
},
}

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-postgres",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "The officially supported Postgres database adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-sqlite",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "The officially supported SQLite database adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -717,7 +717,7 @@ export const traverseFields = ({
case 'upload':
if (Array.isArray(field.relationTo)) {
field.relationTo.forEach((relation) => relationships.add(relation))
} else if (field.type === 'relationship' && field.hasMany) {
} else if (field.hasMany) {
relationships.add(field.relationTo)
} else {
// simple relationships get a column on the targetTable with a foreign key to the relationTo table

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/drizzle",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "A library of shared functions used by different payload database adapters",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-param-reassign */
import type { Field } from 'payload'
import { fieldAffectsData, tabHasName } from 'payload/shared'
@@ -34,8 +33,9 @@ export const traverseFields = ({
// handle simple relationship
if (
depth > 0 &&
(field.type === 'upload' ||
(field.type === 'relationship' && !field.hasMany && typeof field.relationTo === 'string'))
(field.type === 'upload' || field.type === 'relationship') &&
!field.hasMany &&
typeof field.relationTo === 'string'
) {
if (field.localized) {
_locales.with[`${path}${field.name}`] = true

View File

@@ -726,7 +726,7 @@ export const traverseFields = ({
case 'upload':
if (Array.isArray(field.relationTo)) {
field.relationTo.forEach((relation) => relationships.add(relation))
} else if (field.type === 'relationship' && field.hasMany) {
} else if (field.hasMany) {
relationships.add(field.relationTo)
} else {
// simple relationships get a column on the targetTable with a foreign key to the relationTo table

View File

@@ -445,7 +445,7 @@ export const getTableColumnFromPath = ({
case 'relationship':
case 'upload': {
const newCollectionPath = pathSegments.slice(1).join('.')
if (Array.isArray(field.relationTo) || (field.type === 'relationship' && field.hasMany)) {
if (Array.isArray(field.relationTo) || field.hasMany) {
let relationshipFields
const relationTableName = `${rootTableName}${adapter.relationshipsSuffix}`
const {

View File

@@ -351,6 +351,7 @@ export const upsertRow = async <T extends Record<string, unknown> | TypeWithID>(
throw error.code === '23505'
? new ValidationError(
{
id,
errors: [
{
field: adapter.fieldConstraints[tableName][error.constraint],

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/email-nodemailer",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "Payload Nodemailer Email Adapter",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/email-resend",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "Payload Resend Email Adapter",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env node --no-deprecation
#!/usr/bin/env node
import path from 'node:path'
import { fileURLToPath, pathToFileURL } from 'node:url'

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/graphql",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -307,10 +307,51 @@ export function buildMutationInputType({
...inputObjectTypeConfig,
[field.name]: { type: withNullableType(field, GraphQLString, forceNullable) },
}),
upload: (inputObjectTypeConfig: InputObjectTypeConfig, field: UploadField) => ({
...inputObjectTypeConfig,
[field.name]: { type: withNullableType(field, GraphQLString, forceNullable) },
}),
upload: (inputObjectTypeConfig: InputObjectTypeConfig, field: UploadField) => {
const { relationTo } = field
type PayloadGraphQLRelationshipType =
| GraphQLInputObjectType
| GraphQLList<GraphQLScalarType>
| GraphQLScalarType
let type: PayloadGraphQLRelationshipType
if (Array.isArray(relationTo)) {
const fullName = `${combineParentName(
parentName,
toWords(field.name, true),
)}RelationshipInput`
type = new GraphQLInputObjectType({
name: fullName,
fields: {
relationTo: {
type: new GraphQLEnumType({
name: `${fullName}RelationTo`,
values: relationTo.reduce(
(values, option) => ({
...values,
[formatName(option)]: {
value: option,
},
}),
{},
),
}),
},
value: { type: GraphQLJSON },
},
})
} else {
type = getCollectionIDType(
config.db.defaultIDType,
graphqlResult.collections[relationTo].config,
)
}
return {
...inputObjectTypeConfig,
[field.name]: { type: field.hasMany ? new GraphQLList(type) : type },
}
},
}
const fieldName = formatName(name)

View File

@@ -594,49 +594,164 @@ export function buildObjectType({
}),
upload: (objectTypeConfig: ObjectTypeConfig, field: UploadField) => {
const { relationTo } = field
const isRelatedToManyCollections = Array.isArray(relationTo)
const hasManyValues = field.hasMany
const relationshipName = combineParentName(parentName, toWords(field.name, true))
const uploadName = combineParentName(parentName, toWords(field.name, true))
let type
let relationToType = null
if (Array.isArray(relationTo)) {
relationToType = new GraphQLEnumType({
name: `${relationshipName}_RelationTo`,
values: relationTo.reduce(
(relations, relation) => ({
...relations,
[formatName(relation)]: {
value: relation,
},
}),
{},
),
})
const types = relationTo.map((relation) => graphqlResult.collections[relation].graphQL.type)
type = new GraphQLObjectType({
name: `${relationshipName}_Relationship`,
fields: {
relationTo: {
type: relationToType,
},
value: {
type: new GraphQLUnionType({
name: relationshipName,
resolveType(data, { req }) {
return graphqlResult.collections[data.collection].graphQL.type.name
},
types,
}),
},
},
})
} else {
;({ type } = graphqlResult.collections[relationTo].graphQL)
}
// If the relationshipType is undefined at this point,
// it can be assumed that this blockType can have a relationship
// to itself. Therefore, we set the relationshipType equal to the blockType
// that is currently being created.
const type = withNullableType(
field,
graphqlResult.collections[relationTo].graphQL.type || newlyCreatedBlockType,
forceNullable,
type = type || newlyCreatedBlockType
const relationshipArgs: {
draft?: unknown
fallbackLocale?: unknown
limit?: unknown
locale?: unknown
page?: unknown
where?: unknown
} = {}
const relationsUseDrafts = (Array.isArray(relationTo) ? relationTo : [relationTo]).some(
(relation) => graphqlResult.collections[relation].config.versions?.drafts,
)
const uploadArgs = {} as LocaleInputType
if (relationsUseDrafts) {
relationshipArgs.draft = {
type: GraphQLBoolean,
}
}
if (config.localization) {
uploadArgs.locale = {
relationshipArgs.locale = {
type: graphqlResult.types.localeInputType,
}
uploadArgs.fallbackLocale = {
relationshipArgs.fallbackLocale = {
type: graphqlResult.types.fallbackLocaleInputType,
}
}
const relatedCollectionSlug = field.relationTo
const upload = {
type,
args: uploadArgs,
extensions: { complexity: 20 },
const relationship = {
type: withNullableType(
field,
hasManyValues ? new GraphQLList(new GraphQLNonNull(type)) : type,
forceNullable,
),
args: relationshipArgs,
extensions: { complexity: 10 },
async resolve(parent, args, context: Context) {
const value = parent[field.name]
const locale = args.locale || context.req.locale
const fallbackLocale = args.fallbackLocale || context.req.fallbackLocale
const id = value
let relatedCollectionSlug = field.relationTo
const draft = Boolean(args.draft ?? context.req.query?.draft)
if (hasManyValues) {
const results = []
const resultPromises = []
const createPopulationPromise = async (relatedDoc, i) => {
let id = relatedDoc
let collectionSlug = field.relationTo
if (isRelatedToManyCollections) {
collectionSlug = relatedDoc.relationTo
id = relatedDoc.value
}
const result = await context.req.payloadDataLoader.load(
createDataloaderCacheKey({
collectionSlug: collectionSlug as string,
currentDepth: 0,
depth: 0,
docID: id,
draft,
fallbackLocale,
locale,
overrideAccess: false,
showHiddenFields: false,
transactionID: context.req.transactionID,
}),
)
if (result) {
if (isRelatedToManyCollections) {
results[i] = {
relationTo: collectionSlug,
value: {
...result,
collection: collectionSlug,
},
}
} else {
results[i] = result
}
}
}
if (value) {
value.forEach((relatedDoc, i) => {
resultPromises.push(createPopulationPromise(relatedDoc, i))
})
}
await Promise.all(resultPromises)
return results
}
let id = value
if (isRelatedToManyCollections && value) {
id = value.value
relatedCollectionSlug = value.relationTo
}
if (id) {
const relatedDocument = await context.req.payloadDataLoader.load(
createDataloaderCacheKey({
collectionSlug: relatedCollectionSlug,
collectionSlug: relatedCollectionSlug as string,
currentDepth: 0,
depth: 0,
docID: id,
@@ -649,26 +764,30 @@ export function buildObjectType({
}),
)
return relatedDocument || null
if (relatedDocument) {
if (isRelatedToManyCollections) {
return {
relationTo: relatedCollectionSlug,
value: {
...relatedDocument,
collection: relatedCollectionSlug,
},
}
}
return relatedDocument
}
return null
}
return null
},
}
const whereFields = graphqlResult.collections[relationTo].config.fields
upload.args.where = {
type: buildWhereInputType({
name: uploadName,
fields: whereFields,
parentName: uploadName,
}),
}
return {
...objectTypeConfig,
[field.name]: upload,
[field.name]: relationship,
}
},
}

View File

@@ -130,9 +130,36 @@ const fieldToSchemaMap = ({ nestedFieldName, parentName }: Args): any => ({
textarea: (field: TextareaField) => ({
type: withOperators(field, parentName),
}),
upload: (field: UploadField) => ({
type: withOperators(field, parentName),
}),
upload: (field: UploadField) => {
if (Array.isArray(field.relationTo)) {
return {
type: new GraphQLInputObjectType({
name: `${combineParentName(parentName, field.name)}_Relation`,
fields: {
relationTo: {
type: new GraphQLEnumType({
name: `${combineParentName(parentName, field.name)}_Relation_RelationTo`,
values: field.relationTo.reduce(
(values, relation) => ({
...values,
[formatName(relation)]: {
value: relation,
},
}),
{},
),
}),
},
value: { type: GraphQLJSON },
},
}),
}
}
return {
type: withOperators(field, parentName),
}
},
})
export default fieldToSchemaMap

View File

@@ -230,9 +230,9 @@ const defaults: DefaultsType = {
},
upload: {
operators: [
...operators.equality.map((operator) => ({
...[...operators.equality, ...operators.contains].map((operator) => ({
name: operator,
type: GraphQLString,
type: GraphQLJSON,
})),
],
},

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/live-preview-react",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "The official React SDK for Payload Live Preview",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/live-preview-vue",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "The official Vue SDK for Payload Live Preview",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/live-preview",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "The official live preview JavaScript SDK for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/next",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -11,21 +11,13 @@
}
}
&__header {
display: flex;
align-items: flex-end;
flex-wrap: wrap;
gap: base(0.8);
h1 {
margin: 0;
}
.list-header {
a {
text-decoration: none;
}
.pill {
.btn--withoutPopup,
.btn--withPopup {
position: relative;
margin: 0 0 base(0.2);
}

View File

@@ -4,15 +4,17 @@ import type { ClientCollectionConfig } from 'payload'
import { getTranslation } from '@payloadcms/translations'
import {
BulkUploadDrawer,
Button,
DeleteMany,
EditMany,
Gutter,
ListControls,
ListHeader,
ListSelection,
Pagination,
PerPage,
Pill,
PopupList,
PublishMany,
RelationshipProvider,
RenderComponent,
@@ -22,10 +24,13 @@ import {
Table,
UnpublishMany,
ViewDescription,
bulkUploadDrawerSlug,
useConfig,
useEditDepth,
useListInfo,
useListQuery,
useModal,
useRouteCache,
useSearchParams,
useStepNav,
useTranslation,
@@ -41,9 +46,20 @@ const baseClass = 'collection-list'
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
export const DefaultListView: React.FC = () => {
const { Header, collectionSlug, hasCreatePermission, newDocumentURL } = useListInfo()
const {
Header,
beforeActions,
collectionSlug,
disableBulkDelete,
disableBulkEdit,
hasCreatePermission,
newDocumentURL,
} = useListInfo()
const { data, defaultLimit, handlePageChange, handlePerPageChange } = useListQuery()
const { searchParams } = useSearchParams()
const { openModal } = useModal()
const { clearRouteCache } = useRouteCache()
const { getEntityConfig } = useConfig()
@@ -67,7 +83,7 @@ export const DefaultListView: React.FC = () => {
labels,
} = collectionConfig
const { i18n } = useTranslation()
const { i18n, t } = useTranslation()
const drawerDepth = useEditDepth()
@@ -79,7 +95,9 @@ export const DefaultListView: React.FC = () => {
let docs = data.docs || []
if (collectionConfig.upload) {
const isUploadCollection = Boolean(collectionConfig.upload)
if (isUploadCollection) {
docs = docs?.map((doc) => {
return {
...doc,
@@ -104,35 +122,47 @@ export const DefaultListView: React.FC = () => {
<RenderComponent mappedComponent={beforeList} />
<SelectionProvider docs={data.docs} totalDocs={data.totalDocs}>
<Gutter className={`${baseClass}__wrap`}>
<header className={`${baseClass}__header`}>
{Header || (
<Fragment>
<h1>{getTranslation(labels?.plural, i18n)}</h1>
{hasCreatePermission && (
<Pill
aria-label={i18n.t('general:createNewLabel', {
label: getTranslation(labels?.singular, i18n),
})}
to={newDocumentURL}
>
{i18n.t('general:createNew')}
</Pill>
)}
{!smallBreak && (
<ListSelection label={getTranslation(collectionConfig.labels.plural, i18n)} />
)}
{description && (
<div className={`${baseClass}__sub-header`}>
<RenderComponent
Component={ViewDescription}
clientProps={{ description }}
mappedComponent={Description}
/>
</div>
)}
</Fragment>
)}
</header>
{Header || (
<ListHeader heading={getTranslation(labels?.plural, i18n)}>
{hasCreatePermission && (
<Button
Link={Link}
SubMenuPopupContent={
isUploadCollection && collectionConfig.upload.bulkUpload ? (
<PopupList.ButtonGroup>
<PopupList.Button onClick={() => openModal(bulkUploadDrawerSlug)}>
{t('upload:bulkUpload')}
</PopupList.Button>
</PopupList.ButtonGroup>
) : null
}
aria-label={i18n.t('general:createNewLabel', {
label: getTranslation(labels?.singular, i18n),
})}
buttonStyle="pill"
el="link"
size="small"
to={newDocumentURL}
>
{i18n.t('general:createNew')}
</Button>
)}
{!smallBreak && (
<ListSelection label={getTranslation(collectionConfig.labels.plural, i18n)} />
)}
{(description || Description) && (
<div className={`${baseClass}__sub-header`}>
<ViewDescription Description={Description} description={description} />
</div>
)}
{isUploadCollection && collectionConfig.upload.bulkUpload ? (
<BulkUploadDrawer
collectionSlug={collectionSlug}
onSuccess={() => clearRouteCache()}
/>
) : null}
</ListHeader>
)}
<ListControls collectionConfig={collectionConfig} fields={fields} />
<RenderComponent mappedComponent={beforeListTable} />
{!data.docs && (
@@ -174,7 +204,7 @@ export const DefaultListView: React.FC = () => {
limit={data.limit}
nextPage={data.nextPage}
numberOfNeighbors={1}
onChange={handlePageChange}
onChange={(page) => void handlePageChange(page)}
page={data.page}
prevPage={data.prevPage}
totalPages={data.totalPages}
@@ -189,7 +219,7 @@ export const DefaultListView: React.FC = () => {
{i18n.t('general:of')} {data.totalDocs}
</div>
<PerPage
handleChange={handlePerPageChange}
handleChange={(limit) => void handlePerPageChange(limit)}
limit={
isNumber(searchParams?.limit) ? Number(searchParams.limit) : defaultLimit
}
@@ -200,10 +230,15 @@ export const DefaultListView: React.FC = () => {
<div className={`${baseClass}__list-selection`}>
<ListSelection label={getTranslation(collectionConfig.labels.plural, i18n)} />
<div className={`${baseClass}__list-selection-actions`}>
<EditMany collection={collectionConfig} fields={fields} />
<PublishMany collection={collectionConfig} />
<UnpublishMany collection={collectionConfig} />
<DeleteMany collection={collectionConfig} />
{beforeActions && beforeActions}
{!disableBulkEdit && (
<Fragment>
<EditMany collection={collectionConfig} fields={fields} />
<PublishMany collection={collectionConfig} />
<UnpublishMany collection={collectionConfig} />
</Fragment>
)}
{!disableBulkDelete && <DeleteMany collection={collectionConfig} />}
</div>
</div>
)}

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env -S node --no-deprecation
#!/usr/bin/env node
import path from 'node:path'
import { fileURLToPath, pathToFileURL } from 'node:url'

View File

@@ -1,6 +1,6 @@
{
"name": "payload",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "Node, React, Headless CMS and Application Framework built on Next.js",
"keywords": [
"admin panel",

View File

@@ -85,6 +85,7 @@ export async function generateImportMap(
if (shouldLog) {
console.log('Generating import map')
}
const importMap: InternalImportMap = {}
const imports: Imports = {}

View File

@@ -33,8 +33,8 @@ export function iterateCollections({
addToImportMap(collection.admin?.components?.afterListTable)
addToImportMap(collection.admin?.components?.beforeList)
addToImportMap(collection.admin?.components?.beforeListTable)
addToImportMap(collection.admin?.components?.Description)
addToImportMap(collection.admin?.components?.edit?.Description)
addToImportMap(collection.admin?.components?.edit?.PreviewButton)
addToImportMap(collection.admin?.components?.edit?.PublishButton)
addToImportMap(collection.admin?.components?.edit?.SaveButton)

View File

@@ -24,7 +24,6 @@ export type ClientCollectionConfig = {
beforeList: MappedComponent[]
beforeListTable: MappedComponent[]
edit: {
Description: MappedComponent
PreviewButton: MappedComponent
PublishButton: MappedComponent
SaveButton: MappedComponent

View File

@@ -120,6 +120,7 @@ export const sanitizeCollection = async (
// disable duplicate for uploads by default
sanitized.disableDuplicate = sanitized.disableDuplicate || true
sanitized.upload.bulkUpload = sanitized.upload?.bulkUpload ?? true
sanitized.upload.staticDir = sanitized.upload.staticDir || sanitized.slug
sanitized.admin.useAsTitle =
sanitized.admin.useAsTitle && sanitized.admin.useAsTitle !== 'id'

View File

@@ -250,6 +250,7 @@ export type CollectionAdminOptions = {
* Custom admin components
*/
components?: {
Description?: EntityDescriptionComponent
afterList?: CustomComponent[]
afterListTable?: CustomComponent[]
beforeList?: CustomComponent[]
@@ -258,8 +259,6 @@ export type CollectionAdminOptions = {
* Components within the edit view
*/
edit?: {
Description?: EntityDescriptionComponent
/**
* Replaces the "Preview" button
*/

View File

@@ -105,7 +105,10 @@ export async function validateSearchParam({
fieldPath = path.slice(0, -(req.locale.length + 1))
}
// remove ".value" from ends of polymorphic relationship paths
if (field.type === 'relationship' && Array.isArray(field.relationTo)) {
if (
(field.type === 'relationship' || field.type === 'upload') &&
Array.isArray(field.relationTo)
) {
fieldPath = fieldPath.replace('.value', '')
}
const entityType: 'collections' | 'globals' = globalConfig ? 'globals' : 'collections'

View File

@@ -21,7 +21,12 @@ export class ValidationError extends APIError<{
global?: string
}> {
constructor(
results: { collection?: string; errors: ValidationFieldError[]; global?: string },
results: {
collection?: string
errors: ValidationFieldError[]
global?: string
id?: number | string
},
t?: TFunction,
) {
const message = t

View File

@@ -99,19 +99,26 @@ export const sanitizeFields = async ({
})
}
if (field.type === 'relationship') {
if (field.min && !field.minRows) {
console.warn(
`(payload): The "min" property is deprecated for the Relationship field "${field.name}" and will be removed in a future version. Please use "minRows" instead.`,
)
if (field.min && !field.minRows) {
console.warn(
`(payload): The "min" property is deprecated for the Relationship field "${field.name}" and will be removed in a future version. Please use "minRows" instead.`,
)
}
if (field.max && !field.maxRows) {
console.warn(
`(payload): The "max" property is deprecated for the Relationship field "${field.name}" and will be removed in a future version. Please use "maxRows" instead.`,
)
}
field.minRows = field.minRows || field.min
field.maxRows = field.maxRows || field.max
}
if (field.type === 'upload') {
if (!field.admin || !('isSortable' in field.admin)) {
field.admin = {
isSortable: true,
...field.admin,
}
if (field.max && !field.maxRows) {
console.warn(
`(payload): The "max" property is deprecated for the Relationship field "${field.name}" and will be removed in a future version. Please use "maxRows" instead.`,
)
}
field.minRows = field.minRows || field.min
field.maxRows = field.maxRows || field.max
}
}

View File

@@ -824,35 +824,106 @@ export type UIFieldClient = {
} & Omit<DeepUndefinable<FieldBaseClient>, '_isPresentational' | 'admin'> & // still include FieldBaseClient (even if it's undefinable) so that we don't need constant type checks (e.g. if('xy' in field))
Pick<UIField, 'label' | 'name' | 'type'>
export type UploadField = {
admin?: {
components?: {
Error?: CustomComponent<UploadFieldErrorClientComponent | UploadFieldErrorServerComponent>
Label?: CustomComponent<UploadFieldLabelClientComponent | UploadFieldLabelServerComponent>
} & Admin['components']
}
type SharedUploadProperties = {
/**
* Toggle the preview in the admin interface.
*/
displayPreview?: boolean
filterOptions?: FilterOptions
hasMany?: boolean
/**
* Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached.
*
* {@link https://payloadcms.com/docs/getting-started/concepts#field-level-max-depth}
*/
maxDepth?: number
relationTo: CollectionSlug
type: 'upload'
validate?: Validate<unknown, unknown, unknown, UploadField>
} & FieldBase
validate?: Validate<unknown, unknown, unknown, SharedUploadProperties>
} & (
| {
hasMany: true
/**
* @deprecated Use 'maxRows' instead
*/
max?: number
maxRows?: number
/**
* @deprecated Use 'minRows' instead
*/
min?: number
minRows?: number
}
| {
hasMany?: false | undefined
/**
* @deprecated Use 'maxRows' instead
*/
max?: undefined
maxRows?: undefined
/**
* @deprecated Use 'minRows' instead
*/
min?: undefined
minRows?: undefined
}
) &
FieldBase
export type UploadFieldClient = {
type SharedUploadPropertiesClient = FieldBaseClient &
Pick<
SharedUploadProperties,
'hasMany' | 'max' | 'maxDepth' | 'maxRows' | 'min' | 'minRows' | 'type'
>
type UploadAdmin = {
allowCreate?: boolean
components?: {
Error?: CustomComponent<
RelationshipFieldErrorClientComponent | RelationshipFieldErrorServerComponent
>
Label?: CustomComponent<
RelationshipFieldLabelClientComponent | RelationshipFieldLabelServerComponent
>
} & Admin['components']
isSortable?: boolean
} & Admin
type UploadAdminClient = {
components?: {
Error?: MappedComponent
Label?: MappedComponent
} & AdminClient['components']
} & AdminClient &
Pick<UploadAdmin, 'allowCreate' | 'isSortable'>
export type PolymorphicUploadField = {
admin?: {
components?: {
Error?: MappedComponent
Label?: MappedComponent
} & AdminClient['components']
}
} & FieldBaseClient &
Pick<UploadField, 'displayPreview' | 'maxDepth' | 'relationTo' | 'type'>
sortOptions?: { [collectionSlug: CollectionSlug]: string }
} & UploadAdmin
relationTo: CollectionSlug[]
} & SharedUploadProperties
export type PolymorphicUploadFieldClient = {
admin?: {
sortOptions?: Pick<PolymorphicUploadField['admin'], 'sortOptions'>
} & UploadAdminClient
} & Pick<PolymorphicUploadField, 'displayPreview' | 'maxDepth' | 'relationTo' | 'type'> &
SharedUploadPropertiesClient
export type SingleUploadField = {
admin?: {
sortOptions?: string
} & UploadAdmin
relationTo: CollectionSlug
} & SharedUploadProperties
export type SingleUploadFieldClient = {
admin?: Pick<SingleUploadField['admin'], 'sortOptions'> & UploadAdminClient
} & Pick<SingleUploadField, 'displayPreview' | 'maxDepth' | 'relationTo' | 'type'> &
SharedUploadPropertiesClient
export type UploadField = /* PolymorphicUploadField | */ SingleUploadField
export type UploadFieldClient = /* PolymorphicUploadFieldClient | */ SingleUploadFieldClient
export type CodeField = {
admin?: {

View File

@@ -71,6 +71,7 @@ export const beforeChange = async <T extends JsonObject>({
if (errors.length > 0) {
throw new ValidationError(
{
id,
collection: collection?.slug,
errors,
global: global?.slug,

View File

@@ -138,7 +138,7 @@ export const promise = async <T>({
siblingData[field.name] === 'null' ||
siblingData[field.name] === null
) {
if (field.type === 'relationship' && field.hasMany === true) {
if (field.hasMany === true) {
siblingData[field.name] = []
} else {
siblingData[field.name] = null
@@ -153,32 +153,32 @@ export const promise = async <T>({
const relatedCollection = req.payload.config.collections.find(
(collection) => collection.slug === relatedDoc.relationTo,
)
if (relatedCollection?.fields) {
const relationshipIDField = relatedCollection.fields.find(
(collectionField) =>
fieldAffectsData(collectionField) && collectionField.name === 'id',
)
if (relationshipIDField?.type === 'number') {
siblingData[field.name][i] = {
...relatedDoc,
value: parseFloat(relatedDoc.value as string),
}
}
}
})
}
if (field.hasMany !== true && valueIsValueWithRelation(value)) {
const relatedCollection = req.payload.config.collections.find(
(collection) => collection.slug === value.relationTo,
)
if (relatedCollection?.fields) {
const relationshipIDField = relatedCollection.fields.find(
(collectionField) =>
fieldAffectsData(collectionField) && collectionField.name === 'id',
)
if (relationshipIDField?.type === 'number') {
siblingData[field.name][i] = {
...relatedDoc,
value: parseFloat(relatedDoc.value as string),
}
siblingData[field.name] = { ...value, value: parseFloat(value.value as string) }
}
})
}
if (
field.type === 'relationship' &&
field.hasMany !== true &&
valueIsValueWithRelation(value)
) {
const relatedCollection = req.payload.config.collections.find(
(collection) => collection.slug === value.relationTo,
)
const relationshipIDField = relatedCollection.fields.find(
(collectionField) =>
fieldAffectsData(collectionField) && collectionField.name === 'id',
)
if (relationshipIDField?.type === 'number') {
siblingData[field.name] = { ...value, value: parseFloat(value.value as string) }
}
}
} else {
@@ -187,25 +187,31 @@ export const promise = async <T>({
const relatedCollection = req.payload.config.collections.find(
(collection) => collection.slug === field.relationTo,
)
if (relatedCollection?.fields) {
const relationshipIDField = relatedCollection.fields.find(
(collectionField) =>
fieldAffectsData(collectionField) && collectionField.name === 'id',
)
if (relationshipIDField?.type === 'number') {
siblingData[field.name][i] = parseFloat(relatedDoc as string)
}
}
})
}
if (field.hasMany !== true && value) {
const relatedCollection = req.payload.config.collections.find(
(collection) => collection.slug === field.relationTo,
)
if (relatedCollection?.fields) {
const relationshipIDField = relatedCollection.fields.find(
(collectionField) =>
fieldAffectsData(collectionField) && collectionField.name === 'id',
)
if (relationshipIDField?.type === 'number') {
siblingData[field.name][i] = parseFloat(relatedDoc as string)
siblingData[field.name] = parseFloat(value as string)
}
})
}
if (field.type === 'relationship' && field.hasMany !== true && value) {
const relatedCollection = req.payload.config.collections.find(
(collection) => collection.slug === field.relationTo,
)
const relationshipIDField = relatedCollection.fields.find(
(collectionField) =>
fieldAffectsData(collectionField) && collectionField.name === 'id',
)
if (relationshipIDField?.type === 'number') {
siblingData[field.name] = parseFloat(value as string)
}
}
}

View File

@@ -571,18 +571,76 @@ const validateFilterOptions: Validate<
}
export type UploadFieldValidation = Validate<unknown, unknown, unknown, UploadField>
export const upload: UploadFieldValidation = (value: string, options) => {
if (!value && options.required) {
return options?.req?.t('validation:required')
export const upload: UploadFieldValidation = async (value, options) => {
const {
maxRows,
minRows,
relationTo,
req: { payload, t },
required,
} = options
if (
((!value && typeof value !== 'number') || (Array.isArray(value) && value.length === 0)) &&
required
) {
return t('validation:required')
}
if (Array.isArray(value) && value.length > 0) {
if (minRows && value.length < minRows) {
return t('validation:lessThanMin', {
label: t('general:rows'),
min: minRows,
value: value.length,
})
}
if (maxRows && value.length > maxRows) {
return t('validation:greaterThanMax', {
label: t('general:rows'),
max: maxRows,
value: value.length,
})
}
}
if (typeof value !== 'undefined' && value !== null) {
const idType =
options?.req?.payload?.collections[options.relationTo]?.customIDType ||
options?.req?.payload?.db?.defaultIDType
const values = Array.isArray(value) ? value : [value]
if (!isValidID(value, idType)) {
return options.req?.t('validation:validUploadID')
const invalidRelationships = values.filter((val) => {
let collectionSlug: string
let requestedID
if (typeof relationTo === 'string') {
collectionSlug = relationTo
// custom id
if (val || typeof val === 'number') {
requestedID = val
}
}
if (Array.isArray(relationTo) && typeof val === 'object' && val?.relationTo) {
collectionSlug = val.relationTo
requestedID = val.value
}
if (requestedID === null) return false
const idType =
payload.collections[collectionSlug]?.customIDType || payload?.db?.defaultIDType || 'text'
return !isValidID(requestedID, idType)
})
if (invalidRelationships.length > 0) {
return `This relationship field has the following invalid relationships: ${invalidRelationships
.map((err, invalid) => {
return `${err} ${JSON.stringify(invalid)}`
})
.join(', ')}`
}
}

View File

@@ -95,6 +95,11 @@ export type UploadConfig = {
* - A function that generates a fully qualified URL for the thumbnail, receives the doc as the only argument.
**/
adminThumbnail?: GetAdminThumbnail | string
/**
* Enables bulk upload of files from the list view.
* @default true
*/
bulkUpload?: boolean
/**
* Enables cropping of images.
* @default true

View File

@@ -291,6 +291,7 @@ export function fieldsToJSONSchema(
break
}
case 'upload':
case 'relationship': {
if (Array.isArray(field.relationTo)) {
if (field.hasMany) {
@@ -380,21 +381,6 @@ export function fieldsToJSONSchema(
break
}
case 'upload': {
fieldSchema = {
oneOf: [
{
type: collectionIDFieldTypes[field.relationTo],
},
{
$ref: `#/definitions/${field.relationTo}`,
},
],
}
if (!isRequired) fieldSchema.oneOf.push({ type: 'null' })
break
}
case 'blocks': {
// Check for a case where no blocks are provided.
// We need to generate an empty array for this case, note that JSON schema 4 doesn't support empty arrays

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-cloud-storage",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "The official cloud storage plugin for Payload CMS",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-cloud",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "The official Payload Cloud plugin",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-form-builder",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "Form builder plugin for Payload CMS",
"keywords": [
"payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-nested-docs",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "The official Nested Docs plugin for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-redirects",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "Redirects plugin for Payload",
"keywords": [
"payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-relationship-object-ids",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "A Payload plugin to store all relationship IDs as ObjectIDs",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-search",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "Search plugin for Payload",
"keywords": [
"payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-seo",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "SEO plugin for Payload",
"keywords": [
"payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-stripe",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "Stripe plugin for Payload",
"keywords": [
"payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-lexical",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "The officially supported Lexical richtext adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -98,7 +98,12 @@
width: 100%;
overflow: hidden;
gap: calc(var(--base) * 0.375);
justify-content: space-between;
justify-content: flex-start;
pointer-events: none;
& > * {
pointer-events: all;
}
}
&__block-number {

View File

@@ -47,7 +47,7 @@ export function convertLexicalPluginNodesToLexical({
parentNodeType: string
quiet?: boolean
}): SerializedLexicalNode[] {
if (!lexicalPluginNodes?.length) {
if (!lexicalPluginNodes?.length || !converters?.length) {
return []
}
const unknownConverter = converters.find((converter) => converter.nodeTypes.includes('unknown'))

View File

@@ -13,6 +13,7 @@ export type LexicalPluginToLexicalFeatureProps = {
defaultConverters: LexicalPluginNodeConverter[]
}) => LexicalPluginNodeConverter[])
| LexicalPluginNodeConverter[]
disableHooks?: boolean
quiet?: boolean
}
@@ -37,23 +38,25 @@ export const LexicalPluginToLexicalFeature =
return {
ClientFeature: '@payloadcms/richtext-lexical/client#LexicalPluginToLexicalFeatureClient',
hooks: {
afterRead: [
({ value }) => {
if (!value || !('jsonContent' in value)) {
// incomingEditorState null or not from Lexical Plugin
return value
}
hooks: props.disableHooks
? undefined
: {
afterRead: [
({ value }) => {
if (!value || !('jsonContent' in value)) {
// incomingEditorState null or not from Lexical Plugin
return value
}
// Lexical Plugin => convert to lexical
return convertLexicalPluginToLexical({
converters: props.converters as LexicalPluginNodeConverter[],
lexicalPluginData: value as PayloadPluginLexicalData,
quiet: props?.quiet,
})
// Lexical Plugin => convert to lexical
return convertLexicalPluginToLexical({
converters: props.converters as LexicalPluginNodeConverter[],
lexicalPluginData: value as PayloadPluginLexicalData,
quiet: props?.quiet,
})
},
],
},
],
},
nodes: [
{
node: UnknownConvertedNode,

View File

@@ -47,7 +47,7 @@ export function convertSlateNodesToLexical({
parentNodeType: string
slateNodes: SlateNode[]
}): SerializedLexicalNode[] {
if (!converters?.length) {
if (!converters?.length || !slateNodes?.length) {
return []
}
const unknownConverter = converters.find((converter) => converter.nodeTypes.includes('unknown'))

View File

@@ -9,6 +9,7 @@ export type SlateToLexicalFeatureProps = {
converters?:
| (({ defaultConverters }: { defaultConverters: SlateNodeConverter[] }) => SlateNodeConverter[])
| SlateNodeConverter[]
disableHooks?: boolean
}
export const SlateToLexicalFeature = createServerFeature<
@@ -35,22 +36,24 @@ export const SlateToLexicalFeature = createServerFeature<
return {
ClientFeature: '@payloadcms/richtext-lexical/client#SlateToLexicalFeatureClient',
hooks: {
afterRead: [
({ value }) => {
if (!value || !Array.isArray(value) || 'root' in value) {
// incomingEditorState null or not from Slate
return value
}
hooks: props.disableHooks
? undefined
: {
afterRead: [
({ value }) => {
if (!value || !Array.isArray(value) || 'root' in value) {
// incomingEditorState null or not from Slate
return value
}
// Slate => convert to lexical
return convertSlateToLexical({
converters: props.converters as SlateNodeConverter[],
slateData: value,
})
// Slate => convert to lexical
return convertSlateToLexical({
converters: props.converters as SlateNodeConverter[],
slateData: value,
})
},
],
},
],
},
nodes: [
{
node: UnknownConvertedNode,

View File

@@ -64,12 +64,20 @@ async function migrateGlobal({
})
if (found) {
await payload.updateGlobal({
slug: global.slug,
data: document,
depth: 0,
locale: locale || undefined,
})
try {
await payload.updateGlobal({
slug: global.slug,
data: document,
depth: 0,
locale: locale || undefined,
})
// Catch it, because some errors were caused by the user previously (e.g. invalid relationships) and will throw an error now, even though they are not related to the migration
} catch (e) {
console.log('Error updating global', e, {
id: document.id,
slug: global.slug,
})
}
}
}
@@ -136,13 +144,21 @@ async function migrateCollection({
})
if (found) {
await payload.update({
id: document.id,
collection: collection.slug,
data: document,
depth: 0,
locale: locale || undefined,
})
try {
await payload.update({
id: document.id,
collection: collection.slug,
data: document,
depth: 0,
locale: locale || undefined,
})
// Catch it, because some errors were caused by the user previously (e.g. invalid relationships) and will throw an error now, even though they are not related to the migration
} catch (e) {
console.log('Error updating collection', e, {
id: document.id,
slug: collection.slug,
})
}
}
}
page++

View File

@@ -20,15 +20,24 @@ export const richTextValidateHOC = ({
} = options
if (required) {
const hasChildren = value?.root?.children?.length
const hasChildren = !!value?.root?.children?.length
const hasOnlyEmptyParagraph =
(value?.root?.children?.length === 1 &&
value?.root?.children[0]?.type === 'paragraph' &&
(value?.root?.children[0] as SerializedParagraphNode)?.children?.length === 0) ||
((value?.root?.children[0] as SerializedParagraphNode)?.children?.length === 1 &&
(value?.root?.children[0] as SerializedParagraphNode)?.children[0]?.type === 'text' &&
(value?.root?.children[0] as SerializedParagraphNode)?.children[0]?.['text'] === '')
let hasOnlyEmptyParagraph = false
if (value?.root?.children?.length === 1) {
if (value?.root?.children[0]?.type === 'paragraph') {
const paragraphNode = value?.root?.children[0] as SerializedParagraphNode
if (paragraphNode?.children?.length === 0) {
hasOnlyEmptyParagraph = true
} else if (paragraphNode?.children?.length === 1) {
const paragraphNodeChild = paragraphNode?.children[0]
if (paragraphNodeChild.type === 'text') {
if (!paragraphNodeChild?.['text']?.length) {
hasOnlyEmptyParagraph = true
}
}
}
}
}
if (!hasChildren || hasOnlyEmptyParagraph) {
return t('validation:required')

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-slate",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "The officially supported Slate richtext adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/storage-azure",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "Payload storage adapter for Azure Blob Storage",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/storage-gcs",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "Payload storage adapter for Google Cloud Storage",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/storage-s3",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "Payload storage adapter for Amazon S3",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/storage-uploadthing",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "Payload storage adapter for uploadthing",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/storage-vercel-blob",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"description": "Payload storage adapter for Vercel Blob Storage",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/translations",
"version": "3.0.0-beta.88",
"version": "3.0.0-beta.89",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -188,6 +188,7 @@ export const clientTranslationKeys = createClientTranslationKeys([
'general:menu',
'general:moveDown',
'general:moveUp',
'general:next',
'general:noFiltersSet',
'general:noLabel',
'general:none',
@@ -204,6 +205,7 @@ export const clientTranslationKeys = createClientTranslationKeys([
'general:password',
'general:payloadSettings',
'general:perPage',
'general:previous',
'general:remove',
'general:reset',
'general:row',
@@ -239,6 +241,7 @@ export const clientTranslationKeys = createClientTranslationKeys([
'general:updatedCountSuccessfully',
'general:updatedSuccessfully',
'general:updating',
'general:uploading',
'general:welcome',
'operators:equals',
@@ -256,11 +259,15 @@ export const clientTranslationKeys = createClientTranslationKeys([
'operators:within',
'operators:intersects',
'upload:addFile',
'upload:addFiles',
'upload:bulkUpload',
'upload:crop',
'upload:cropToolDescription',
'upload:dragAndDrop',
'upload:addFile',
'upload:editImage',
'upload:fileToUpload',
'upload:filesToUpload',
'upload:focalPoint',
'upload:focalPointDescription',
'upload:height',

View File

@@ -244,6 +244,7 @@ export const arTranslations: DefaultTranslationsObject = {
moveDown: 'التّحريك إلى الأسفل',
moveUp: 'التّحريك إلى الأعلى',
newPassword: 'كلمة مرور جديدة',
next: 'التالي',
noFiltersSet: 'لم يتم تعيين أي عوامل تصفية',
noLabel: '<لا {{label}}>',
noOptions: 'لا خيارات',
@@ -261,6 +262,7 @@ export const arTranslations: DefaultTranslationsObject = {
password: 'كلمة المرور',
payloadSettings: 'الإعدادات',
perPage: 'لكلّ صفحة: {{limit}}',
previous: 'سابق',
remove: 'إزالة',
reset: 'إعادة تعيين',
row: 'سطر',
@@ -318,6 +320,8 @@ export const arTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'إضافة ملف',
addFiles: 'أضف ملفات',
bulkUpload: 'تحميل بالجملة',
crop: 'محصول',
cropToolDescription: 'اسحب الزوايا المحددة للمنطقة، رسم منطقة جديدة أو قم بضبط القيم أدناه.',
dragAndDrop: 'قم بسحب وإسقاط ملفّ',
@@ -325,6 +329,8 @@ export const arTranslations: DefaultTranslationsObject = {
editImage: 'تعديل الصورة',
fileName: 'اسم الملفّ',
fileSize: 'حجم الملفّ',
fileToUpload: 'ملف للتحميل',
filesToUpload: 'ملفات للتحميل',
focalPoint: 'نقطة التركيز',
focalPointDescription: 'اسحب النقطة المركزية مباشرة على المعاينة أو قم بضبط القيم أدناه.',
height: 'الطّول',

View File

@@ -246,6 +246,7 @@ export const azTranslations: DefaultTranslationsObject = {
moveDown: 'Aşağı hərəkət et',
moveUp: 'Yuxarı hərəkət et',
newPassword: 'Yeni şifrə',
next: 'Növbəti',
noFiltersSet: 'Filter təyin edilməyib',
noLabel: '<Heç bir {{label}}>',
noOptions: 'Heç bir seçim yoxdur',
@@ -263,6 +264,7 @@ export const azTranslations: DefaultTranslationsObject = {
password: 'Şifrə',
payloadSettings: 'Payload Parametrləri',
perPage: 'Hər səhifədə: {{limit}}',
previous: 'Əvvəlki',
remove: 'Sil',
reset: 'Yenidən başlat',
row: 'Sətir',
@@ -321,6 +323,8 @@ export const azTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Fayl əlavə et',
addFiles: 'Faylları Əlavə Edin',
bulkUpload: 'Kütləvi Yükləmə',
crop: 'Məhsul',
cropToolDescription:
'Seçilmiş sahənin köşələrini sürükləyin, yeni bir sahə çəkin və ya aşağıdakı dəyərləri düzəltin.',
@@ -329,6 +333,8 @@ export const azTranslations: DefaultTranslationsObject = {
editImage: 'Şəkili Redaktə Et',
fileName: 'Faylın Adı',
fileSize: 'Faylım Ölçüsü',
fileToUpload: 'Yükləmək üçün Fayl',
filesToUpload: 'Yükləmək üçün fayllar',
focalPoint: 'Mərkəzi Nöqtə',
focalPointDescription:
'Fokus nöqtəsini birbaşa önizləməyə sürükləyin və ya aşağıdakı dəyərləri düzəltin.',

View File

@@ -245,6 +245,7 @@ export const bgTranslations: DefaultTranslationsObject = {
moveDown: 'Надолу',
moveUp: 'Нагоре',
newPassword: 'Нова парола',
next: 'Следващ',
noFiltersSet: 'Няма зададени филтри',
noLabel: '<Няма {{label}}>',
noOptions: 'Няма опции',
@@ -262,6 +263,7 @@ export const bgTranslations: DefaultTranslationsObject = {
password: 'Парола',
payloadSettings: 'Настройки на Payload',
perPage: 'На страница: {{limit}}',
previous: 'Предишен',
remove: 'Премахни',
reset: 'Нулиране',
row: 'ред',
@@ -319,6 +321,8 @@ export const bgTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Добавяне на файл',
addFiles: 'Добави файлове',
bulkUpload: 'Масово Качване',
crop: 'Изрязване',
cropToolDescription:
'Плъзни ъглите на избраната област, избери нова област или коригирай стойностите по-долу.',
@@ -327,6 +331,8 @@ export const bgTranslations: DefaultTranslationsObject = {
editImage: 'Редактирай изображение',
fileName: 'Име на файла',
fileSize: 'Големина на файла',
fileToUpload: 'Файл за качване',
filesToUpload: 'Файлове за качване',
focalPoint: 'Фокусна точка',
focalPointDescription:
'Премести фокусната точка директно върху визуализацията или регулирай стойностите по-долу.',

View File

@@ -245,6 +245,7 @@ export const csTranslations: DefaultTranslationsObject = {
moveDown: 'Posunout dolů',
moveUp: 'Posunout nahoru',
newPassword: 'Nové heslo',
next: 'Další',
noFiltersSet: 'Nenastaveny žádné filtry',
noLabel: '<Žádný {{label}}>',
noOptions: 'Žádné možnosti',
@@ -262,6 +263,7 @@ export const csTranslations: DefaultTranslationsObject = {
password: 'Heslo',
payloadSettings: 'Payload nastavení',
perPage: 'Na stránku: {{limit}}',
previous: 'Předchozí',
remove: 'Odstranit',
reset: 'Resetovat',
row: 'Řádek',
@@ -319,6 +321,8 @@ export const csTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Přidat soubor',
addFiles: 'Přidat soubory',
bulkUpload: 'Hromadné nahrání',
crop: 'Ořez',
cropToolDescription:
'Přetáhněte rohy vybrané oblasti, nakreslete novou oblast nebo upravte níže uvedené hodnoty.',
@@ -327,6 +331,8 @@ export const csTranslations: DefaultTranslationsObject = {
editImage: 'Upravit obrázek',
fileName: 'Název souboru',
fileSize: 'Velikost souboru',
fileToUpload: 'Soubor k nahrání',
filesToUpload: 'Soubory k nahrání',
focalPoint: 'Středobod',
focalPointDescription:
'Přetáhněte bod zaměření přímo na náhled nebo upravte níže uvedené hodnoty.',

View File

@@ -250,6 +250,7 @@ export const deTranslations: DefaultTranslationsObject = {
moveDown: 'Nach unten bewegen',
moveUp: 'Nach oben bewegen',
newPassword: 'Neues Passwort',
next: 'Nächste',
noFiltersSet: 'Keine Filter gesetzt',
noLabel: '<Kein {{label}}>',
noOptions: 'Keine Optionen',
@@ -267,6 +268,7 @@ export const deTranslations: DefaultTranslationsObject = {
password: 'Passwort',
payloadSettings: 'Payload Einstellungen',
perPage: 'Pro Seite: {{limit}}',
previous: 'Vorherige',
remove: 'Entfernen',
reset: 'Zurücksetzen',
row: 'Zeile',
@@ -325,6 +327,8 @@ export const deTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Datei hinzufügen',
addFiles: 'Dateien hinzufügen',
bulkUpload: 'Massenupload',
crop: 'Zuschneiden',
cropToolDescription:
'Ziehen Sie die Ecken des ausgewählten Bereichs, zeichnen Sie einen neuen Bereich oder passen Sie die Werte unten an.',
@@ -333,6 +337,8 @@ export const deTranslations: DefaultTranslationsObject = {
editImage: 'Bild bearbeiten',
fileName: 'Dateiname',
fileSize: 'Dateigröße',
fileToUpload: 'Datei zum Hochladen',
filesToUpload: 'Dateien zum Hochladen',
focalPoint: 'Brennpunkt',
focalPointDescription:
'Ziehen Sie den Fokuspunkt direkt auf die Vorschau oder passen Sie die Werte unten an.',

View File

@@ -248,6 +248,7 @@ export const enTranslations = {
moveDown: 'Move Down',
moveUp: 'Move Up',
newPassword: 'New Password',
next: 'Next',
noFiltersSet: 'No filters set',
noLabel: '<No {{label}}>',
noOptions: 'No options',
@@ -265,6 +266,7 @@ export const enTranslations = {
password: 'Password',
payloadSettings: 'Payload Settings',
perPage: 'Per Page: {{limit}}',
previous: 'Previous',
remove: 'Remove',
reset: 'Reset',
row: 'Row',
@@ -322,6 +324,8 @@ export const enTranslations = {
},
upload: {
addFile: 'Add File',
addFiles: 'Add Files',
bulkUpload: 'Bulk Upload',
crop: 'Crop',
cropToolDescription:
'Drag the corners of the selected area, draw a new area or adjust the values below.',
@@ -330,6 +334,8 @@ export const enTranslations = {
editImage: 'Edit Image',
fileName: 'File Name',
fileSize: 'File Size',
fileToUpload: 'File to Upload',
filesToUpload: 'Files to Upload',
focalPoint: 'Focal Point',
focalPointDescription:
'Drag the focal point directly on the preview or adjust the values below.',

View File

@@ -250,6 +250,7 @@ export const esTranslations: DefaultTranslationsObject = {
moveDown: 'Mover abajo',
moveUp: 'Mover arriba',
newPassword: 'Nueva contraseña',
next: 'Siguiente',
noFiltersSet: 'No hay filtros establecidos',
noLabel: '<Sin {{label}}>',
noOptions: 'Sin opciones',
@@ -267,6 +268,7 @@ export const esTranslations: DefaultTranslationsObject = {
password: 'Contraseña',
payloadSettings: 'Configuración de la carga',
perPage: 'Por página: {{limit}}',
previous: 'Anterior',
remove: 'Remover',
reset: 'Reiniciar',
row: 'Fila',
@@ -324,6 +326,8 @@ export const esTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Añadir archivo',
addFiles: 'Añadir archivos',
bulkUpload: 'Subida en Masa',
crop: 'Cultivo',
cropToolDescription:
'Arrastra las esquinas del área seleccionada, dibuja un nuevo área o ajusta los valores a continuación.',
@@ -332,6 +336,8 @@ export const esTranslations: DefaultTranslationsObject = {
editImage: 'Editar imagen',
fileName: 'Nombre del archivo',
fileSize: 'Tamaño del archivo',
fileToUpload: 'Archivo para subir',
filesToUpload: 'Archivos para subir',
focalPoint: 'Punto Focal',
focalPointDescription:
'Arrastra el punto focal directamente en la vista previa o ajusta los valores a continuación.',

View File

@@ -245,6 +245,7 @@ export const faTranslations: DefaultTranslationsObject = {
moveDown: 'حرکت به پایین',
moveUp: 'حرکت به بالا',
newPassword: 'گذرواژه تازه',
next: 'بعدی',
noFiltersSet: 'هیچ علامت‌گذاری تنظیم نشده',
noLabel: '<No {{label}}>',
noOptions: 'بدون گزینه',
@@ -262,6 +263,7 @@ export const faTranslations: DefaultTranslationsObject = {
password: 'گذرواژه',
payloadSettings: 'تنظیمات پی‌لود',
perPage: 'هر برگه: {{limit}}',
previous: 'قبلی',
remove: 'برداشتن',
reset: 'بازنشانی',
row: 'ردیف',
@@ -319,6 +321,8 @@ export const faTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'اضافه کردن فایل',
addFiles: 'اضافه کردن فایل‌ها',
bulkUpload: 'بارگذاری انبوه',
crop: 'محصول',
cropToolDescription:
'گوشه‌های منطقه انتخاب شده را بکشید، یک منطقه جدید رسم کنید یا مقادیر زیر را تنظیم کنید.',
@@ -327,6 +331,8 @@ export const faTranslations: DefaultTranslationsObject = {
editImage: 'ویرایش تصویر',
fileName: 'نام رسانه',
fileSize: 'حجم رسانه',
fileToUpload: 'فایل برای بارگذاری',
filesToUpload: 'فایل ها برای بارگذاری',
focalPoint: 'نقطه متمرکز',
focalPointDescription:
'نقطه کانونی را مستقیماً روی پیش نمایش بکشید یا مقادیر زیر را تنظیم کنید.',

View File

@@ -253,6 +253,7 @@ export const frTranslations: DefaultTranslationsObject = {
moveDown: 'Déplacer vers le bas',
moveUp: 'Déplacer vers le haut',
newPassword: 'Nouveau mot de passe',
next: 'Prochain',
noFiltersSet: 'Aucun filtre défini',
noLabel: '<Pas de {{label}}>',
noOptions: 'Aucune option',
@@ -270,6 +271,7 @@ export const frTranslations: DefaultTranslationsObject = {
password: 'Mot de passe',
payloadSettings: 'Paramètres de Payload',
perPage: 'Par Page: {{limit}}',
previous: 'Précédent',
remove: 'Retirer',
reset: 'Réinitialiser',
row: 'Ligne',
@@ -328,6 +330,8 @@ export const frTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Ajouter un fichier',
addFiles: 'Ajouter des fichiers',
bulkUpload: 'Téléchargement en masse',
crop: 'Recadrer',
cropToolDescription:
'Faites glisser les coins de la zone sélectionnée, dessinez une nouvelle zone ou ajustez les valeurs ci-dessous.',
@@ -336,6 +340,8 @@ export const frTranslations: DefaultTranslationsObject = {
editImage: 'Modifier limage',
fileName: 'Nom du fichier',
fileSize: 'Taille du fichier',
fileToUpload: 'Fichier à télécharger',
filesToUpload: 'Fichiers à télécharger',
focalPoint: 'Point focal',
focalPointDescription:
'Faites glisser le point focal directement sur laperçu ou ajustez les valeurs ci-dessous.',

View File

@@ -241,6 +241,7 @@ export const heTranslations: DefaultTranslationsObject = {
moveDown: 'הזז למטה',
moveUp: 'הזז למעלה',
newPassword: 'סיסמה חדשה',
next: 'הבא',
noFiltersSet: 'לא הוגדרו מסננים',
noLabel: '<ללא {{label}}>',
noOptions: 'אין אפשרויות',
@@ -257,6 +258,7 @@ export const heTranslations: DefaultTranslationsObject = {
password: 'סיסמה',
payloadSettings: 'הגדרות מערכת Payload',
perPage: '{{limit}} בכל עמוד',
previous: 'קודם',
remove: 'הסר',
reset: 'איפוס',
row: 'שורה',
@@ -314,6 +316,8 @@ export const heTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'הוסף קובץ',
addFiles: 'הוסף קבצים',
bulkUpload: 'העלאה בתפוצה רחבה',
crop: 'חתוך',
cropToolDescription: 'גרור את הפינות של האזור שנבחר, צייר אזור חדש או התאם את הערכים למטה.',
dragAndDrop: 'גרור ושחרר קובץ',
@@ -321,6 +325,8 @@ export const heTranslations: DefaultTranslationsObject = {
editImage: 'ערוך תמונה',
fileName: 'שם קובץ',
fileSize: 'גודל קובץ',
fileToUpload: 'קובץ להעלאה',
filesToUpload: 'קבצים להעלאה',
focalPoint: 'נקודת מיקוד',
focalPointDescription: 'גרור את נקודת המיקוד ישירות על התצוגה המקדימה או התאם את הערכים למטה.',
height: 'גובה',

View File

@@ -246,6 +246,7 @@ export const hrTranslations: DefaultTranslationsObject = {
moveDown: 'Pomakni dolje',
moveUp: 'Pomakni gore',
newPassword: 'Nova lozinka',
next: 'Sljedeće',
noFiltersSet: 'Nema postavljenih filtera',
noLabel: '<Nema {{label}}>',
noOptions: 'Nema opcija',
@@ -263,6 +264,7 @@ export const hrTranslations: DefaultTranslationsObject = {
password: 'Lozinka',
payloadSettings: 'Payload postavke',
perPage: 'Po stranici: {{limit}}',
previous: 'Prethodni',
remove: 'Ukloni',
reset: 'Ponovno postavi',
row: 'Red',
@@ -320,6 +322,8 @@ export const hrTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Dodaj datoteku',
addFiles: 'Dodaj datoteke',
bulkUpload: 'Masovno otpremanje',
crop: 'Usjev',
cropToolDescription:
'Povucite kutove odabranog područja, nacrtajte novo područje ili prilagodite vrijednosti ispod.',
@@ -328,6 +332,8 @@ export const hrTranslations: DefaultTranslationsObject = {
editImage: 'Uredi sliku',
fileName: 'Ime datoteke',
fileSize: 'Veličina datoteke',
fileToUpload: 'Datoteka za prijenos',
filesToUpload: 'Datoteke za učitavanje',
focalPoint: 'Središnja točka',
focalPointDescription:
'Povucite središnju točku izravno na pregledu ili prilagodite vrijednosti ispod.',

View File

@@ -248,6 +248,7 @@ export const huTranslations: DefaultTranslationsObject = {
moveDown: 'Mozgatás lefelé',
moveUp: 'Mozgatás felfelé',
newPassword: 'Új jelszó',
next: 'Következő',
noFiltersSet: 'Nincs beállítva szűrő',
noLabel: '<No {{label}}>',
noOptions: 'Nincs lehetőség',
@@ -265,6 +266,7 @@ export const huTranslations: DefaultTranslationsObject = {
password: 'Jelszó',
payloadSettings: 'Payload beállítások',
perPage: 'Oldalanként: {{limit}}',
previous: 'Előző',
remove: 'Törlés',
reset: 'Visszaállítás',
row: 'Sor',
@@ -322,6 +324,8 @@ export const huTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Fájl hozzáadása',
addFiles: 'Fájlok hozzáadása',
bulkUpload: 'Tömeges feltöltés',
crop: 'Termés',
cropToolDescription:
'Húzza a kijelölt terület sarkait, rajzoljon új területet, vagy igazítsa a lentebb található értékeket.',
@@ -330,6 +334,8 @@ export const huTranslations: DefaultTranslationsObject = {
editImage: 'Kép szerkesztése',
fileName: 'Fájlnév',
fileSize: 'Fájl mérete',
fileToUpload: 'Feltöltendő fájl',
filesToUpload: 'Feltöltendő fájlok',
focalPoint: 'Fókuszpont',
focalPointDescription:
'Húzza az érdekes pontot közvetlenül az előnézetre, vagy állítsa be az alábbi értékeket.',

View File

@@ -248,6 +248,7 @@ export const itTranslations: DefaultTranslationsObject = {
moveDown: 'Sposta sotto',
moveUp: 'Sposta sopra',
newPassword: 'Nuova Password',
next: 'Successivo',
noFiltersSet: 'Nessun filtro impostato',
noLabel: '<No {{label}}>',
noOptions: 'Nessuna opzione',
@@ -265,6 +266,7 @@ export const itTranslations: DefaultTranslationsObject = {
password: 'Password',
payloadSettings: 'Impostazioni di Payload',
perPage: 'Per Pagina: {{limit}}',
previous: 'Precedente',
remove: 'Rimuovi',
reset: 'Ripristina',
row: 'Riga',
@@ -322,6 +324,8 @@ export const itTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Aggiungi file',
addFiles: 'Aggiungi File',
bulkUpload: 'Caricamento in Blocco',
crop: 'Raccolto',
cropToolDescription:
"Trascina gli angoli dell'area selezionata, disegna una nuova area o regola i valori qui sotto.",
@@ -330,6 +334,8 @@ export const itTranslations: DefaultTranslationsObject = {
editImage: 'Modifica immagine',
fileName: 'Nome File',
fileSize: 'Dimensione File',
fileToUpload: 'File da caricare',
filesToUpload: 'File da caricare',
focalPoint: 'Punto Focale',
focalPointDescription:
"Trascina il punto focale direttamente sull'anteprima o regola i valori sottostanti.",

View File

@@ -246,6 +246,7 @@ export const jaTranslations: DefaultTranslationsObject = {
moveDown: '下へ移動',
moveUp: '上へ移動',
newPassword: '新しいパスワード',
next: '次',
noFiltersSet: '絞り込みが未設定です。',
noLabel: '<No {{label}}>',
noOptions: '選択肢なし',
@@ -263,6 +264,7 @@ export const jaTranslations: DefaultTranslationsObject = {
password: 'パスワード',
payloadSettings: 'Payload 設定',
perPage: '表示件数: {{limit}}',
previous: '前の',
remove: '削除',
reset: 'リセット',
row: '列',
@@ -320,6 +322,8 @@ export const jaTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'ファイルを追加',
addFiles: 'ファイルを追加する',
bulkUpload: '一括アップロード',
crop: 'クロップ',
cropToolDescription:
'選択したエリアのコーナーをドラッグしたり、新たなエリアを描画したり、下記の値を調整してください。',
@@ -328,6 +332,8 @@ export const jaTranslations: DefaultTranslationsObject = {
editImage: '画像を編集する',
fileName: 'ファイル名',
fileSize: 'ファイル容量',
fileToUpload: 'アップロードするファイル',
filesToUpload: 'アップロードするファイル',
focalPoint: '焦点',
focalPointDescription: 'プレビュー上で焦点を直接ドラッグするか、下の値を調整してください。',
height: '高さ',

View File

@@ -245,6 +245,7 @@ export const koTranslations: DefaultTranslationsObject = {
moveDown: '아래로 이동',
moveUp: '위로 이동',
newPassword: '새 비밀번호',
next: '다음',
noFiltersSet: '설정된 필터 없음',
noLabel: '<{{label}} 없음>',
noOptions: '옵션 없음',
@@ -262,6 +263,7 @@ export const koTranslations: DefaultTranslationsObject = {
password: '비밀번호',
payloadSettings: 'Payload 설정',
perPage: '페이지당 개수: {{limit}}',
previous: '이전',
remove: '제거',
reset: '초기화',
row: '행',
@@ -319,6 +321,8 @@ export const koTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: '파일 추가',
addFiles: '파일 추가',
bulkUpload: '일괄 업로드',
crop: '자르기',
cropToolDescription:
'선택한 영역의 모퉁이를 드래그하거나 새로운 영역을 그리거나 아래의 값을 조정하세요.',
@@ -327,6 +331,8 @@ export const koTranslations: DefaultTranslationsObject = {
editImage: '이미지 수정',
fileName: '파일 이름',
fileSize: '파일 크기',
fileToUpload: '업로드할 파일',
filesToUpload: '업로드할 파일들',
focalPoint: '초점',
focalPointDescription: '미리보기에서 초점을 직접 드래그하거나 아래의 값을 조정하세요.',
height: '높이',

View File

@@ -248,6 +248,7 @@ export const myTranslations: DefaultTranslationsObject = {
moveDown: 'Move Down',
moveUp: 'Move Up',
newPassword: 'စကားဝှက် အသစ်',
next: 'Seterusnya',
noFiltersSet: 'စစ်ထုတ်မှုများ မသတ်မှတ်ထားပါ။',
noLabel: '<မရှိ {{label}}>',
noOptions: 'ရွေးချယ်မှုမရှိပါ',
@@ -265,6 +266,7 @@ export const myTranslations: DefaultTranslationsObject = {
password: 'စကားဝှက်',
payloadSettings: 'ရွေးချယ်စရာများ',
perPage: 'စာမျက်နှာ အလိုက်: {{limit}}',
previous: 'ယခင်',
remove: 'ဖယ်ရှားမည်။',
reset: 'Tetapkan semula',
row: 'အတန်း',
@@ -323,6 +325,8 @@ export const myTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'ဖိုင်ထည့်ပါ',
addFiles: 'Tambah Fail',
bulkUpload: 'Muat naik pukal',
crop: 'သုန်း',
cropToolDescription:
'ရွေးထားသည့်ဧရိယာတွင်မွေးလျှက်မှုများကိုဆွဲပြီး, အသစ်တည်ပြီးသို့မဟုတ်အောက်ပါတ',
@@ -331,6 +335,8 @@ export const myTranslations: DefaultTranslationsObject = {
editImage: 'ပုံပြင်ပြောင်းရန်',
fileName: 'ဖိုင် နာမည်',
fileSize: 'ဖိုင် အရွယ်အစား',
fileToUpload: 'ဖိုင်တင်ရန်',
filesToUpload: 'Fail untuk Dimuat Naik',
focalPoint: 'အကန့်အသတ်ချုပ်',
focalPointDescription:
'ပြသနားရထားသည့်ပုံအားထိန်းသိမ်းရန် ဖိုကယ်ပိုင်းကို တိုက်ရိုက်ပွဲ့နိုင်သည် သို',

View File

@@ -246,6 +246,7 @@ export const nbTranslations: DefaultTranslationsObject = {
moveDown: 'Flytt ned',
moveUp: 'Flytt opp',
newPassword: 'Nytt passord',
next: 'Neste',
noFiltersSet: 'Ingen filtre satt',
noLabel: '<Ingen {{label}}>',
noOptions: 'Ingen alternativer',
@@ -263,6 +264,7 @@ export const nbTranslations: DefaultTranslationsObject = {
password: 'Passord',
payloadSettings: 'Payload-innstillinger',
perPage: 'Per side: {{limit}}',
previous: 'Forrige',
remove: 'Fjern',
reset: 'Tilbakestill',
row: 'Rad',
@@ -320,6 +322,8 @@ export const nbTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Legg til fil',
addFiles: 'Legg til filer',
bulkUpload: 'Bulk opplasting',
crop: 'Beskjær',
cropToolDescription:
'Dra hjørnene av det valgte området, tegn et nytt område eller juster verdiene nedenfor.',
@@ -328,6 +332,8 @@ export const nbTranslations: DefaultTranslationsObject = {
editImage: 'Rediger bilde',
fileName: 'Filnavn',
fileSize: 'Filstørrelse',
fileToUpload: 'Fil til opplasting',
filesToUpload: 'Filer til opplasting',
focalPoint: 'Fokuspunkt',
focalPointDescription:
'Dra fokuspunktet direkte på forhåndsvisningen eller juster verdiene nedenfor.',

View File

@@ -248,6 +248,7 @@ export const nlTranslations: DefaultTranslationsObject = {
moveDown: 'Verplaats naar beneden',
moveUp: 'Verplaats naar boven',
newPassword: 'Nieuw wachtwoord',
next: 'Volgende',
noFiltersSet: 'Geen filters ingesteld',
noLabel: 'Geen "{{label}}"',
noOptions: 'Geen opties',
@@ -265,6 +266,7 @@ export const nlTranslations: DefaultTranslationsObject = {
password: 'Wachtwoord',
payloadSettings: 'Payload Instellingen',
perPage: 'Per pagina: {{limit}}',
previous: 'Vorige',
remove: 'Verwijderen',
reset: 'Resetten',
row: 'Rij',
@@ -322,6 +324,8 @@ export const nlTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Bestand toevoegen',
addFiles: 'Bestanden toevoegen',
bulkUpload: 'Bulk Upload',
crop: 'Bijsnijden',
cropToolDescription:
'Sleep de hoeken van het geselecteerde gebied, teken een nieuw gebied of pas de waarden hieronder aan.',
@@ -330,6 +334,8 @@ export const nlTranslations: DefaultTranslationsObject = {
editImage: 'Afbeelding bewerken',
fileName: 'Bestandsnaam',
fileSize: 'Bestandsgrootte',
fileToUpload: 'Bestand om te uploaden',
filesToUpload: 'Bestanden om te uploaden',
focalPoint: 'Focuspunt',
focalPointDescription:
'Sleep het focuspunt rechtstreeks op de voorvertoning of pas de waarden hieronder aan.',

View File

@@ -246,6 +246,7 @@ export const plTranslations: DefaultTranslationsObject = {
moveDown: 'Przesuń niżej',
moveUp: 'Przesuń wyżej',
newPassword: 'Nowe hasło',
next: 'Następny',
noFiltersSet: 'Brak ustawionych filtrów',
noLabel: '<Bez {{label}}>',
noOptions: 'Brak opcji',
@@ -263,6 +264,7 @@ export const plTranslations: DefaultTranslationsObject = {
password: 'Hasło',
payloadSettings: 'Ustawienia Payload',
perPage: 'Na stronę: {{limit}}',
previous: 'Poprzedni',
remove: 'Usuń',
reset: 'Zresetuj',
row: 'Wiersz',
@@ -320,6 +322,8 @@ export const plTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Dodaj plik',
addFiles: 'Dodaj pliki',
bulkUpload: 'Załaduj masowo',
crop: 'Przytnij',
cropToolDescription:
'Przeciągnij narożniki wybranego obszaru, narysuj nowy obszar lub dostosuj poniższe wartości.',
@@ -328,6 +332,8 @@ export const plTranslations: DefaultTranslationsObject = {
editImage: 'Edytuj obraz',
fileName: 'Nazwa pliku',
fileSize: 'Rozmiar pliku',
fileToUpload: 'Plik do przesłania',
filesToUpload: 'Pliki do przesłania',
focalPoint: 'Punkt centralny',
focalPointDescription:
'Przeciągnij punkt centralny bezpośrednio na podglądzie lub dostosuj wartości poniżej.',

View File

@@ -247,6 +247,7 @@ export const ptTranslations: DefaultTranslationsObject = {
moveDown: 'Mover para Baixo',
moveUp: 'Mover para Cima',
newPassword: 'Nova Senha',
next: 'Próximo',
noFiltersSet: 'Nenhum filtro definido',
noLabel: '<Nenhum(a) {{label}}>',
noOptions: 'Sem opções',
@@ -264,6 +265,7 @@ export const ptTranslations: DefaultTranslationsObject = {
password: 'Senha',
payloadSettings: 'Configurações do Payload',
perPage: 'Itens por Página: {{limit}}',
previous: 'Anterior',
remove: 'Remover',
reset: 'Redefinir',
row: 'Linha',
@@ -321,6 +323,8 @@ export const ptTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Adicionar arquivo',
addFiles: 'Adicionar Arquivos',
bulkUpload: 'Upload em Massa',
crop: 'Cultura',
cropToolDescription:
'Arraste as bordas da área selecionada, desenhe uma nova área ou ajuste os valores abaixo.',
@@ -329,6 +333,8 @@ export const ptTranslations: DefaultTranslationsObject = {
editImage: 'Editar imagem',
fileName: 'Nome do Arquivo',
fileSize: 'Tamanho do Arquivo',
fileToUpload: 'Arquivo para upload',
filesToUpload: 'Arquivos para Carregar',
focalPoint: 'Ponto Focal',
focalPointDescription:
'Arraste o ponto focal diretamente na pré-visualização ou ajuste os valores abaixo.',

View File

@@ -250,6 +250,7 @@ export const roTranslations: DefaultTranslationsObject = {
moveDown: 'Mutați în jos',
moveUp: 'Mutați în sus',
newPassword: 'Parolă nouă',
next: 'Următorul',
noFiltersSet: 'Nici un filtru setat',
noLabel: '<Nici un {{label}}>',
noOptions: 'Fără opțiuni',
@@ -267,6 +268,7 @@ export const roTranslations: DefaultTranslationsObject = {
password: 'Parola',
payloadSettings: 'Setări de Payload',
perPage: 'Pe pagină: {{limit}}',
previous: 'Anterior',
remove: 'Eliminați',
reset: 'Resetare',
row: 'Rând',
@@ -324,6 +326,8 @@ export const roTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Adaugă fișier',
addFiles: 'Adăugați fișiere',
bulkUpload: 'Încărcare în masă',
crop: 'Cultură',
cropToolDescription:
'Trageți colțurile zonei selectate, desenați o nouă zonă sau ajustați valorile de mai jos.',
@@ -332,6 +336,8 @@ export const roTranslations: DefaultTranslationsObject = {
editImage: 'Editează imaginea',
fileName: 'Numele fișierului',
fileSize: 'Dimensiunea fișierului',
fileToUpload: 'Fișier de încărcat',
filesToUpload: 'Fișiere de încărcat',
focalPoint: 'Punct central',
focalPointDescription:
'Trageți punctul focal direct pe previzualizare sau ajustați valorile de mai jos.',

View File

@@ -245,6 +245,7 @@ export const rsTranslations: DefaultTranslationsObject = {
moveDown: 'Помери доле',
moveUp: 'Помери горе',
newPassword: 'Нова лозинка',
next: 'Следећи',
noFiltersSet: 'Нема постављених филтера',
noLabel: '<Нема {{label}}>',
noOptions: 'Нема опција',
@@ -262,6 +263,7 @@ export const rsTranslations: DefaultTranslationsObject = {
password: 'Лозинка',
payloadSettings: 'Payload поставке',
perPage: 'По страници: {{limit}}',
previous: 'Prethodni',
remove: 'Уклони',
reset: 'Поново постави',
row: 'Ред',
@@ -319,6 +321,8 @@ export const rsTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Додај датотеку',
addFiles: 'Dodaj datoteke',
bulkUpload: 'Masovno otpremanje',
crop: 'Исеците слику',
cropToolDescription:
'Превуците углове изабраног подручја, нацртајте ново подручје или прилагодите вредности испод.',
@@ -327,6 +331,8 @@ export const rsTranslations: DefaultTranslationsObject = {
editImage: 'Уреди слику',
fileName: 'Име датотеке',
fileSize: 'Величина датотеке',
fileToUpload: 'Fajl za otpremanje',
filesToUpload: 'Fajlovi za otpremanje',
focalPoint: 'Централна тачка',
focalPointDescription:
'Превуците средишњу тачку директно на преглед или прилагодите вредности испод.',

View File

@@ -245,6 +245,7 @@ export const rsLatinTranslations: DefaultTranslationsObject = {
moveDown: 'Pomeri dole',
moveUp: 'Pomeri gore',
newPassword: 'Nova lozinka',
next: 'Sledeći',
noFiltersSet: 'Nema postavljenih filtera',
noLabel: '<Nema {{label}}>',
noOptions: 'Nema opcija',
@@ -262,6 +263,7 @@ export const rsLatinTranslations: DefaultTranslationsObject = {
password: 'Lozinka',
payloadSettings: 'Payload postavke',
perPage: 'Po stranici: {{limit}}',
previous: 'Prethodni',
remove: 'Ukloni',
reset: 'Ponovo postavi',
row: 'Red',
@@ -319,6 +321,8 @@ export const rsLatinTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Dodaj datoteku',
addFiles: 'Dodaj Datoteke',
bulkUpload: 'Masovno otpremanje',
crop: 'Isecite sliku',
cropToolDescription:
'Prevucite uglove izabranog područja, nacrtajte novo područje ili prilagodite vrednosti ispod.',
@@ -327,6 +331,8 @@ export const rsLatinTranslations: DefaultTranslationsObject = {
editImage: 'Uredi sliku',
fileName: 'Ime datoteke',
fileSize: 'Veličina datoteke',
fileToUpload: 'Datoteka za otpremanje',
filesToUpload: 'Fajlovi za Slanje',
focalPoint: 'Centralna tačka',
focalPointDescription:
'Prevucite središnju tačku direktno na pregled ili prilagodite vrednosti ispod.',

View File

@@ -248,6 +248,7 @@ export const ruTranslations: DefaultTranslationsObject = {
moveDown: 'Сдвинуть вниз',
moveUp: 'Сдвинуть вверх',
newPassword: 'Новый пароль',
next: 'Следующий',
noFiltersSet: 'Фильтры не установлены',
noLabel: 'Без метки',
noOptions: 'Нет вариантов',
@@ -265,6 +266,7 @@ export const ruTranslations: DefaultTranslationsObject = {
password: 'Пароль',
payloadSettings: 'Настройки Payload',
perPage: 'На странице: {{limit}}',
previous: 'Предыдущий',
remove: 'Удалить',
reset: 'Сброс',
row: 'Строка',
@@ -323,6 +325,8 @@ export const ruTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Добавить файл',
addFiles: 'Добавить файлы',
bulkUpload: 'Массовая загрузка',
crop: 'Обрезать',
cropToolDescription:
'Перетащите углы выбранной области, нарисуйте новую область или отрегулируйте значения ниже.',
@@ -331,6 +335,8 @@ export const ruTranslations: DefaultTranslationsObject = {
editImage: 'Редактировать изображение',
fileName: 'Имя файла',
fileSize: 'Размер файла',
fileToUpload: 'Файл для загрузки',
filesToUpload: 'Файлы для загрузки',
focalPoint: 'Центральная точка',
focalPointDescription:
'Перетащите фокусное расстояние прямо на предварительный просмотр или отрегулируйте значения ниже.',

View File

@@ -247,6 +247,7 @@ export const skTranslations: DefaultTranslationsObject = {
moveDown: 'Presunúť dolu',
moveUp: 'Presunúť hore',
newPassword: 'Nové heslo',
next: 'Ďalej',
noFiltersSet: 'Nie sú nastavené žiadne filtre',
noLabel: '<Žiadny {{label}}>',
noOptions: 'Žiadne možnosti',
@@ -264,6 +265,7 @@ export const skTranslations: DefaultTranslationsObject = {
password: 'Heslo',
payloadSettings: 'Nastavenia dátového záznamu',
perPage: 'Na stránku: {{limit}}',
previous: 'Predchádzajúci',
remove: 'Odstrániť',
reset: 'Resetovať',
row: 'Riadok',
@@ -321,6 +323,8 @@ export const skTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Pridať súbor',
addFiles: 'Pridať súbory',
bulkUpload: 'Hromadné nahranie',
crop: 'Orezať',
cropToolDescription:
'Potiahnite rohy vybranej oblasti, nakreslite novú oblasť alebo upravte hodnoty nižšie.',
@@ -329,6 +333,8 @@ export const skTranslations: DefaultTranslationsObject = {
editImage: 'Upraviť obrázok',
fileName: 'Názov súboru',
fileSize: 'Veľkosť súboru',
fileToUpload: 'Súbor na nahranie',
filesToUpload: 'Súbory na nahranie',
focalPoint: 'Stredobod',
focalPointDescription:
'Potiahnite bod stredobodu priamo na náhľad alebo upravte hodnoty nižšie.',

View File

@@ -246,6 +246,7 @@ export const svTranslations: DefaultTranslationsObject = {
moveDown: 'Flytta Ner',
moveUp: 'Flytta Upp',
newPassword: 'Nytt Lösenord',
next: 'Nästa',
noFiltersSet: 'Inga filter inställda',
noLabel: '<Ingen {{label}}>',
noOptions: 'Inga alternativ',
@@ -263,6 +264,7 @@ export const svTranslations: DefaultTranslationsObject = {
password: 'Lösenord',
payloadSettings: 'Payload Inställningar',
perPage: 'Per Sida: {{limit}}',
previous: 'Föregående',
remove: 'Ta bort',
reset: 'Återställ',
row: 'Rad',
@@ -320,6 +322,8 @@ export const svTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Lägg till fil',
addFiles: 'Lägg till filer',
bulkUpload: 'Massuppladdning',
crop: 'Skörd',
cropToolDescription:
'Dra i hörnen på det valda området, rita ett nytt område eller justera värdena nedan.',
@@ -328,6 +332,8 @@ export const svTranslations: DefaultTranslationsObject = {
editImage: 'Redigera bild',
fileName: 'Filnamn',
fileSize: 'Filstorlek',
fileToUpload: 'Fil att ladda upp',
filesToUpload: 'Filer att ladda upp',
focalPoint: 'Fokuspunkt',
focalPointDescription:
'Dra fokuspunkten direkt på förhandsgranskningen eller justera värdena nedan.',

View File

@@ -242,6 +242,7 @@ export const thTranslations: DefaultTranslationsObject = {
moveDown: 'ขยับขึ้น',
moveUp: 'ขยับลง',
newPassword: 'รหัสผ่านใหม่',
next: 'ถัดไป',
noFiltersSet: 'ไม่มีการกรอง',
noLabel: '<ไม่มี {{label}}>',
noOptions: 'ไม่มีตัวเลือก',
@@ -259,6 +260,7 @@ export const thTranslations: DefaultTranslationsObject = {
password: 'รหัสผ่าน',
payloadSettings: 'การตั้งค่า Payload',
perPage: 'จำนวนต่อหน้า: {{limit}}',
previous: 'ก่อนหน้านี้',
remove: 'ลบ',
reset: 'รีเซ็ต',
row: 'แถว',
@@ -316,6 +318,8 @@ export const thTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'เพิ่มไฟล์',
addFiles: 'เพิ่มไฟล์',
bulkUpload: 'อัปโหลดจำนวนมาก',
crop: 'พืชผล',
cropToolDescription: 'ลากมุมของพื้นที่ที่เลือก, วาดพื้นที่ใหม่หรือปรับค่าด้านล่าง',
dragAndDrop: 'ลากและวางไฟล์',
@@ -323,6 +327,8 @@ export const thTranslations: DefaultTranslationsObject = {
editImage: 'แก้ไขรูปภาพ',
fileName: 'ชื่อไฟล์',
fileSize: 'ขนาดไฟล์',
fileToUpload: 'อัปโหลดไฟล์',
filesToUpload: 'อัปโหลดไฟล์',
focalPoint: 'จุดสนใจ',
focalPointDescription: 'ลากจุดโฟกัสตรงบนภาพตัวอย่างหรือปรับค่าที่อยู่ด้านล่าง',
height: 'ความสูง',

View File

@@ -249,6 +249,7 @@ export const trTranslations: DefaultTranslationsObject = {
moveDown: 'Aşağı taşı',
moveUp: 'Yukarı taşı',
newPassword: 'Yeni parola',
next: 'Sonraki',
noFiltersSet: 'Tanımlı filtre yok',
noLabel: '<{{label}} yok>',
noOptions: 'Seçenek yok',
@@ -266,6 +267,7 @@ export const trTranslations: DefaultTranslationsObject = {
password: 'Parola',
payloadSettings: 'Ayarlar',
perPage: 'Sayfa başına: {{limit}}',
previous: 'Önceki',
remove: 'Kaldır',
reset: 'Sıfırla',
row: 'Satır',
@@ -324,6 +326,8 @@ export const trTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Dosya ekle',
addFiles: 'Dosya Ekle',
bulkUpload: 'Toplu Yükleme',
crop: 'Mahsulat',
cropToolDescription:
'Seçilen alanın köşelerini sürükleyin, yeni bir alan çizin ya da aşağıdaki değerleri ayarlayın.',
@@ -332,6 +336,8 @@ export const trTranslations: DefaultTranslationsObject = {
editImage: 'Görüntüyü Düzenle',
fileName: 'Dosya adı',
fileSize: 'Dosya boyutu',
fileToUpload: 'Yüklenecek Dosya',
filesToUpload: 'Yüklemek için Dosyalar',
focalPoint: 'Odak Noktası',
focalPointDescription:
'Önizlemeye odak noktasını doğrudan sürükleyin veya aşağıdaki değerleri ayarlayın.',

View File

@@ -246,6 +246,7 @@ export const ukTranslations: DefaultTranslationsObject = {
moveDown: 'Перемістити нижче',
moveUp: 'Перемістити вище',
newPassword: 'Новий пароль',
next: 'Наступний',
noFiltersSet: 'Відсусті фільтри',
noLabel: '<без {{label}}>',
noOptions: 'Немає варіантів',
@@ -263,6 +264,7 @@ export const ukTranslations: DefaultTranslationsObject = {
password: 'Пароль',
payloadSettings: 'Налаштування Payload',
perPage: 'На сторінці: {{limit}}',
previous: 'Попередній',
remove: 'Видалити',
reset: 'Скидання',
row: 'Рядок',
@@ -320,6 +322,8 @@ export const ukTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Додати файл',
addFiles: 'Додати файли',
bulkUpload: 'Масове завантаження',
crop: 'Обрізати',
cropToolDescription:
'Перетягніть кути обраної області, намалюйте нову область або скоригуйте значення нижче.',
@@ -328,6 +332,8 @@ export const ukTranslations: DefaultTranslationsObject = {
editImage: 'Редагувати зображення',
fileName: 'Назва файлу',
fileSize: 'Розмір файлу',
fileToUpload: 'Файл для завантаження',
filesToUpload: 'Файли для завантаження',
focalPoint: 'Точка фокусу',
focalPointDescription:
'Перетягніть точку фокусу безпосередньо на попередньому перегляді або налаштуйте значення нижче.',

View File

@@ -244,6 +244,7 @@ export const viTranslations: DefaultTranslationsObject = {
moveDown: 'Di chuyển xuống',
moveUp: 'Di chuyển lên',
newPassword: 'Mật khảu mới',
next: 'Tiếp theo',
noFiltersSet: 'Không có bộ lọc nào được áp dụng',
noLabel: '<Không có {{label}}>',
noOptions: 'Không có lựa chọn',
@@ -261,6 +262,7 @@ export const viTranslations: DefaultTranslationsObject = {
password: 'Mật khẩu',
payloadSettings: 'Cài đặt',
perPage: 'Hiển thị mỗi trang: {{limit}}',
previous: 'Trước đó',
remove: 'Loại bỏ',
reset: 'Đặt lại',
row: 'Hàng',
@@ -318,6 +320,8 @@ export const viTranslations: DefaultTranslationsObject = {
},
upload: {
addFile: 'Thêm tập tin',
addFiles: 'Thêm tệp',
bulkUpload: 'Tải lên số lượng lớn',
crop: 'Mùa vụ',
cropToolDescription:
'Kéo các góc của khu vực đã chọn, vẽ một khu vực mới hoặc điều chỉnh các giá trị dưới đây.',
@@ -326,6 +330,8 @@ export const viTranslations: DefaultTranslationsObject = {
editImage: 'Chỉnh sửa hình ảnh',
fileName: 'Tên file',
fileSize: 'Dung lượng file',
fileToUpload: 'Tệp để Tải lên',
filesToUpload: 'Tệp để Tải lên',
focalPoint: 'Điểm trọng tâm',
focalPointDescription:
'Kéo điểm tiêu cực trực tiếp trên trình xem trước hoặc điều chỉnh các giá trị bên dưới.',

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