Compare commits
24 Commits
fix/in-ope
...
v2.20.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab97590879 | ||
|
|
ed86b15242 | ||
|
|
d58631c12c | ||
|
|
37c8386a51 | ||
|
|
2f9ed34d13 | ||
|
|
921a5c065d | ||
|
|
e3003b443f | ||
|
|
8a622984e7 | ||
|
|
507e0954b2 | ||
|
|
63bc6ae52f | ||
|
|
d016fbd2a5 | ||
|
|
9525511e8b | ||
|
|
1e834e58a4 | ||
|
|
373cb00139 | ||
|
|
558b298bf0 | ||
|
|
cd24e2bb3c | ||
|
|
ac8c2096af | ||
|
|
626be15578 | ||
|
|
67c0b0e6e0 | ||
|
|
11239103a6 | ||
|
|
4998ef8c9b | ||
|
|
e44ce819ce | ||
|
|
b700208b98 | ||
|
|
4a54aa7776 |
2
.github/ISSUE_TEMPLATE/2.bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/2.bug_report.yml
vendored
@@ -1,6 +1,6 @@
|
||||
name: Bug Report
|
||||
description: Create a bug report for Payload
|
||||
labels: ['status: needs-triage']
|
||||
labels: ['status: needs-triage', 'v2']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
61
CHANGELOG.md
61
CHANGELOG.md
@@ -1,3 +1,64 @@
|
||||
## [2.20.0](https://github.com/payloadcms/payload/compare/v2.19.3...v2.20.0) (2024-06-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **ui:** updates draft/published version pills ([#6732](https://github.com/payloadcms/payload/issues/6732)) ([ed86b15](https://github.com/payloadcms/payload/commit/ed86b15242ccbd737f3fe80103afc7d8c4cc6915))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* adds multi select inputs for `number` & `text` fields in where builder ([#6662](https://github.com/payloadcms/payload/issues/6662)) ([e3003b4](https://github.com/payloadcms/payload/commit/e3003b443fd3b472670ade228c174c7f755b1732))
|
||||
* create sharp file for `fileHasAdjustments` files or `fileIsAnimated` files ([#6710](https://github.com/payloadcms/payload/issues/6710)) ([921a5c0](https://github.com/payloadcms/payload/commit/921a5c065d6089f0118ad8be7adbf75614c8db9c))
|
||||
* enable SaveDraft button when creating new documents ([#6672](https://github.com/payloadcms/payload/issues/6672)) ([63bc6ae](https://github.com/payloadcms/payload/commit/63bc6ae52f63adf98f442c2d7992461e7f5f86e4)), closes [#6671](https://github.com/payloadcms/payload/issues/6671) [/github.com/payloadcms/payload/commit/8f03cd7c789eda7613ddced0d45a32afe49b1e01#diff-b7c978f47b1f3beff95c78ad95078e600624cbcd7ac10f9378cc4ad6803db244L75-R79](https://github.com/payloadcms//github.com/payloadcms/payload/commit/8f03cd7c789eda7613ddced0d45a32afe49b1e01/issues/diff-b7c978f47b1f3beff95c78ad95078e600624cbcd7ac10f9378cc4ad6803db244L75-R79)
|
||||
* handles localized nested relationship fields in versions ([#6679](https://github.com/payloadcms/payload/issues/6679)) ([8a62298](https://github.com/payloadcms/payload/commit/8a622984e7ce4a2439d5d63e2689404652f8c96b))
|
||||
* live preview device position when using zoom ([#6667](https://github.com/payloadcms/payload/issues/6667)) ([9525511](https://github.com/payloadcms/payload/commit/9525511e8bc6bc3fbd7e21e36596404604f1c109))
|
||||
* only use `metadata.pages` for height if animated ([#6729](https://github.com/payloadcms/payload/issues/6729)) ([2f9ed34](https://github.com/payloadcms/payload/commit/2f9ed34d13d94070db40b1eabd04655d2e13e094))
|
||||
* removes `array` & `blocks` & `group` fields from sort ([#6574](https://github.com/payloadcms/payload/issues/6574)) ([507e095](https://github.com/payloadcms/payload/commit/507e0954b2743012f0b53c396d49461120a02b1a)), closes [#6469](https://github.com/payloadcms/payload/issues/6469)
|
||||
* withinCollapsible should be undefined by default ([#6666](https://github.com/payloadcms/payload/issues/6666)) ([37c8386](https://github.com/payloadcms/payload/commit/37c8386a51172966057df3477517d160e1c4a9a7)), closes [#6658](https://github.com/payloadcms/payload/issues/6658)
|
||||
|
||||
## [2.19.3](https://github.com/payloadcms/payload/compare/v2.19.2...v2.19.3) (2024-06-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* scopes uploadEdits to documents, hoists action to doc provider ([#6664](https://github.com/payloadcms/payload/issues/6664)) ([373cb00](https://github.com/payloadcms/payload/commit/373cb0013902b52aba455542e10402316da4b2f4))
|
||||
|
||||
## [2.19.2](https://github.com/payloadcms/payload/compare/v2.19.1...v2.19.2) (2024-06-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* cascade draft arg when querying globals with graphql ([#6651](https://github.com/payloadcms/payload/issues/6651)) ([ac8c209](https://github.com/payloadcms/payload/commit/ac8c2096af641a6886e4543ee65c9790e45f080f))
|
||||
* filtered out `disableListColumn` fields reappeared after toggling other fields ([#6636](https://github.com/payloadcms/payload/issues/6636)) ([626be15](https://github.com/payloadcms/payload/commit/626be155784dda181276bb87617433822a0accf3))
|
||||
* resizing animated images ([#6621](https://github.com/payloadcms/payload/issues/6621)) ([67c0b0e](https://github.com/payloadcms/payload/commit/67c0b0e6e0b5b190f6a916b59ba02f8c18479e18)), closes [#2181](https://github.com/payloadcms/payload/issues/2181) [#6146](https://github.com/payloadcms/payload/issues/6146)
|
||||
|
||||
## [2.19.1](https://github.com/payloadcms/payload/compare/v2.19.0...v2.19.1) (2024-06-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* override ajv dependency version to 8.14.0 wherever possible ([#6618](https://github.com/payloadcms/payload/issues/6618)) ([e44ce81](https://github.com/payloadcms/payload/commit/e44ce819cefddeaaf20b2b7ce804e94a9272baf1))
|
||||
|
||||
## [2.19.0](https://github.com/payloadcms/payload/compare/v2.18.3...v2.19.0) (2024-06-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **translations:** update Turkish translations ([#5738](https://github.com/payloadcms/payload/issues/5738)) ([4fddea8](https://github.com/payloadcms/payload/commit/4fddea86ebd5f21705be2310f8b7053d31109189))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* adds new `userEmailAlreadyRegistered` translations ([#6549](https://github.com/payloadcms/payload/issues/6549)) ([56c6700](https://github.com/payloadcms/payload/commit/56c6700cf25570cc217e28dc69459a3b81adbced)), closes [#6535](https://github.com/payloadcms/payload/issues/6535)
|
||||
* adjusts sizing of remove/add buttons to be same size ([#6527](https://github.com/payloadcms/payload/issues/6527)) ([a352ebc](https://github.com/payloadcms/payload/commit/a352ebc5520bbd0f6a9caef068825976dba05ded)), closes [#6098](https://github.com/payloadcms/payload/issues/6098)
|
||||
* focalPoint undefined handling ([#6552](https://github.com/payloadcms/payload/issues/6552)) ([fcfc3c5](https://github.com/payloadcms/payload/commit/fcfc3c593f69f63c51f8aa09973fcacbfbe04952))
|
||||
* pagination on polymorphic relationship field requesting entries with page parameter set to NaN ([#5366](https://github.com/payloadcms/payload/issues/5366)) ([547acfe](https://github.com/payloadcms/payload/commit/547acfe876bdf0df2ce808941f72b690c9dbcae3))
|
||||
* safely evaluates `field.admin` in WhereBuilder ([#6534](https://github.com/payloadcms/payload/issues/6534)) ([4f9d78d](https://github.com/payloadcms/payload/commit/4f9d78df5e38f3f70852bb6de47cff619f57c648))
|
||||
* separate sort and search fields when looking up relationship. ([#5964](https://github.com/payloadcms/payload/issues/5964)) ([c009219](https://github.com/payloadcms/payload/commit/c0092191a6ded1098a94d9f48918ab79171e5e32)), closes [#4815](https://github.com/payloadcms/payload/issues/4815) [#5222](https://github.com/payloadcms/payload/issues/5222)
|
||||
* ui field validation error with `admin.disableListColumn` property ([#6530](https://github.com/payloadcms/payload/issues/6530)) ([eeddece](https://github.com/payloadcms/payload/commit/eeddeceda988d7a4ce8ad31d3036a4ee84aceec3)), closes [#6521](https://github.com/payloadcms/payload/issues/6521)
|
||||
* **ui:** blocks browser save dialog from opening when hotkey used with no changes ([#6365](https://github.com/payloadcms/payload/issues/6365)) ([8f03cd7](https://github.com/payloadcms/payload/commit/8f03cd7c789eda7613ddced0d45a32afe49b1e01)), closes [#214](https://github.com/payloadcms/payload/issues/214)
|
||||
|
||||
## [2.18.3](https://github.com/payloadcms/payload/compare/v2.18.2...v2.18.3) (2024-05-17)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Implementing Live Preview in your app
|
||||
label: Frontend Implementation
|
||||
label: Frontend
|
||||
order: 20
|
||||
desc: Learn how to implement Live Preview in your front-end application.
|
||||
keywords: live preview, frontend, react, next.js, vue, nuxt.js, svelte, hook, useLivePreview
|
||||
@@ -274,3 +274,11 @@ const { data } = useLivePreview<PageType>({
|
||||
depth: 1, // Ensure this matches the depth of your initial request
|
||||
})
|
||||
```
|
||||
|
||||
#### Iframe refuses to connect
|
||||
|
||||
If your front-end application has set a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) that blocks the Admin Panel from loading your front-end application, the iframe will not be able to load your site. To resolve this, you can whitelist the Admin Panel's domain in your CSP by setting the `frame-ancestors` directive:
|
||||
|
||||
```plaintext
|
||||
frame-ancestors: "self" localhost:* https://your-site.com;
|
||||
```
|
||||
|
||||
@@ -129,6 +129,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/react": "^7.77.0",
|
||||
"ajv": "^8.12.0"
|
||||
"ajv": "8.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/bundler-webpack",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.7",
|
||||
"description": "The officially supported Webpack bundler adapter for Payload",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -27,7 +27,6 @@
|
||||
"compression": "1.7.4",
|
||||
"connect-history-api-fallback": "1.6.0",
|
||||
"css-loader": "5.2.7",
|
||||
"css-minimizer-webpack-plugin": "^5.0.0",
|
||||
"file-loader": "6.2.0",
|
||||
"find-node-modules": "^2.1.3",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
@@ -48,7 +47,8 @@
|
||||
"webpack-bundle-analyzer": "^4.8.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-dev-middleware": "6.1.2",
|
||||
"webpack-hot-middleware": "^2.25.3"
|
||||
"webpack-hot-middleware": "^2.25.3",
|
||||
"ajv": "8.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@payloadcms/eslint-config": "workspace:*",
|
||||
@@ -62,8 +62,44 @@
|
||||
"@types/webpack-hot-middleware": "2.25.6",
|
||||
"payload": "workspace:*"
|
||||
},
|
||||
"resolutions": {
|
||||
"ajv": "8.14.0",
|
||||
"webpack-dev-middleware/**/ajv": "8.14.0",
|
||||
"css-minimizer-webpack-plugin/**/ajv": "8.14.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"payload": "^2.0.0"
|
||||
"payload": "^2.0.0",
|
||||
"ajv": "8.14.0"
|
||||
},
|
||||
"overrides": {
|
||||
"ajv": "8.14.0",
|
||||
"webpack-dev-middleware": {
|
||||
"ajv": "8.14.0",
|
||||
"schema-utils": {
|
||||
"ajv": "8.14.0"
|
||||
}
|
||||
},
|
||||
"css-minimizer-webpack-plugin": {
|
||||
"schema-utils": {
|
||||
"ajv": "8.14.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"ajv": "8.14.0",
|
||||
"webpack-dev-middleware": {
|
||||
"ajv": "8.14.0",
|
||||
"schema-utils": {
|
||||
"ajv": "8.14.0"
|
||||
}
|
||||
},
|
||||
"css-minimizer-webpack-plugin": {
|
||||
"schema-utils": {
|
||||
"ajv": "8.14.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "2.18.3",
|
||||
"version": "2.20.0",
|
||||
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
@@ -209,6 +209,29 @@
|
||||
"vite": "^4.4.9",
|
||||
"webpack": "^5.78.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"ajv": "8.14.0",
|
||||
"webpack-dev-middleware/**/ajv": "8.14.0",
|
||||
"css-minimizer-webpack-plugin/**/ajv": "8.14.0"
|
||||
},
|
||||
"overrides": {
|
||||
"ajv": "8.14.0",
|
||||
"css-minimizer-webpack-plugin": {
|
||||
"schema-utils": {
|
||||
"ajv": "8.14.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"ajv": "8.14.0",
|
||||
"css-minimizer-webpack-plugin": {
|
||||
"schema-utils": {
|
||||
"ajv": "8.14.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ const Context = createContext({
|
||||
collapsed: false,
|
||||
isVisible: true,
|
||||
toggle: () => {},
|
||||
withinCollapsible: true,
|
||||
withinCollapsible: false,
|
||||
})
|
||||
|
||||
export const CollapsibleProvider: React.FC<{
|
||||
@@ -18,7 +18,7 @@ export const CollapsibleProvider: React.FC<{
|
||||
collapsed?: boolean
|
||||
toggle: () => void
|
||||
withinCollapsible?: boolean
|
||||
}> = ({ children, collapsed, toggle, withinCollapsible = true }) => {
|
||||
}> = ({ children, collapsed, toggle, withinCollapsible }) => {
|
||||
const { collapsed: parentIsCollapsed, isVisible } = useCollapsible()
|
||||
|
||||
const contextValue = React.useMemo((): ContextType => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useId } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import type { Column } from '../Table/types'
|
||||
import type { Props } from './types'
|
||||
|
||||
import { getTranslation } from '../../../../utilities/getTranslation'
|
||||
@@ -14,6 +15,12 @@ import './index.scss'
|
||||
|
||||
const baseClass = 'column-selector'
|
||||
|
||||
const filterColumnFields = (fields: Column[]): Column[] => {
|
||||
return fields.filter((field) => {
|
||||
return !field.admin?.disableListColumn
|
||||
})
|
||||
}
|
||||
|
||||
const ColumnSelector: React.FC<Props> = (props) => {
|
||||
const { slug } = props
|
||||
|
||||
@@ -27,10 +34,12 @@ const ColumnSelector: React.FC<Props> = (props) => {
|
||||
return null
|
||||
}
|
||||
|
||||
const filteredColumns = filterColumnFields(columns)
|
||||
|
||||
return (
|
||||
<DraggableSortable
|
||||
className={baseClass}
|
||||
ids={columns.map((col) => col.accessor)}
|
||||
ids={filteredColumns.map((col) => col.accessor)}
|
||||
onDragEnd={({ moveFromIndex, moveToIndex }) => {
|
||||
moveColumn({
|
||||
fromIndex: moveFromIndex,
|
||||
@@ -38,7 +47,7 @@ const ColumnSelector: React.FC<Props> = (props) => {
|
||||
})
|
||||
}}
|
||||
>
|
||||
{columns.map((col, i) => {
|
||||
{filteredColumns.map((col, i) => {
|
||||
const { name, accessor, active, label } = col
|
||||
|
||||
if (col.accessor === '_select') return null
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useModal } from '@faceless-ui/modal'
|
||||
import queryString from 'qs'
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { toast } from 'react-toastify'
|
||||
@@ -18,7 +17,6 @@ import X from '../../icons/X'
|
||||
import { useAuth } from '../../utilities/Auth'
|
||||
import { useConfig } from '../../utilities/Config'
|
||||
import { DocumentInfoProvider, useDocumentInfo } from '../../utilities/DocumentInfo'
|
||||
import { useFormQueryParams } from '../../utilities/FormQueryParams'
|
||||
import { useLocale } from '../../utilities/Locale'
|
||||
import RenderCustomComponent from '../../utilities/RenderCustomComponent'
|
||||
import DefaultEdit from '../../views/collections/Edit/Default'
|
||||
@@ -45,12 +43,10 @@ const Content: React.FC<DocumentDrawerProps> = ({
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [collectionConfig] = useRelatedCollections(collectionSlug)
|
||||
const config = useConfig()
|
||||
const { formQueryParams } = useFormQueryParams()
|
||||
const formattedQueryParams = queryString.stringify(formQueryParams)
|
||||
|
||||
const { admin: { components: { views: { Edit } = {} } = {} } = {} } = collectionConfig
|
||||
|
||||
const { id, docPermissions, getDocPreferences } = useDocumentInfo()
|
||||
const { id, action, docPermissions, getDocPreferences } = useDocumentInfo()
|
||||
|
||||
// If they are replacing the entire edit view, use that.
|
||||
// Else let the DefaultEdit determine what to render.
|
||||
@@ -90,7 +86,7 @@ const Content: React.FC<DocumentDrawerProps> = ({
|
||||
setInternalState(state)
|
||||
}
|
||||
|
||||
awaitInitialState()
|
||||
void awaitInitialState()
|
||||
hasInitializedState.current = true
|
||||
}, [data, fields, id, user, locale, isLoadingDocument, t, getDocPreferences, config])
|
||||
|
||||
@@ -111,10 +107,6 @@ const Content: React.FC<DocumentDrawerProps> = ({
|
||||
|
||||
const apiURL = id ? `${serverURL}${api}/${collectionSlug}/${id}?locale=${locale}` : null
|
||||
|
||||
const action = `${serverURL}${api}/${collectionSlug}${
|
||||
isEditing ? `/${id}` : ''
|
||||
}?${formattedQueryParams}`
|
||||
|
||||
const hasSavePermission =
|
||||
(isEditing && docPermissions?.update?.permission) ||
|
||||
(!isEditing && (docPermissions as CollectionPermission)?.create?.permission)
|
||||
|
||||
@@ -7,7 +7,7 @@ import 'react-image-crop/dist/ReactCrop.css'
|
||||
import type { Data } from '../../forms/Form/types'
|
||||
|
||||
import Plus from '../../icons/Plus'
|
||||
import { useFormQueryParams } from '../../utilities/FormQueryParams'
|
||||
import { useUploadEdits } from '../../utilities/UploadEdits'
|
||||
import { editDrawerSlug } from '../../views/collections/Edit/Upload'
|
||||
import Button from '../Button'
|
||||
import './index.scss'
|
||||
@@ -35,8 +35,8 @@ export const EditUpload: React.FC<{
|
||||
}> = ({ doc, fileName, fileSrc, imageCacheTag, showCrop, showFocalPoint }) => {
|
||||
const { closeModal } = useModal()
|
||||
const { t } = useTranslation(['general', 'upload'])
|
||||
const { formQueryParams, setFormQueryParams } = useFormQueryParams()
|
||||
const { uploadEdits } = formQueryParams || {}
|
||||
const { updateUploadEdits, uploadEdits } = useUploadEdits()
|
||||
|
||||
const [crop, setCrop] = useState<CropType>({
|
||||
height: uploadEdits?.crop?.height || 100,
|
||||
unit: '%',
|
||||
@@ -87,12 +87,9 @@ export const EditUpload: React.FC<{
|
||||
}
|
||||
|
||||
const saveEdits = () => {
|
||||
setFormQueryParams({
|
||||
...formQueryParams,
|
||||
uploadEdits: {
|
||||
crop: crop || undefined,
|
||||
focalPoint: focalPosition ? focalPosition : undefined,
|
||||
},
|
||||
updateUploadEdits({
|
||||
crop: crop || undefined,
|
||||
focalPoint: focalPosition ? focalPosition : undefined,
|
||||
})
|
||||
closeModal(editDrawerSlug)
|
||||
}
|
||||
|
||||
@@ -67,13 +67,10 @@ export const ListControls: React.FC<Props> = (props) => {
|
||||
}, [listSearchableFields, fields])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (hasWhereParam.current && !params?.where) {
|
||||
if (!params?.limit) {
|
||||
setVisibleDrawer(undefined)
|
||||
hasWhereParam.current = false
|
||||
} else if (params?.where) {
|
||||
hasWhereParam.current = true
|
||||
}
|
||||
}, [setVisibleDrawer, params?.where])
|
||||
}, [setVisibleDrawer, params?.limit])
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
|
||||
@@ -8,7 +8,6 @@ import { useConfig } from '../../utilities/Config'
|
||||
import { useDocumentInfo } from '../../utilities/DocumentInfo'
|
||||
import { useEditDepth } from '../../utilities/EditDepth'
|
||||
import { useLocale } from '../../utilities/Locale'
|
||||
import { useOperation } from '../../utilities/OperationProvider'
|
||||
import RenderCustomComponent from '../../utilities/RenderCustomComponent'
|
||||
|
||||
const baseClass = 'save-draft'
|
||||
@@ -70,13 +69,12 @@ export const SaveDraft: React.FC<Props> = ({ CustomComponent }) => {
|
||||
} = useConfig()
|
||||
const { submit } = useForm()
|
||||
const { id, collection, global } = useDocumentInfo()
|
||||
const operation = useOperation()
|
||||
const modified = useFormModified()
|
||||
|
||||
const { code: locale } = useLocale()
|
||||
const { t } = useTranslation('version')
|
||||
|
||||
const canSaveDraft = operation === 'update' && modified
|
||||
const canSaveDraft = modified
|
||||
|
||||
const saveDraft = useCallback(async () => {
|
||||
const search = `?locale=${locale}&depth=0&fallback-locale=null&draft=true`
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { FieldBase } from '../../../../fields/config/types'
|
||||
export type Column = {
|
||||
accessor: string
|
||||
active: boolean
|
||||
admin?: FieldBase['admin']
|
||||
components: {
|
||||
Heading: React.ReactNode
|
||||
renderCell: (row: any, data: any) => React.ReactNode
|
||||
|
||||
@@ -42,18 +42,27 @@ const buildColumns = ({
|
||||
colIndex += 1
|
||||
}
|
||||
const props = cellProps?.[colIndex] || {}
|
||||
|
||||
const fieldAffectsDataSubFields =
|
||||
field &&
|
||||
field.type &&
|
||||
(field.type === 'array' || field.type === 'group' || field.type === 'blocks')
|
||||
|
||||
const disableListFilter =
|
||||
field.admin && 'disableListFilter' in field.admin ? field.admin.disableListFilter : false
|
||||
|
||||
return {
|
||||
name: field.name,
|
||||
accessor: field.name,
|
||||
active: isActive,
|
||||
admin: {
|
||||
disableListColumn: field.admin?.disableListColumn,
|
||||
disableListFilter,
|
||||
},
|
||||
components: {
|
||||
Heading: (
|
||||
<SortColumn
|
||||
disable={
|
||||
('disableSort' in field && Boolean(field.disableSort)) ||
|
||||
fieldIsPresentationalOnly(field) ||
|
||||
undefined
|
||||
}
|
||||
disable={fieldAffectsDataSubFields || fieldIsPresentationalOnly(field) || undefined}
|
||||
label={field.label || field.name}
|
||||
name={field.name}
|
||||
/>
|
||||
|
||||
@@ -3,31 +3,78 @@ import { useTranslation } from 'react-i18next'
|
||||
|
||||
import type { Props } from './types'
|
||||
|
||||
import ReactSelect from '../../../ReactSelect'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'condition-value-number'
|
||||
|
||||
const NumberField: React.FC<Props> = ({ disabled, onChange, operator, value }) => {
|
||||
const { t } = useTranslation('general')
|
||||
const { t } = useTranslation()
|
||||
|
||||
const isMulti = ['in', 'not_in'].includes(operator)
|
||||
|
||||
let valueToRender
|
||||
const [valueToRender, setValueToRender] = React.useState<
|
||||
{ id: string; label: string; value: { value: number } }[]
|
||||
>([])
|
||||
|
||||
if (isMulti && Array.isArray(value)) {
|
||||
valueToRender = value.map((val) => ({ label: val, value: val }))
|
||||
} else if (value) {
|
||||
valueToRender = { label: value, value }
|
||||
}
|
||||
const onSelect = React.useCallback(
|
||||
(selectedOption) => {
|
||||
let newValue
|
||||
if (!selectedOption) {
|
||||
newValue = []
|
||||
} else if (isMulti) {
|
||||
if (Array.isArray(selectedOption)) {
|
||||
newValue = selectedOption.map((option) => Number(option.value?.value || option.value))
|
||||
} else {
|
||||
newValue = [Number(selectedOption.value?.value || selectedOption.value)]
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
onChange(newValue)
|
||||
},
|
||||
[isMulti, onChange],
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (Array.isArray(value)) {
|
||||
setValueToRender(
|
||||
value.map((val, index) => {
|
||||
return {
|
||||
id: `${val}${index}`, // append index to avoid duplicate keys but allow duplicate numbers
|
||||
label: `${val}`,
|
||||
value: {
|
||||
toString: () => `${val}${index}`,
|
||||
value: (val as any)?.value || val,
|
||||
},
|
||||
}
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
setValueToRender([])
|
||||
}
|
||||
}, [value])
|
||||
|
||||
return isMulti ? (
|
||||
<ReactSelect
|
||||
disabled={disabled}
|
||||
isClearable
|
||||
isCreatable
|
||||
isMulti={isMulti}
|
||||
isSortable
|
||||
numberOnly
|
||||
onChange={onSelect}
|
||||
options={[]}
|
||||
placeholder={t('general:enterAValue')}
|
||||
value={valueToRender || []}
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
className={baseClass}
|
||||
disabled={disabled}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={t('enterAValue')}
|
||||
placeholder={t('general:enterAValue')}
|
||||
type="number"
|
||||
value={value}
|
||||
value={value as number}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ export type Props = {
|
||||
disabled?: boolean
|
||||
onChange: (e: string) => void
|
||||
operator: Operator
|
||||
value: string
|
||||
value: number | number[]
|
||||
}
|
||||
|
||||
@@ -3,18 +3,75 @@ import { useTranslation } from 'react-i18next'
|
||||
|
||||
import type { Props } from './types'
|
||||
|
||||
import ReactSelect from '../../../ReactSelect'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'condition-value-text'
|
||||
|
||||
const Text: React.FC<Props> = ({ disabled, onChange, value }) => {
|
||||
const { t } = useTranslation('general')
|
||||
return (
|
||||
const Text: React.FC<Props> = ({ disabled, onChange, operator, value }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const isMulti = ['in', 'not_in'].includes(operator)
|
||||
|
||||
const [valueToRender, setValueToRender] = React.useState<
|
||||
{ id: string; label: string; value: { value: string } }[]
|
||||
>([])
|
||||
|
||||
const onSelect = React.useCallback(
|
||||
(selectedOption) => {
|
||||
let newValue
|
||||
if (!selectedOption) {
|
||||
newValue = []
|
||||
} else if (isMulti) {
|
||||
if (Array.isArray(selectedOption)) {
|
||||
newValue = selectedOption.map((option) => option.value?.value || option.value)
|
||||
} else {
|
||||
newValue = [selectedOption.value?.value || selectedOption.value]
|
||||
}
|
||||
}
|
||||
|
||||
onChange(newValue)
|
||||
},
|
||||
[isMulti, onChange],
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (Array.isArray(value)) {
|
||||
setValueToRender(
|
||||
value.map((val, index) => {
|
||||
return {
|
||||
id: `${val}${index}`, // append index to avoid duplicate keys but allow duplicate numbers
|
||||
label: `${val}`,
|
||||
value: {
|
||||
toString: () => `${val}${index}`,
|
||||
value: (val as any)?.value || val,
|
||||
},
|
||||
}
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
setValueToRender([])
|
||||
}
|
||||
}, [value])
|
||||
|
||||
return isMulti ? (
|
||||
<ReactSelect
|
||||
disabled={disabled}
|
||||
isClearable
|
||||
isCreatable
|
||||
isMulti={isMulti}
|
||||
isSortable
|
||||
onChange={onSelect}
|
||||
options={[]}
|
||||
placeholder={t('general:enterAValue')}
|
||||
value={valueToRender || []}
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
className={baseClass}
|
||||
disabled={disabled}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={t('enterAValue')}
|
||||
placeholder={t('general:enterAValue')}
|
||||
type="text"
|
||||
value={value || ''}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import type { Operator } from '../../../../../../types'
|
||||
|
||||
export type Props = {
|
||||
disabled?: boolean
|
||||
onChange: (val: string) => void
|
||||
value: string
|
||||
operator: Operator
|
||||
value: string | string[]
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ const Condition: React.FC<Props> = (props) => {
|
||||
orIndex,
|
||||
})
|
||||
setInternalOperatorField(operator.value)
|
||||
setInternalValue('') // Reset value when operator changes
|
||||
}}
|
||||
options={activeField.operators}
|
||||
value={
|
||||
|
||||
@@ -34,7 +34,7 @@ const reduceFields = (fields, i18n) =>
|
||||
}
|
||||
|
||||
const operatorKeys = new Set()
|
||||
const filteredOperators = operators.reduce((acc, operator) => {
|
||||
const reducedOperators = operators.reduce((acc, operator) => {
|
||||
if (!operatorKeys.has(operator.value)) {
|
||||
operatorKeys.add(operator.value)
|
||||
return [
|
||||
@@ -52,7 +52,7 @@ const reduceFields = (fields, i18n) =>
|
||||
label: getTranslation(field.label || field.name, i18n),
|
||||
value: field.name,
|
||||
...fieldTypes[field.type],
|
||||
operators: filteredOperators,
|
||||
operators: reducedOperators,
|
||||
props: {
|
||||
...field,
|
||||
},
|
||||
@@ -135,6 +135,26 @@ const WhereBuilder: React.FC<Props> = (props) => {
|
||||
or: [...conditions, ...paramsToKeep],
|
||||
}
|
||||
|
||||
const reducedQuery = {
|
||||
or: newWhereQuery.or.map((orCondition) => {
|
||||
const andConditions = (orCondition.and || []).map((andCondition) => {
|
||||
const reducedCondition = {}
|
||||
Object.entries(andCondition).forEach(([fieldName, fieldValue]) => {
|
||||
Object.entries(fieldValue).forEach(([operatorKey, operatorValue]) => {
|
||||
reducedCondition[fieldName] = {}
|
||||
reducedCondition[fieldName][operatorKey] = !operatorValue
|
||||
? undefined
|
||||
: operatorValue
|
||||
})
|
||||
})
|
||||
return reducedCondition
|
||||
})
|
||||
return {
|
||||
and: andConditions,
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
if (handleChange) handleChange(newWhereQuery as Where)
|
||||
|
||||
const hasExistingConditions =
|
||||
@@ -149,7 +169,7 @@ const WhereBuilder: React.FC<Props> = (props) => {
|
||||
{
|
||||
...currentParams,
|
||||
page: 1,
|
||||
where: newWhereQuery,
|
||||
where: reducedQuery,
|
||||
},
|
||||
{ addQueryPrefix: true },
|
||||
),
|
||||
|
||||
@@ -50,9 +50,15 @@ const reducer = (state: Where[], action: Action): Where[] => {
|
||||
)[0] || [undefined, undefined]
|
||||
|
||||
if (operator) {
|
||||
const existingOperator = Object.keys(existingCondition)[0]
|
||||
|
||||
const newValue =
|
||||
existingOperator && existingOperator !== operator
|
||||
? undefined
|
||||
: Object.values(existingCondition)[0]
|
||||
newState[orIndex].and[andIndex] = {
|
||||
[existingFieldName]: {
|
||||
[operator]: Object.values(existingCondition)[0],
|
||||
[operator]: newValue,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import qs from 'qs'
|
||||
import QueryString from 'qs'
|
||||
import React, { createContext, useCallback, useContext, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useParams } from 'react-router-dom'
|
||||
@@ -14,12 +15,13 @@ import { useAuth } from '../Auth'
|
||||
import { useConfig } from '../Config'
|
||||
import { useLocale } from '../Locale'
|
||||
import { usePreferences } from '../Preferences'
|
||||
import { UploadEditsProvider, useUploadEdits } from '../UploadEdits'
|
||||
|
||||
const Context = createContext({} as ContextType)
|
||||
|
||||
export const useDocumentInfo = (): ContextType => useContext(Context)
|
||||
|
||||
export const DocumentInfoProvider: React.FC<Props> = ({
|
||||
const DocumentInfo: React.FC<Props> = ({
|
||||
id: idFromProps,
|
||||
children,
|
||||
collection,
|
||||
@@ -37,6 +39,7 @@ export const DocumentInfoProvider: React.FC<Props> = ({
|
||||
const { i18n } = useTranslation()
|
||||
const { permissions } = useAuth()
|
||||
const { code } = useLocale()
|
||||
const { uploadEdits } = useUploadEdits()
|
||||
const [publishedDoc, setPublishedDoc] = useState<TypeWithID & TypeWithTimestamps>(null)
|
||||
const [versions, setVersions] = useState<PaginatedDocs<Version>>(null)
|
||||
const [unpublishedVersions, setUnpublishedVersions] = useState<PaginatedDocs<Version>>(null)
|
||||
@@ -256,16 +259,31 @@ export const DocumentInfoProvider: React.FC<Props> = ({
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
getVersions()
|
||||
void getVersions()
|
||||
}, [getVersions])
|
||||
|
||||
useEffect(() => {
|
||||
getDocPermissions()
|
||||
void getDocPermissions()
|
||||
}, [getDocPermissions])
|
||||
|
||||
const action: string = React.useMemo(() => {
|
||||
const docURL = `${baseURL}${pluralType === 'globals' ? `/globals` : ''}/${slug}${id ? `/${id}` : ''}`
|
||||
const params = {
|
||||
depth: 0,
|
||||
'fallback-locale': 'null',
|
||||
locale: code,
|
||||
uploadEdits: uploadEdits || undefined,
|
||||
}
|
||||
|
||||
return `${docURL}${QueryString.stringify(params, {
|
||||
addQueryPrefix: true,
|
||||
})}`
|
||||
}, [baseURL, code, pluralType, id, slug, uploadEdits])
|
||||
|
||||
const value: ContextType = {
|
||||
id,
|
||||
slug,
|
||||
action,
|
||||
collection,
|
||||
docPermissions,
|
||||
getDocPermissions,
|
||||
@@ -281,3 +299,11 @@ export const DocumentInfoProvider: React.FC<Props> = ({
|
||||
|
||||
return <Context.Provider value={value}>{children}</Context.Provider>
|
||||
}
|
||||
|
||||
export const DocumentInfoProvider: React.FC<Props> = (props) => {
|
||||
return (
|
||||
<UploadEditsProvider>
|
||||
<DocumentInfo {...props} />
|
||||
</UploadEditsProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ export type Version = TypeWithVersion<any>
|
||||
export type DocumentPermissions = CollectionPermission | GlobalPermission
|
||||
|
||||
export type ContextType = {
|
||||
action: string
|
||||
collection?: SanitizedCollectionConfig
|
||||
docPermissions: DocumentPermissions
|
||||
getDocPermissions: () => Promise<void>
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { createContext, useContext } from 'react'
|
||||
|
||||
import type { UploadEdits } from '../../views/collections/Edit/types'
|
||||
|
||||
export type QueryParamTypes = {
|
||||
depth: number
|
||||
'fallback-locale': string
|
||||
locale: string
|
||||
uploadEdits?: UploadEdits
|
||||
}
|
||||
export const FormQueryParams = createContext(
|
||||
{} as {
|
||||
formQueryParams: QueryParamTypes
|
||||
setFormQueryParams: (params: QueryParamTypes) => void
|
||||
},
|
||||
)
|
||||
|
||||
export const useFormQueryParams = (): {
|
||||
formQueryParams: QueryParamTypes
|
||||
setFormQueryParams: (params: QueryParamTypes) => void
|
||||
} => useContext(FormQueryParams)
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { UploadEdits } from '../../../../uploads/types'
|
||||
|
||||
export type UploadEditsContext = {
|
||||
updateUploadEdits: (edits: UploadEdits) => void
|
||||
uploadEdits: UploadEdits
|
||||
}
|
||||
|
||||
const Context = React.createContext<UploadEditsContext>({
|
||||
updateUploadEdits: undefined,
|
||||
uploadEdits: undefined,
|
||||
})
|
||||
|
||||
export const UploadEditsProvider = ({ children }) => {
|
||||
const [uploadEdits, setUploadEdits] = React.useState<UploadEdits>(undefined)
|
||||
|
||||
const updateUploadEdits = (edits: UploadEdits) => {
|
||||
setUploadEdits((prevEdits) => ({
|
||||
...(prevEdits || {}),
|
||||
...(edits || {}),
|
||||
}))
|
||||
}
|
||||
|
||||
return <Context.Provider value={{ updateUploadEdits, uploadEdits }}>{children}</Context.Provider>
|
||||
}
|
||||
|
||||
export const useUploadEdits = (): UploadEditsContext => React.useContext(Context)
|
||||
@@ -27,8 +27,14 @@ const GlobalView: React.FC<IndexProps> = (props) => {
|
||||
const { permissions, user } = useAuth()
|
||||
const [initialState, setInitialState] = useState<Fields>()
|
||||
const [updatedAt, setUpdatedAt] = useState<string>()
|
||||
const { docPermissions, getDocPermissions, getDocPreferences, getVersions, preferencesKey } =
|
||||
useDocumentInfo()
|
||||
const {
|
||||
action,
|
||||
docPermissions,
|
||||
getDocPermissions,
|
||||
getDocPreferences,
|
||||
getVersions,
|
||||
preferencesKey,
|
||||
} = useDocumentInfo()
|
||||
const { getPreference } = usePreferences()
|
||||
const { t } = useTranslation()
|
||||
const config = useConfig()
|
||||
@@ -49,8 +55,8 @@ const GlobalView: React.FC<IndexProps> = (props) => {
|
||||
updatedAt: json?.result?.updatedAt || new Date().toISOString(),
|
||||
})
|
||||
|
||||
getVersions()
|
||||
getDocPermissions()
|
||||
void getVersions()
|
||||
void getDocPermissions()
|
||||
setUpdatedAt(json?.result?.updatedAt)
|
||||
|
||||
const preferences = await getDocPreferences()
|
||||
@@ -109,7 +115,7 @@ const GlobalView: React.FC<IndexProps> = (props) => {
|
||||
setInitialState(state)
|
||||
}
|
||||
|
||||
if (dataToRender) awaitInitialState()
|
||||
if (dataToRender) void awaitInitialState()
|
||||
}, [
|
||||
dataToRender,
|
||||
fields,
|
||||
@@ -125,7 +131,7 @@ const GlobalView: React.FC<IndexProps> = (props) => {
|
||||
const isLoading = !initialState || !docPermissions || isLoadingData
|
||||
|
||||
const componentProps: DefaultGlobalViewProps = {
|
||||
action: `${serverURL}${api}/globals/${slug}?locale=${locale}&fallback-locale=null`,
|
||||
action,
|
||||
apiURL: `${serverURL}${api}/globals/${slug}?locale=${locale}${
|
||||
global.versions?.drafts ? '&draft=true' : ''
|
||||
}`,
|
||||
|
||||
@@ -9,16 +9,20 @@ export const DeviceContainer: React.FC<{
|
||||
const { children } = props
|
||||
|
||||
const deviceFrameRef = React.useRef<HTMLDivElement>(null)
|
||||
const outerFrameRef = React.useRef<HTMLDivElement>(null)
|
||||
|
||||
const { breakpoint, setMeasuredDeviceSize, size, zoom } = useLivePreviewContext()
|
||||
const { breakpoint, setMeasuredDeviceSize, size: desiredSize, zoom } = useLivePreviewContext()
|
||||
|
||||
// Keep an accurate measurement of the actual device size as it is truly rendered
|
||||
// This is helpful when `sizes` are non-number units like percentages, etc.
|
||||
const { size: measuredDeviceSize } = useResize(deviceFrameRef)
|
||||
const { size: measuredDeviceSize } = useResize(deviceFrameRef.current)
|
||||
const { size: outerFrameSize } = useResize(outerFrameRef.current)
|
||||
|
||||
let deviceIsLargerThanFrame: boolean = false
|
||||
|
||||
// Sync the measured device size with the context so that other components can use it
|
||||
// This happens from the bottom up so that as this component mounts and unmounts,
|
||||
// Its size is freshly populated again upon re-mounting, i.e. going from iframe->popup->iframe
|
||||
// its size is freshly populated again upon re-mounting, i.e. going from iframe->popup->iframe
|
||||
useEffect(() => {
|
||||
if (measuredDeviceSize) {
|
||||
setMeasuredDeviceSize(measuredDeviceSize)
|
||||
@@ -33,13 +37,34 @@ export const DeviceContainer: React.FC<{
|
||||
|
||||
if (
|
||||
typeof zoom === 'number' &&
|
||||
typeof size.width === 'number' &&
|
||||
typeof size.height === 'number'
|
||||
typeof desiredSize.width === 'number' &&
|
||||
typeof desiredSize.height === 'number' &&
|
||||
typeof measuredDeviceSize.width === 'number' &&
|
||||
typeof measuredDeviceSize.height === 'number'
|
||||
) {
|
||||
const scaledWidth = size.width / zoom
|
||||
const difference = scaledWidth - size.width
|
||||
x = `${difference / 2}px`
|
||||
margin = '0 auto'
|
||||
const scaledDesiredWidth = desiredSize.width / zoom
|
||||
const scaledDeviceWidth = measuredDeviceSize.width * zoom
|
||||
const scaledDeviceDifferencePixels = scaledDesiredWidth - desiredSize.width
|
||||
deviceIsLargerThanFrame = scaledDeviceWidth > outerFrameSize.width
|
||||
|
||||
if (deviceIsLargerThanFrame) {
|
||||
if (zoom > 1) {
|
||||
const differenceFromDeviceToFrame = measuredDeviceSize.width - outerFrameSize.width
|
||||
if (differenceFromDeviceToFrame < 0) x = `${differenceFromDeviceToFrame / 2}px`
|
||||
else x = '0'
|
||||
} else {
|
||||
x = '0'
|
||||
}
|
||||
} else {
|
||||
if (zoom >= 1) {
|
||||
x = `${scaledDeviceDifferencePixels / 2}px`
|
||||
} else {
|
||||
const differenceFromDeviceToFrame = outerFrameSize.width - scaledDeviceWidth
|
||||
x = `${differenceFromDeviceToFrame / 2}px`
|
||||
margin = '0'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,21 +72,29 @@ export const DeviceContainer: React.FC<{
|
||||
let height = zoom ? `${100 / zoom}%` : '100%'
|
||||
|
||||
if (breakpoint !== 'responsive') {
|
||||
width = `${size?.width / (typeof zoom === 'number' ? zoom : 1)}px`
|
||||
height = `${size?.height / (typeof zoom === 'number' ? zoom : 1)}px`
|
||||
width = `${desiredSize?.width / (typeof zoom === 'number' ? zoom : 1)}px`
|
||||
height = `${desiredSize?.height / (typeof zoom === 'number' ? zoom : 1)}px`
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={deviceFrameRef}
|
||||
ref={outerFrameRef}
|
||||
style={{
|
||||
height,
|
||||
margin,
|
||||
transform: `translate3d(${x}, 0, 0)`,
|
||||
width,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
<div
|
||||
ref={deviceFrameRef}
|
||||
style={{
|
||||
height,
|
||||
margin,
|
||||
transform: `translate3d(${x}, 0, 0)`,
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,17 +10,25 @@ import { formatDate } from '../../../../utilities/formatDate'
|
||||
import ReactSelect from '../../../elements/ReactSelect'
|
||||
import { fieldBaseClass } from '../../../forms/field-types/shared'
|
||||
import { useConfig } from '../../../utilities/Config'
|
||||
import { mostRecentVersionOption, publishedVersionOption } from '../shared'
|
||||
import { renderPill } from '../../Versions/cells/AutosaveCell'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'compare-version'
|
||||
|
||||
const maxResultsPerRequest = 10
|
||||
const maxResultsPerRequest = 100
|
||||
|
||||
const baseOptions = [mostRecentVersionOption]
|
||||
const baseOptions = []
|
||||
|
||||
const CompareVersion: React.FC<Props> = (props) => {
|
||||
const { baseURL, onChange, parentID, publishedDoc, value, versionID } = props
|
||||
const {
|
||||
baseURL,
|
||||
latestDraftVersion,
|
||||
latestPublishedVersion,
|
||||
onChange,
|
||||
parentID,
|
||||
value,
|
||||
versionID,
|
||||
} = props
|
||||
|
||||
const {
|
||||
admin: { dateFormat },
|
||||
@@ -70,30 +78,61 @@ const CompareVersion: React.FC<Props> = (props) => {
|
||||
if (response.ok) {
|
||||
const data: PaginatedDocs = await response.json()
|
||||
if (data.docs.length > 0) {
|
||||
setOptions((existingOptions) => [
|
||||
...existingOptions,
|
||||
...data.docs.map((doc) => ({
|
||||
label: formatDate(doc.updatedAt, dateFormat, i18n?.language),
|
||||
const versionInfo = {
|
||||
draft: {
|
||||
currentLabel: t('version:currentDraft'),
|
||||
latestVersion: latestDraftVersion,
|
||||
pillStyle: undefined,
|
||||
previousLabel: t('version:draft'),
|
||||
},
|
||||
published: {
|
||||
currentLabel: t('version:currentPublishedVersion'),
|
||||
latestVersion: latestPublishedVersion,
|
||||
pillStyle: 'success',
|
||||
previousLabel: t('version:previouslyPublished'),
|
||||
},
|
||||
}
|
||||
|
||||
const additionalOptions = data.docs.map((doc) => {
|
||||
const status = doc.version._status
|
||||
const { currentLabel, latestVersion, pillStyle, previousLabel } =
|
||||
versionInfo[status] || {}
|
||||
|
||||
return {
|
||||
label: (
|
||||
<div>
|
||||
{formatDate(doc.updatedAt, dateFormat, i18n?.language)}
|
||||
|
||||
{renderPill(doc, latestVersion, currentLabel, previousLabel, pillStyle)}
|
||||
</div>
|
||||
),
|
||||
value: doc.id,
|
||||
})),
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
setOptions(additionalOptions)
|
||||
setLastLoadedPage(data.page)
|
||||
}
|
||||
} else {
|
||||
setErrorLoading(t('error:unspecific'))
|
||||
}
|
||||
},
|
||||
[dateFormat, baseURL, parentID, versionID, t, i18n],
|
||||
[dateFormat, baseURL, parentID, versionID, t, i18n, latestDraftVersion, latestPublishedVersion],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
getResults({ lastLoadedPage: 1 })
|
||||
void getResults({ lastLoadedPage: 1 })
|
||||
}, [getResults])
|
||||
|
||||
const filteredOptions = options.filter(
|
||||
(option, index, self) => self.findIndex((t) => t.value === option.value) === index,
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (publishedDoc?._status === 'published')
|
||||
setOptions((currentOptions) => [publishedVersionOption, ...currentOptions])
|
||||
}, [publishedDoc])
|
||||
if (filteredOptions.length > 0 && !value) {
|
||||
onChange(filteredOptions[0])
|
||||
}
|
||||
}, [filteredOptions, value, onChange])
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -108,9 +147,9 @@ const CompareVersion: React.FC<Props> = (props) => {
|
||||
isSearchable={false}
|
||||
onChange={onChange}
|
||||
onMenuScrollToBottom={() => {
|
||||
getResults({ lastLoadedPage: lastLoadedPage + 1 })
|
||||
void getResults({ lastLoadedPage: lastLoadedPage + 1 })
|
||||
}}
|
||||
options={options}
|
||||
options={filteredOptions}
|
||||
placeholder={t('selectVersionToCompare')}
|
||||
value={value}
|
||||
/>
|
||||
|
||||
@@ -4,9 +4,10 @@ import type { CompareOption } from '../types'
|
||||
|
||||
export type Props = {
|
||||
baseURL: string
|
||||
latestDraftVersion?: string
|
||||
latestPublishedVersion?: string
|
||||
onChange: (val: CompareOption) => void
|
||||
parentID?: string
|
||||
publishedDoc: any
|
||||
value: CompareOption
|
||||
versionID: string
|
||||
}
|
||||
|
||||
@@ -6,11 +6,9 @@ import type { SanitizedCollectionConfig } from '../../../../../../../collections
|
||||
import type { RelationshipField } from '../../../../../../../fields/config/types'
|
||||
import type { Props } from '../types'
|
||||
|
||||
import {
|
||||
fieldAffectsData,
|
||||
fieldIsPresentationalOnly,
|
||||
} from '../../../../../../../fields/config/types'
|
||||
import { fieldAffectsData } from '../../../../../../../fields/config/types'
|
||||
import { getTranslation } from '../../../../../../../utilities/getTranslation'
|
||||
import { useUseTitleField } from '../../../../../../hooks/useUseAsTitle'
|
||||
import { useConfig } from '../../../../../utilities/Config'
|
||||
import { useLocale } from '../../../../../utilities/Locale'
|
||||
import Label from '../../Label'
|
||||
@@ -49,9 +47,10 @@ const generateLabelFromValue = (
|
||||
|
||||
if (relatedCollection) {
|
||||
const useAsTitle = relatedCollection?.admin?.useAsTitle
|
||||
const useAsTitleField = relatedCollection.fields.find(
|
||||
(f) => fieldAffectsData(f) && !fieldIsPresentationalOnly(f) && f.name === useAsTitle,
|
||||
)
|
||||
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const useAsTitleField = useUseTitleField(relatedCollection)
|
||||
|
||||
let titleFieldIsLocalized = false
|
||||
|
||||
if (useAsTitleField && fieldAffectsData(useAsTitleField))
|
||||
|
||||
@@ -27,7 +27,6 @@ import fieldComponents from './RenderFieldsToDiff/fields'
|
||||
import Restore from './Restore'
|
||||
import SelectLocales from './SelectLocales'
|
||||
import './index.scss'
|
||||
import { mostRecentVersionOption } from './shared'
|
||||
|
||||
const baseClass = 'view-version'
|
||||
|
||||
@@ -46,11 +45,11 @@ const VersionView: React.FC<Props> = ({ collection, global }) => {
|
||||
params: { id, versionID },
|
||||
} = useRouteMatch<{ id?: string; versionID: string }>()
|
||||
|
||||
const [compareValue, setCompareValue] = useState<CompareOption>(mostRecentVersionOption)
|
||||
const [compareValue, setCompareValue] = useState<CompareOption>()
|
||||
const [localeOptions] = useState<Option[]>(() => {
|
||||
if (localization && localization?.locales) {
|
||||
return localization.locales.map(({ code, label }) => ({
|
||||
label: label,
|
||||
label,
|
||||
value: code,
|
||||
}))
|
||||
}
|
||||
@@ -70,6 +69,8 @@ const VersionView: React.FC<Props> = ({ collection, global }) => {
|
||||
let compareBaseURL: string
|
||||
let slug: string
|
||||
let parentID: string
|
||||
const [latestDraftVersion, setLatestDraftVersion] = useState(undefined)
|
||||
const [latestPublishedVersion, setLatestPublishedVersion] = useState(undefined)
|
||||
|
||||
if (collection) {
|
||||
;({ slug } = collection)
|
||||
@@ -92,10 +93,7 @@ const VersionView: React.FC<Props> = ({ collection, global }) => {
|
||||
fieldPermissions = permissions.globals[global.slug].fields
|
||||
}
|
||||
|
||||
const compareFetchURL =
|
||||
compareValue?.value === 'mostRecent' || compareValue?.value === 'published'
|
||||
? originalDocFetchURL
|
||||
: `${compareBaseURL}/${compareValue.value}`
|
||||
const compareFetchURL = compareValue?.value && `${compareBaseURL}/${compareValue.value}`
|
||||
|
||||
const [{ data: doc, isError }] = usePayloadAPI(versionFetchURL, {
|
||||
initialParams: { depth: 1, locale: '*' },
|
||||
@@ -110,6 +108,39 @@ const VersionView: React.FC<Props> = ({ collection, global }) => {
|
||||
initialParams: { depth: 1, draft: 'true', locale: '*' },
|
||||
})
|
||||
|
||||
const sharedParams = (status) => {
|
||||
return {
|
||||
depth: 0,
|
||||
limit: 1,
|
||||
sort: '-updatedAt',
|
||||
where: {
|
||||
'version._status': {
|
||||
equals: status,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const [{ data: draft }] = usePayloadAPI(compareBaseURL, {
|
||||
initialParams: { ...sharedParams('draft') },
|
||||
})
|
||||
|
||||
const [{ data: published }] = usePayloadAPI(compareBaseURL, {
|
||||
initialParams: { ...sharedParams('published') },
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const formattedPublished = published?.docs?.length > 0 && published?.docs[0]
|
||||
const formattedDraft = draft?.docs?.length > 0 && draft?.docs[0]
|
||||
|
||||
if (!formattedPublished || !formattedDraft) return
|
||||
|
||||
const publishedNewerThanDraft = formattedPublished?.updatedAt > formattedDraft?.updatedAt
|
||||
|
||||
setLatestDraftVersion(publishedNewerThanDraft ? undefined : formattedDraft?.id)
|
||||
setLatestPublishedVersion(formattedPublished?.id)
|
||||
}, [draft, published])
|
||||
|
||||
useEffect(() => {
|
||||
let nav: StepNavItem[] = []
|
||||
|
||||
@@ -192,18 +223,18 @@ const VersionView: React.FC<Props> = ({ collection, global }) => {
|
||||
|
||||
let metaTitle: string
|
||||
let metaDesc: string
|
||||
const formattedCreatedAt = doc?.createdAt
|
||||
? formatDate(doc.createdAt, dateFormat, i18n?.language)
|
||||
const versionCreatedAt = doc?.updatedAt
|
||||
? formatDate(doc.updatedAt, dateFormat, i18n?.language)
|
||||
: ''
|
||||
|
||||
if (collection) {
|
||||
const useAsTitle = collection?.admin?.useAsTitle || 'id'
|
||||
metaTitle = `${t('version')} - ${formattedCreatedAt} - ${doc[useAsTitle]} - ${entityLabel}`
|
||||
metaTitle = `${t('version')} - ${versionCreatedAt} - ${doc[useAsTitle]} - ${entityLabel}`
|
||||
metaDesc = t('viewingVersion', { documentTitle: doc[useAsTitle], entityLabel })
|
||||
}
|
||||
|
||||
if (global) {
|
||||
metaTitle = `${t('version')} - ${formattedCreatedAt} - ${entityLabel}`
|
||||
metaTitle = `${t('version')} - ${versionCreatedAt} - ${entityLabel}`
|
||||
metaDesc = t('viewingVersionGlobal', { entityLabel })
|
||||
}
|
||||
|
||||
@@ -234,14 +265,14 @@ const VersionView: React.FC<Props> = ({ collection, global }) => {
|
||||
})}
|
||||
</p>
|
||||
<header className={`${baseClass}__header`}>
|
||||
<h2>{formattedCreatedAt}</h2>
|
||||
<h2>{versionCreatedAt}</h2>
|
||||
{canUpdate && (
|
||||
<Restore
|
||||
className={`${baseClass}__restore`}
|
||||
collection={collection}
|
||||
global={global}
|
||||
originalDocID={id}
|
||||
versionDate={formattedCreatedAt}
|
||||
versionDate={versionCreatedAt}
|
||||
versionID={versionID}
|
||||
/>
|
||||
)}
|
||||
@@ -250,9 +281,10 @@ const VersionView: React.FC<Props> = ({ collection, global }) => {
|
||||
<div className={`${baseClass}__controls`}>
|
||||
<CompareVersion
|
||||
baseURL={compareBaseURL}
|
||||
latestDraftVersion={latestDraftVersion}
|
||||
latestPublishedVersion={latestPublishedVersion}
|
||||
onChange={setCompareValue}
|
||||
parentID={parentID}
|
||||
publishedDoc={publishedDoc}
|
||||
value={compareValue}
|
||||
versionID={versionID}
|
||||
/>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
export const mostRecentVersionOption = {
|
||||
label: 'Most recent',
|
||||
value: 'mostRecent',
|
||||
}
|
||||
|
||||
export const publishedVersionOption = {
|
||||
label: 'Most recently published',
|
||||
value: 'published',
|
||||
}
|
||||
@@ -17,7 +17,17 @@ import './index.scss'
|
||||
const baseClass = 'versions'
|
||||
|
||||
export const DefaultVersionsView: React.FC<Props> = (props) => {
|
||||
const { id, collection, data, entityLabel, global, isLoadingVersions, versionsData } = props
|
||||
const {
|
||||
id,
|
||||
collection,
|
||||
data,
|
||||
entityLabel,
|
||||
global,
|
||||
isLoadingVersions,
|
||||
latestDraftVersion,
|
||||
latestPublishedVersion,
|
||||
versionsData,
|
||||
} = props
|
||||
|
||||
const { t } = useTranslation('version')
|
||||
|
||||
@@ -58,7 +68,13 @@ export const DefaultVersionsView: React.FC<Props> = (props) => {
|
||||
})}
|
||||
</div> */}
|
||||
<Table
|
||||
columns={buildVersionColumns(collection, global, t)}
|
||||
columns={buildVersionColumns(
|
||||
collection,
|
||||
global,
|
||||
t,
|
||||
latestDraftVersion,
|
||||
latestPublishedVersion,
|
||||
)}
|
||||
data={versionsData?.docs}
|
||||
/>
|
||||
<div className={`${baseClass}__page-controls`}>
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
'use client'
|
||||
import React, { Fragment } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { Pill } from '../../../'
|
||||
|
||||
type AutosaveCellProps = {
|
||||
latestDraftVersion?: string
|
||||
latestPublishedVersion?: string
|
||||
rowData: any
|
||||
}
|
||||
|
||||
export const renderPill = (data, latestVersion, currentLabel, previousLabel, pillStyle) => {
|
||||
console.log(data.id === latestVersion)
|
||||
return (
|
||||
<React.Fragment>
|
||||
{data?.id === latestVersion ? (
|
||||
<Pill pillStyle={pillStyle}>{currentLabel}</Pill>
|
||||
) : (
|
||||
<Pill>{previousLabel}</Pill>
|
||||
)}
|
||||
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
export const AutosaveCell: React.FC<AutosaveCellProps> = ({
|
||||
latestDraftVersion,
|
||||
latestPublishedVersion,
|
||||
rowData,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const status = rowData?.version._status
|
||||
|
||||
const versionInfo = {
|
||||
draft: {
|
||||
currentLabel: t('version:currentDraft'),
|
||||
latestVersion: latestDraftVersion,
|
||||
pillStyle: undefined,
|
||||
previousLabel: t('version:draft'),
|
||||
},
|
||||
published: {
|
||||
currentLabel: t('version:currentPublishedVersion'),
|
||||
latestVersion: latestPublishedVersion,
|
||||
pillStyle: 'success',
|
||||
previousLabel: t('version:previouslyPublished'),
|
||||
},
|
||||
}
|
||||
|
||||
const { currentLabel, latestVersion, pillStyle, previousLabel } = versionInfo[status] || {}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{rowData?.autosave && (
|
||||
<React.Fragment>
|
||||
<Pill>{t('version:autosave')}</Pill>
|
||||
|
||||
</React.Fragment>
|
||||
)}
|
||||
{status && renderPill(rowData, latestVersion, currentLabel, previousLabel, pillStyle)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -8,10 +8,10 @@ import type { SanitizedCollectionConfig } from '../../../../collections/config/t
|
||||
import type { SanitizedGlobalConfig } from '../../../../globals/config/types'
|
||||
import type { Column } from '../../elements/Table/types'
|
||||
|
||||
import { Pill } from '../..'
|
||||
import { formatDate } from '../../../utilities/formatDate'
|
||||
import SortColumn from '../../elements/SortColumn'
|
||||
import { useConfig } from '../../utilities/Config'
|
||||
import { AutosaveCell } from './cells/AutosaveCell'
|
||||
|
||||
type CreatedAtCellProps = {
|
||||
collection?: SanitizedCollectionConfig
|
||||
@@ -45,6 +45,8 @@ export const buildVersionColumns = (
|
||||
collection: SanitizedCollectionConfig,
|
||||
global: SanitizedGlobalConfig,
|
||||
t: TFunction,
|
||||
latestDraftVersion?: string,
|
||||
latestPublishedVersion?: string,
|
||||
): Column[] => [
|
||||
{
|
||||
name: '',
|
||||
@@ -73,24 +75,16 @@ export const buildVersionColumns = (
|
||||
accessor: 'autosave',
|
||||
active: true,
|
||||
components: {
|
||||
Heading: <SortColumn disable label={t('type')} name="autosave" />,
|
||||
renderCell: (row) => (
|
||||
<TextCell>
|
||||
{row?.autosave && (
|
||||
<React.Fragment>
|
||||
<Pill>{t('autosave')}</Pill>
|
||||
|
||||
</React.Fragment>
|
||||
)}
|
||||
{row?.version._status === 'published' && (
|
||||
<React.Fragment>
|
||||
<Pill pillStyle="success">{t('published')}</Pill>
|
||||
|
||||
</React.Fragment>
|
||||
)}
|
||||
{row?.version._status === 'draft' && <Pill>{t('draft')}</Pill>}
|
||||
</TextCell>
|
||||
),
|
||||
Heading: <SortColumn disable label={t('status')} name="autosave" />,
|
||||
renderCell: (row) => {
|
||||
return (
|
||||
<AutosaveCell
|
||||
latestDraftVersion={latestDraftVersion}
|
||||
latestPublishedVersion={latestPublishedVersion}
|
||||
rowData={row}
|
||||
/>
|
||||
)
|
||||
},
|
||||
},
|
||||
label: '',
|
||||
},
|
||||
|
||||
@@ -36,6 +36,8 @@ const VersionsView: React.FC<IndexProps> = (props) => {
|
||||
let entityLabel: string
|
||||
let slug: string
|
||||
let editURL: string
|
||||
const [latestDraftVersion, setLatestDraftVersion] = useState(undefined)
|
||||
const [latestPublishedVersion, setLatestPublishedVersion] = useState(undefined)
|
||||
|
||||
if (collection) {
|
||||
;({ slug } = collection)
|
||||
@@ -92,6 +94,38 @@ const VersionsView: React.FC<IndexProps> = (props) => {
|
||||
const [{ data: versionsData, isLoading: isLoadingVersions }, { setParams }] =
|
||||
usePayloadAPI(fetchURL)
|
||||
|
||||
const sharedParams = (status) => {
|
||||
return {
|
||||
depth: 0,
|
||||
limit: 1,
|
||||
sort: '-updatedAt',
|
||||
where: {
|
||||
'version._status': {
|
||||
equals: status,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const [{ data: draft }] = usePayloadAPI(fetchURL, {
|
||||
initialParams: { ...sharedParams('draft') },
|
||||
})
|
||||
|
||||
const [{ data: published }] = usePayloadAPI(fetchURL, {
|
||||
initialParams: { ...sharedParams('published') },
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const formattedPublished = published?.docs?.length > 0 && published?.docs[0]
|
||||
const formattedDraft = draft?.docs?.length > 0 && draft?.docs[0]
|
||||
|
||||
if (!formattedPublished || !formattedDraft) return
|
||||
|
||||
const publishedNewerThanDraft = formattedPublished?.updatedAt > formattedDraft?.updatedAt
|
||||
setLatestDraftVersion(publishedNewerThanDraft ? undefined : formattedDraft?.id)
|
||||
setLatestPublishedVersion(formattedPublished?.id)
|
||||
}, [draft, published])
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
depth: 1,
|
||||
@@ -158,6 +192,8 @@ const VersionsView: React.FC<IndexProps> = (props) => {
|
||||
global,
|
||||
isLoading,
|
||||
isLoadingVersions,
|
||||
latestDraftVersion,
|
||||
latestPublishedVersion,
|
||||
user,
|
||||
versionsData,
|
||||
}}
|
||||
|
||||
@@ -17,5 +17,7 @@ export type Props = IndexProps & {
|
||||
id: string
|
||||
isLoading: boolean
|
||||
isLoadingVersions: boolean
|
||||
latestDraftVersion?: string
|
||||
latestPublishedVersion?: string
|
||||
versionsData: PaginatedDocs<Version>
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ const DefaultEditView: React.FC<DefaultEditViewProps> = (props) => {
|
||||
} = props
|
||||
|
||||
const { setViewActions } = useActions()
|
||||
|
||||
const { reportUpdate } = useDocumentEvents()
|
||||
|
||||
const { auth } = collection
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import queryString from 'qs'
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useHistory, useRouteMatch } from 'react-router-dom'
|
||||
|
||||
import type { CollectionPermission } from '../../../../../auth'
|
||||
import type { Fields } from '../../../forms/Form/types'
|
||||
import type { QueryParamTypes } from '../../../utilities/FormQueryParams'
|
||||
import type { DefaultEditViewProps } from './Default'
|
||||
import type { IndexProps } from './types'
|
||||
|
||||
@@ -16,7 +14,6 @@ import { useAuth } from '../../../utilities/Auth'
|
||||
import { useConfig } from '../../../utilities/Config'
|
||||
import { useDocumentInfo } from '../../../utilities/DocumentInfo'
|
||||
import { EditDepthContext } from '../../../utilities/EditDepth'
|
||||
import { FormQueryParams } from '../../../utilities/FormQueryParams'
|
||||
import { useLocale } from '../../../utilities/Locale'
|
||||
import RenderCustomComponent from '../../../utilities/RenderCustomComponent'
|
||||
import NotFound from '../../NotFound'
|
||||
@@ -32,15 +29,6 @@ const EditView: React.FC<IndexProps> = (props) => {
|
||||
const [fields] = useState(() => formatFields(incomingCollection, isEditing))
|
||||
const [collection] = useState(() => ({ ...incomingCollection, fields }))
|
||||
const [redirect, setRedirect] = useState<string>()
|
||||
const [formQueryParams, setFormQueryParams] = useState<QueryParamTypes>({
|
||||
depth: 0,
|
||||
'fallback-locale': 'null',
|
||||
locale: '',
|
||||
uploadEdits: undefined,
|
||||
})
|
||||
|
||||
const formattedQueryParams = queryString.stringify(formQueryParams)
|
||||
|
||||
const { code: locale } = useLocale()
|
||||
|
||||
const config = useConfig()
|
||||
@@ -56,7 +44,8 @@ const EditView: React.FC<IndexProps> = (props) => {
|
||||
const [updatedAt, setUpdatedAt] = useState<string>()
|
||||
const { permissions, user } = useAuth()
|
||||
const userRef = useRef(user)
|
||||
const { docPermissions, getDocPermissions, getDocPreferences, getVersions } = useDocumentInfo()
|
||||
const { action, docPermissions, getDocPermissions, getDocPreferences, getVersions } =
|
||||
useDocumentInfo()
|
||||
const { t } = useTranslation('general')
|
||||
|
||||
const [{ data, isError, isLoading: isLoadingData }, { refetchData }] = usePayloadAPI(
|
||||
@@ -87,20 +76,16 @@ const EditView: React.FC<IndexProps> = (props) => {
|
||||
)
|
||||
|
||||
const onSave = useCallback(
|
||||
async (json: { doc }) => {
|
||||
getVersions()
|
||||
getDocPermissions()
|
||||
(json: { doc }) => {
|
||||
void getVersions()
|
||||
void getDocPermissions()
|
||||
setUpdatedAt(json?.doc?.updatedAt)
|
||||
if (!isEditing) {
|
||||
setRedirect(`${admin}/collections/${collection.slug}/${json?.doc?.id}`)
|
||||
} else {
|
||||
buildState(json.doc, {
|
||||
void buildState(json.doc, {
|
||||
fieldSchema: collection.fields,
|
||||
})
|
||||
setFormQueryParams((params) => ({
|
||||
...params,
|
||||
uploadEdits: undefined,
|
||||
}))
|
||||
}
|
||||
},
|
||||
[admin, getVersions, isEditing, buildState, getDocPermissions, collection],
|
||||
@@ -108,15 +93,15 @@ const EditView: React.FC<IndexProps> = (props) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (fields && (isEditing ? data : true)) {
|
||||
const awaitInternalState = async () => {
|
||||
const awaitInternalState = () => {
|
||||
setUpdatedAt(data?.updatedAt)
|
||||
buildState(data, {
|
||||
void buildState(data, {
|
||||
fieldSchema: fields,
|
||||
operation: isEditing ? 'update' : 'create',
|
||||
})
|
||||
}
|
||||
|
||||
awaitInternalState()
|
||||
void awaitInternalState()
|
||||
}
|
||||
}, [isEditing, data, buildState, fields])
|
||||
|
||||
@@ -126,13 +111,6 @@ const EditView: React.FC<IndexProps> = (props) => {
|
||||
}
|
||||
}, [history, redirect])
|
||||
|
||||
useEffect(() => {
|
||||
setFormQueryParams((params) => ({
|
||||
...params,
|
||||
locale,
|
||||
}))
|
||||
}, [locale])
|
||||
|
||||
useEffect(() => {
|
||||
if (history.location.state?.refetchDocumentData) {
|
||||
void refetchData()
|
||||
@@ -147,10 +125,6 @@ const EditView: React.FC<IndexProps> = (props) => {
|
||||
collection.versions.drafts ? '&draft=true' : ''
|
||||
}`
|
||||
|
||||
const action = `${serverURL}${api}/${collectionSlug}${
|
||||
isEditing ? `/${id}` : ''
|
||||
}?${formattedQueryParams}`
|
||||
|
||||
const hasSavePermission =
|
||||
(isEditing && docPermissions?.update?.permission) ||
|
||||
(!isEditing && (docPermissions as CollectionPermission)?.create?.permission)
|
||||
@@ -177,13 +151,11 @@ const EditView: React.FC<IndexProps> = (props) => {
|
||||
|
||||
return (
|
||||
<EditDepthContext.Provider value={1}>
|
||||
<FormQueryParams.Provider value={{ formQueryParams, setFormQueryParams }}>
|
||||
<RenderCustomComponent
|
||||
CustomComponent={typeof Edit === 'function' ? Edit : undefined}
|
||||
DefaultComponent={DefaultEdit}
|
||||
componentProps={componentProps}
|
||||
/>
|
||||
</FormQueryParams.Provider>
|
||||
<RenderCustomComponent
|
||||
CustomComponent={typeof Edit === 'function' ? Edit : undefined}
|
||||
DefaultComponent={DefaultEdit}
|
||||
componentProps={componentProps}
|
||||
/>
|
||||
</EditDepthContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,15 +11,13 @@ interface Resize {
|
||||
size?: Size
|
||||
}
|
||||
|
||||
export const useResize = (ref: React.MutableRefObject<HTMLElement>): Resize => {
|
||||
export const useResize = (element: HTMLElement): Resize => {
|
||||
const [size, setSize] = useState<Size>()
|
||||
|
||||
useEffect(() => {
|
||||
let observer: any // eslint-disable-line
|
||||
|
||||
const { current: currentRef } = ref
|
||||
|
||||
if (currentRef) {
|
||||
if (element) {
|
||||
observer = new ResizeObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
const {
|
||||
@@ -52,15 +50,15 @@ export const useResize = (ref: React.MutableRefObject<HTMLElement>): Resize => {
|
||||
})
|
||||
})
|
||||
|
||||
observer.observe(currentRef)
|
||||
observer.observe(element)
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (observer) {
|
||||
observer.unobserve(currentRef)
|
||||
observer.unobserve(element)
|
||||
}
|
||||
}
|
||||
}, [ref])
|
||||
}, [element])
|
||||
|
||||
return {
|
||||
size,
|
||||
|
||||
@@ -8,17 +8,32 @@ import findOne from '../../operations/findOne'
|
||||
|
||||
export default function findOneResolver(globalConfig: SanitizedGlobalConfig): Document {
|
||||
return async function resolver(_, args, context) {
|
||||
if (args.locale) context.req.locale = args.locale
|
||||
if (args.fallbackLocale) context.req.fallbackLocale = args.fallbackLocale
|
||||
let { req } = context
|
||||
const locale = req.locale
|
||||
const fallbackLocale = req.fallbackLocale
|
||||
req = isolateObjectProperty(req, 'locale')
|
||||
req = isolateObjectProperty(req, 'fallbackLocale')
|
||||
req.locale = args.locale || locale
|
||||
req.fallbackLocale = args.fallbackLocale || fallbackLocale
|
||||
|
||||
const { slug } = globalConfig
|
||||
if (!req.query) req.query = {}
|
||||
|
||||
const draft: boolean =
|
||||
args.draft ?? req.query?.draft === 'false'
|
||||
? false
|
||||
: req.query?.draft === 'true'
|
||||
? true
|
||||
: undefined
|
||||
if (typeof draft === 'boolean') req.query.draft = String(draft)
|
||||
|
||||
context.req = req
|
||||
|
||||
const options = {
|
||||
slug: globalConfig.slug,
|
||||
depth: 0,
|
||||
draft: args.draft,
|
||||
globalConfig,
|
||||
req: isolateObjectProperty(context.req, 'transactionID'),
|
||||
slug,
|
||||
req: isolateObjectProperty(req, 'transactionID'),
|
||||
}
|
||||
|
||||
const result = await findOne(options)
|
||||
|
||||
@@ -24,15 +24,21 @@ export type Resolver = (
|
||||
|
||||
export default function findVersionByIDResolver(globalConfig: SanitizedGlobalConfig): Resolver {
|
||||
return async function resolver(_, args, context) {
|
||||
if (args.locale) context.req.locale = args.locale
|
||||
if (args.fallbackLocale) context.req.fallbackLocale = args.fallbackLocale
|
||||
let { req } = context
|
||||
const locale = req.locale
|
||||
const fallbackLocale = req.fallbackLocale
|
||||
req = isolateObjectProperty(req, 'locale')
|
||||
req = isolateObjectProperty(req, 'fallbackLocale')
|
||||
req.locale = args.locale || locale
|
||||
req.fallbackLocale = args.fallbackLocale || fallbackLocale
|
||||
|
||||
context.req = req
|
||||
|
||||
const options = {
|
||||
id: args.id,
|
||||
depth: 0,
|
||||
draft: args.draft,
|
||||
globalConfig,
|
||||
req: isolateObjectProperty<PayloadRequest>(context.req, 'transactionID'),
|
||||
req: isolateObjectProperty<PayloadRequest>(req, 'transactionID'),
|
||||
}
|
||||
|
||||
const result = await findVersionByID(options)
|
||||
|
||||
@@ -26,18 +26,32 @@ export default function updateResolver<TSlug extends keyof GeneratedTypes['globa
|
||||
globalConfig: SanitizedGlobalConfig,
|
||||
): Resolver<TSlug> {
|
||||
return async function resolver(_, args, context) {
|
||||
if (args.locale) context.req.locale = args.locale
|
||||
if (args.fallbackLocale) context.req.fallbackLocale = args.fallbackLocale
|
||||
let { req } = context
|
||||
const locale = req.locale
|
||||
const fallbackLocale = req.fallbackLocale
|
||||
req = isolateObjectProperty<PayloadRequest>(req, 'locale')
|
||||
req = isolateObjectProperty<PayloadRequest>(req, 'fallbackLocale')
|
||||
req.locale = args.locale || locale
|
||||
req.fallbackLocale = args.fallbackLocale || fallbackLocale
|
||||
if (!req.query) req.query = {}
|
||||
|
||||
const { slug } = globalConfig
|
||||
const draft: boolean =
|
||||
args.draft ?? req.query?.draft === 'false'
|
||||
? false
|
||||
: req.query?.draft === 'true'
|
||||
? true
|
||||
: undefined
|
||||
if (typeof draft === 'boolean') req.query.draft = String(draft)
|
||||
|
||||
context.req = req
|
||||
|
||||
const options = {
|
||||
slug: globalConfig.slug,
|
||||
data: args.data,
|
||||
depth: 0,
|
||||
draft: args.draft,
|
||||
globalConfig,
|
||||
req: isolateObjectProperty<PayloadRequest>(context.req, 'transactionID'),
|
||||
slug,
|
||||
req: isolateObjectProperty<PayloadRequest>(req, 'transactionID'),
|
||||
}
|
||||
|
||||
const result = await update<TSlug>(options)
|
||||
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "تأكيد إلغاء النّشر",
|
||||
"confirmVersionRestoration": "تأكيد إستعادة النّسخة",
|
||||
"currentDocumentStatus": "المستند {{docStatus}} الحالي",
|
||||
"currentDraft": "مسودة حالية",
|
||||
"currentPublishedVersion": "النسخة المنشورة الحالية",
|
||||
"draft": "مسودّة",
|
||||
"draftSavedSuccessfully": "تمّ حفظ المسودّة بنجاح.",
|
||||
"lastSavedAgo": "تم الحفظ آخر مرة قبل {{distance}}",
|
||||
"noFurtherVersionsFound": "لم يتمّ العثور على نسخات أخرى",
|
||||
"noRowsFound": "لم يتمّ العثور على {{label}}",
|
||||
"preview": "معاينة",
|
||||
"previouslyPublished": "نشر سابقا",
|
||||
"problemRestoringVersion": "حدث خطأ في استعادة هذه النّسخة",
|
||||
"publish": "نشر",
|
||||
"publishChanges": "نشر التّغييرات",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "يتمّ استعراض النُّسَخ ل {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "يتمّ استعراض النُّسَخ للاعداد العامّ {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Dərcdən çıxartmağı təsdiq edin",
|
||||
"confirmVersionRestoration": "Versiyanın bərpasını təsdiq edin",
|
||||
"currentDocumentStatus": "Cari {{docStatus}} sənədi",
|
||||
"currentDraft": "Cari Müsvedde",
|
||||
"currentPublishedVersion": "Hazırki Nəşr Versiyası",
|
||||
"draft": "Qaralama",
|
||||
"draftSavedSuccessfully": "Qaralama uğurla yadda saxlandı.",
|
||||
"lastSavedAgo": "{{distance}} əvvəl son yadda saxlanıldı",
|
||||
"noFurtherVersionsFound": "Başqa versiyalar tapılmadı",
|
||||
"noRowsFound": "Heç bir {{label}} tapılmadı",
|
||||
"preview": "Öncədən baxış",
|
||||
"previouslyPublished": "Əvvəlki nəşr olunmuş",
|
||||
"problemRestoringVersion": "Bu versiyanın bərpasında problem yaşandı",
|
||||
"publish": "Dərc et",
|
||||
"publishChanges": "Dəyişiklikləri dərc et",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "{{entityLabel}} {{documentTitle}} üçün versiyaları göstərir",
|
||||
"viewingVersionsGlobal": "Qlobal {{entityLabel}} üçün versiyaları göstərir"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Потвърди скриване",
|
||||
"confirmVersionRestoration": "Потвърди възстановяване на версия",
|
||||
"currentDocumentStatus": "Сегашен статус на документа: {{docStatus}}",
|
||||
"currentDraft": "Текуща версия",
|
||||
"currentPublishedVersion": "Текуща публикувана версия",
|
||||
"draft": "Чернова",
|
||||
"draftSavedSuccessfully": "Чернова запазена успешно.",
|
||||
"lastSavedAgo": "последно запазено преди {{distance}}",
|
||||
"noFurtherVersionsFound": "Не са открити повече версии",
|
||||
"noRowsFound": "Не е открит {{label}}",
|
||||
"preview": "Предварителен преглед",
|
||||
"previouslyPublished": "Предишно публикувано",
|
||||
"problemRestoringVersion": "Имаше проблем при възстановяването на тази версия",
|
||||
"publish": "Публикувай",
|
||||
"publishChanges": "Публикувай промените",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Гледане на версии за {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "Гледане на версии за глобалния документ {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Potvrdit zrušení publikování",
|
||||
"confirmVersionRestoration": "Potvrdit obnovení verze",
|
||||
"currentDocumentStatus": "Současný {{docStatus}} dokument",
|
||||
"currentDraft": "Aktuální koncept",
|
||||
"currentPublishedVersion": "Aktuálně publikovaná verze",
|
||||
"draft": "Koncept",
|
||||
"draftSavedSuccessfully": "Koncept úspěšně uložen.",
|
||||
"lastSavedAgo": "Naposledy uloženo před {{distance}}",
|
||||
"noFurtherVersionsFound": "Nenalezeny další verze",
|
||||
"noRowsFound": "Nenalezen {{label}}",
|
||||
"preview": "Náhled",
|
||||
"previouslyPublished": "Dříve publikováno",
|
||||
"problemRestoringVersion": "Při obnovování této verze došlo k problému",
|
||||
"publish": "Publikovat",
|
||||
"publishChanges": "Publikovat změny",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Zobrazuji verze pro {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "Zobrazuji verze pro globální {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Setzen auf Entwurf bestätigen",
|
||||
"confirmVersionRestoration": " Wiederherstellung der Version bestätigen",
|
||||
"currentDocumentStatus": "Aktueller Dokumentenstatus: {{docStatus}}",
|
||||
"currentDraft": "Aktueller Entwurf",
|
||||
"currentPublishedVersion": "Aktuell veröffentlichte Version",
|
||||
"draft": "Entwurf",
|
||||
"draftSavedSuccessfully": "Entwurf erfolgreich gespeichert.",
|
||||
"lastSavedAgo": "Zuletzt vor {{distance}} gespeichert",
|
||||
"noFurtherVersionsFound": "Keine weiteren Versionen vorhanden",
|
||||
"noRowsFound": "Kein {{label}} gefunden",
|
||||
"preview": "Vorschau",
|
||||
"previouslyPublished": "Zuvor veröffentlicht",
|
||||
"problemRestoringVersion": "Es gab ein Problem bei der Wiederherstellung dieser Version",
|
||||
"publish": "Veröffentlichen",
|
||||
"publishChanges": "Änderungen veröffentlichen",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Betrachte Versionen für {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "`Betrachte Versionen für das Globale Dokument {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Confirm unpublish",
|
||||
"confirmVersionRestoration": "Confirm version Restoration",
|
||||
"currentDocumentStatus": "Current {{docStatus}} document",
|
||||
"currentDraft": "Current Draft",
|
||||
"currentPublishedVersion": "Current Published Version",
|
||||
"draft": "Draft",
|
||||
"draftSavedSuccessfully": "Draft saved successfully.",
|
||||
"lastSavedAgo": "Last saved {{distance}} ago",
|
||||
"noFurtherVersionsFound": "No further versions found",
|
||||
"noRowsFound": "No {{label}} found",
|
||||
"preview": "Preview",
|
||||
"previouslyPublished": "Previously Published",
|
||||
"problemRestoringVersion": "There was a problem restoring this version",
|
||||
"publish": "Publish",
|
||||
"publishChanges": "Publish changes",
|
||||
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Confirmar despublicado",
|
||||
"confirmVersionRestoration": "Confirmar restauración de versión",
|
||||
"currentDocumentStatus": "Documento {{docStatus}} actual",
|
||||
"currentDraft": "Borrador Actual",
|
||||
"currentPublishedVersion": "Versión Publicada Actualmente",
|
||||
"draft": "Borrador",
|
||||
"draftSavedSuccessfully": "Borrador guardado con éxito.",
|
||||
"lastSavedAgo": "Guardado por última vez hace {{distance}}",
|
||||
"noFurtherVersionsFound": "No se encontraron más versiones",
|
||||
"noRowsFound": "No encontramos {{label}}",
|
||||
"preview": "Previsualizar",
|
||||
"previouslyPublished": "Publicado anteriormente",
|
||||
"problemRestoringVersion": "Ocurrió un problema al restaurar esta versión",
|
||||
"publish": "Publicar",
|
||||
"publishChanges": "Publicar cambios",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Viendo versiones para {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "Viendo versiones para el global {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "تأیید لغو انتشار",
|
||||
"confirmVersionRestoration": "تأیید بازیابی نگارش",
|
||||
"currentDocumentStatus": "جاری {{docStatus}} سند",
|
||||
"currentDraft": "پیش نویس فعلی",
|
||||
"currentPublishedVersion": "نسخه منتشر شده فعلی",
|
||||
"draft": "پیشنویس",
|
||||
"draftSavedSuccessfully": "پیشنویس با موفقیت ذخیره شد.",
|
||||
"lastSavedAgo": "آخرین بار {{distance}} پیش ذخیره شد",
|
||||
"noFurtherVersionsFound": "نگارش دیگری یافت نشد",
|
||||
"noRowsFound": "هیچ {{label}} یافت نشد",
|
||||
"preview": "پیشنمایش",
|
||||
"previouslyPublished": "قبلا منتشر شده",
|
||||
"problemRestoringVersion": "مشکلی در بازیابی این نگارش وجود دارد",
|
||||
"publish": "انتشار",
|
||||
"publishChanges": "انتشار تغییرات",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "مشاهده نگارشها برای {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "مشاهده نگارشهای کلی {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Confirmer l’annulation",
|
||||
"confirmVersionRestoration": "Confirmer la restauration de la version",
|
||||
"currentDocumentStatus": "Document {{docStatus}} actuel",
|
||||
"currentDraft": "Projet actuel",
|
||||
"currentPublishedVersion": "Version Publiée Actuelle",
|
||||
"draft": "Brouillon",
|
||||
"draftSavedSuccessfully": "Brouillon enregistré avec succès.",
|
||||
"lastSavedAgo": "Dernière sauvegarde il y a {{distance}}",
|
||||
"noFurtherVersionsFound": "Aucune autre version trouvée",
|
||||
"noRowsFound": "Aucun(e) {{label}} trouvé(e)",
|
||||
"preview": "Aperçu",
|
||||
"previouslyPublished": "Précédemment publié",
|
||||
"problemRestoringVersion": "Un problème est survenu lors de la restauration de cette version",
|
||||
"publish": "Publier",
|
||||
"publishChanges": "Publier les modifications",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Affichage des versions de ou du {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "Affichage des versions globales de ou du {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Potvrdite poništavanje objave",
|
||||
"confirmVersionRestoration": "Potvrdite vraćanje verzije",
|
||||
"currentDocumentStatus": "Trenutni {{docStatus}} dokumenta",
|
||||
"currentDraft": "Trenutačni nacrt",
|
||||
"currentPublishedVersion": "Trenutačno objavljena verzija",
|
||||
"draft": "Nacrt",
|
||||
"draftSavedSuccessfully": "Nacrt uspješno spremljen.",
|
||||
"lastSavedAgo": "Zadnji put spremljeno prije {{distance}",
|
||||
"noFurtherVersionsFound": "Nisu pronađene daljnje verzije",
|
||||
"noRowsFound": "{{label}} nije pronađeno",
|
||||
"preview": "Pregled",
|
||||
"previouslyPublished": "Prethodno objavljeno",
|
||||
"problemRestoringVersion": "Nastao je problem pri vraćanju ove verzije",
|
||||
"publish": "Objaviti",
|
||||
"publishChanges": "Objavi promjene",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Pregled verzija za {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "Pregled verzije za globalni {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "A közzététel visszavonásának megerősítése",
|
||||
"confirmVersionRestoration": "Verzió-visszaállítás megerősítése",
|
||||
"currentDocumentStatus": "Jelenlegi {{docStatus}} dokumentum",
|
||||
"currentDraft": "Jelenlegi vázlat",
|
||||
"currentPublishedVersion": "Aktuálisan Kiadott Verzió",
|
||||
"draft": "Piszkozat",
|
||||
"draftSavedSuccessfully": "A piszkozat sikeresen mentve.",
|
||||
"lastSavedAgo": "Utoljára mentve {{distance}} órája",
|
||||
"noFurtherVersionsFound": "További verziók nem találhatók",
|
||||
"noRowsFound": "Nem található {{label}}",
|
||||
"preview": "Előnézet",
|
||||
"previouslyPublished": "Korábban Megjelent",
|
||||
"problemRestoringVersion": "Hiba történt a verzió visszaállításakor",
|
||||
"publish": "Közzététel",
|
||||
"publishChanges": "Módosítások közzététele",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "A {{entityLabel}} {{documentTitle}} verzióinak megtekintése",
|
||||
"viewingVersionsGlobal": "A globális {{entityLabel}} verzióinak megtekintése"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -342,12 +342,15 @@
|
||||
"confirmUnpublish": "Conferma annullamento della pubblicazione",
|
||||
"confirmVersionRestoration": "Conferma il ripristino della versione",
|
||||
"currentDocumentStatus": "Documento {{docStatus}} corrente",
|
||||
"currentDraft": "Bozza Corrente",
|
||||
"currentPublishedVersion": "Versione Pubblicata Corrente",
|
||||
"draft": "Bozza",
|
||||
"draftSavedSuccessfully": "Bozza salvata con successo.",
|
||||
"lastSavedAgo": "Ultimo salvataggio {{distance}} fa",
|
||||
"noFurtherVersionsFound": "Non sono state trovate ulteriori versioni",
|
||||
"noRowsFound": "Nessun {{label}} trovato",
|
||||
"preview": "Anteprima",
|
||||
"previouslyPublished": "Pubblicato in precedenza",
|
||||
"problemRestoringVersion": "Si è verificato un problema durante il ripristino di questa versione",
|
||||
"publish": "Pubblicare",
|
||||
"publishChanges": "Pubblica modifiche",
|
||||
@@ -379,4 +382,4 @@
|
||||
"viewingVersions": "Visualizzazione delle versioni per {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "`Visualizzazione delle versioni per {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "非公開の確認",
|
||||
"confirmVersionRestoration": "バージョン復元の確認",
|
||||
"currentDocumentStatus": "現在の {{docStatus}} データ",
|
||||
"currentDraft": "現行のドラフト",
|
||||
"currentPublishedVersion": "現在公開されているバージョン",
|
||||
"draft": "ドラフト",
|
||||
"draftSavedSuccessfully": "下書きは正常に保存されました。",
|
||||
"lastSavedAgo": "{{distance}}前に最後に保存されました",
|
||||
"noFurtherVersionsFound": "その他のバージョンは見つかりませんでした。",
|
||||
"noRowsFound": "{{label}} は未設定です",
|
||||
"preview": "プレビュー",
|
||||
"previouslyPublished": "以前に公開された",
|
||||
"problemRestoringVersion": "このバージョンの復元に問題がありました。",
|
||||
"publish": "公開する",
|
||||
"publishChanges": "変更内容を公開",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "表示バージョン: {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "表示バージョン: グローバルな {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "게시 해제하기",
|
||||
"confirmVersionRestoration": "버전 복원하기",
|
||||
"currentDocumentStatus": "현재 {{docStatus}} 문서",
|
||||
"currentDraft": "현재 초안",
|
||||
"currentPublishedVersion": "현재 게시된 버전",
|
||||
"draft": "초안",
|
||||
"draftSavedSuccessfully": "초안이 저장되었습니다.",
|
||||
"lastSavedAgo": "마지막으로 저장한지 {{distance}} 전",
|
||||
"noFurtherVersionsFound": "더 이상의 버전을 찾을 수 없습니다.",
|
||||
"noRowsFound": "{{label}}을(를) 찾을 수 없음",
|
||||
"preview": "미리보기",
|
||||
"previouslyPublished": "이전에 발표된",
|
||||
"problemRestoringVersion": "이 버전을 복원하는 중 문제가 발생했습니다.",
|
||||
"publish": "게시",
|
||||
"publishChanges": "변경 사항 게시",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "{{entityLabel}} {{documentTitle}}에 대한 버전 보기",
|
||||
"viewingVersionsGlobal": "글로벌 {{entityLabel}}에 대한 버전 보기"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "အများဆိုင်ကို ဖျက်ရန် အတည်ပြုပါ။",
|
||||
"confirmVersionRestoration": "ဗားရှင်းပြန်လည် အသုံးပြုခြင်းကို အတည်ပြုပါ။",
|
||||
"currentDocumentStatus": "လက်ရှိ {{docStatus}} ဖိုင်",
|
||||
"currentDraft": "လက်ရှိမှန်ကန့်သတ်",
|
||||
"currentPublishedVersion": "Versi yang Diterbitkan Saat Ini",
|
||||
"draft": "မူကြမ်း",
|
||||
"draftSavedSuccessfully": "မူကြမ်းကို အောင်မြင်စွာ သိမ်းဆည်းပြီးပါပြီ။",
|
||||
"lastSavedAgo": "နောက်ဆုံး သိမ်းချက် {{distance}} ကြာပြီး",
|
||||
"noFurtherVersionsFound": "နောက်ထပ်ဗားရှင်းများ မတွေ့ပါ။",
|
||||
"noRowsFound": "{{label}} အားမတွေ့ပါ။",
|
||||
"preview": "နမူနာပြရန်",
|
||||
"previouslyPublished": "Sebelum ini diterbitkan",
|
||||
"problemRestoringVersion": "ဤဗားရှင်းကို ပြန်လည်ရယူရာတွင် ပြဿနာရှိနေသည်။",
|
||||
"publish": "ထုတ်ဝေသည်။",
|
||||
"publishChanges": "အပြောင်းအလဲများကို တင်ခဲ့သည်။",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "{{entityLabel}} {{documentTitle}} အတွက် ဗားရှင်းများကို ကြည့်ရှုခြင်း",
|
||||
"viewingVersionsGlobal": "`ဂလိုဘယ်ဆိုင်ရာ {{entityLabel}} အတွက် ဗားရှင်းများကို ကြည့်ရှုနေသည်"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Bekreft avpublisering",
|
||||
"confirmVersionRestoration": "Bekreft versjon-gjenoppretting",
|
||||
"currentDocumentStatus": "Nåværende {{docStatus}} dokument",
|
||||
"currentDraft": "Nåværende utkast",
|
||||
"currentPublishedVersion": "Nåværende publiserte versjon",
|
||||
"draft": "Utkast",
|
||||
"draftSavedSuccessfully": "Utkast lagret.",
|
||||
"lastSavedAgo": "Sist lagret {{distance}} siden",
|
||||
"noFurtherVersionsFound": "Ingen flere versjoner funnet",
|
||||
"noRowsFound": "Ingen {{label}} funnet",
|
||||
"preview": "Forhåndsvisning",
|
||||
"previouslyPublished": "Tidligere Publisert",
|
||||
"problemRestoringVersion": "Det oppstod et problem med gjenoppretting av denne versjonen",
|
||||
"publish": "Publisere",
|
||||
"publishChanges": "Publiser endringer",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Viser versjoner for {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "Viser versjoner for den globale variabelen {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Bevestig depubliceren",
|
||||
"confirmVersionRestoration": "Bevestig te herstellen versie",
|
||||
"currentDocumentStatus": "Huidig {{docStatus}} document",
|
||||
"currentDraft": "Huidige Concept",
|
||||
"currentPublishedVersion": "Huidige Gepubliceerde Versie",
|
||||
"draft": "Concept",
|
||||
"draftSavedSuccessfully": "Concept succesvol bewaard.",
|
||||
"lastSavedAgo": "Laatst opgeslagen {{distance}} geleden",
|
||||
"noFurtherVersionsFound": "Geen verdere versies gevonden",
|
||||
"noRowsFound": "Geen {{label}} gevonden",
|
||||
"preview": "Voorbeeld",
|
||||
"previouslyPublished": "Eerder gepubliceerd",
|
||||
"problemRestoringVersion": "Er was een probleem bij het herstellen van deze versie",
|
||||
"publish": "Publiceren",
|
||||
"publishChanges": "Publiceer wijzigingen",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Bekijk versies voor {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "`Bekijk versies voor global {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -342,12 +342,15 @@
|
||||
"confirmUnpublish": "Potwierdź cofnięcie publikacji",
|
||||
"confirmVersionRestoration": "Potwierdź przywrócenie wersji",
|
||||
"currentDocumentStatus": "Bieżący status {{docStatus}} dokumentu",
|
||||
"currentDraft": "Aktualny projekt",
|
||||
"currentPublishedVersion": "Aktualna opublikowana wersja",
|
||||
"draft": "Szkic",
|
||||
"draftSavedSuccessfully": "Wersja robocza została pomyślnie zapisana.",
|
||||
"lastSavedAgo": "Ostatnio zapisane {{distance}} temu",
|
||||
"noFurtherVersionsFound": "Nie znaleziono dalszych wersji",
|
||||
"noRowsFound": "Nie znaleziono {{label}}",
|
||||
"preview": "Podgląd",
|
||||
"previouslyPublished": "Wcześniej opublikowane",
|
||||
"problemRestoringVersion": "Wystąpił problem podczas przywracania tej wersji",
|
||||
"publish": "Publikuj",
|
||||
"publishChanges": "Opublikuj zmiany",
|
||||
@@ -379,4 +382,4 @@
|
||||
"viewingVersions": "Przeglądanie wersji {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "Przeglądanie wersji dla globalnej kolekcji {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Confirmar despublicação",
|
||||
"confirmVersionRestoration": "Confirmar Restauração de versão",
|
||||
"currentDocumentStatus": "Documento {{docStatus}} atual",
|
||||
"currentDraft": "Rascunho Atual",
|
||||
"currentPublishedVersion": "Versão Publicada Atual",
|
||||
"draft": "Rascunho",
|
||||
"draftSavedSuccessfully": "Rascunho salvo com sucesso.",
|
||||
"lastSavedAgo": "Última gravação há {{distance}}",
|
||||
"noFurtherVersionsFound": "Nenhuma outra versão encontrada",
|
||||
"noRowsFound": "Nenhum(a) {{label}} encontrado(a)",
|
||||
"preview": "Pré-visualização",
|
||||
"previouslyPublished": "Publicado Anteriormente",
|
||||
"problemRestoringVersion": "Ocorreu um problema ao restaurar essa versão",
|
||||
"publish": "Publicar",
|
||||
"publishChanges": "Publicar alterações",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Visualizando versões para o/a {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "`Visualizando versões para o global {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Confirmați nepublicarea",
|
||||
"confirmVersionRestoration": "Confirmați restaurarea versiunii",
|
||||
"currentDocumentStatus": "Documentul {{docStatus}} curent",
|
||||
"currentDraft": "Proiect curent",
|
||||
"currentPublishedVersion": "Versiunea Publicată Curentă",
|
||||
"draft": "Proiect",
|
||||
"draftSavedSuccessfully": "Proiect salvat cu succes.",
|
||||
"lastSavedAgo": "Ultima salvare acum {{distance}}",
|
||||
"noFurtherVersionsFound": "Nu s-au găsit alte versiuni",
|
||||
"noRowsFound": "Nu s-a găsit niciun {{label}}",
|
||||
"preview": "Previzualizare",
|
||||
"previouslyPublished": "Publicat anterior",
|
||||
"problemRestoringVersion": "A existat o problemă la restaurarea acestei versiuni",
|
||||
"publish": "Publicați",
|
||||
"publishChanges": "Publicați modificările",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Vizualizarea versiunilor pentru {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "Vizualizarea versiunilor pentru globala {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Potvrdite poništavanje objave",
|
||||
"confirmVersionRestoration": "Potvrdite vraćanje verzije",
|
||||
"currentDocumentStatus": "Trenutni {{docStatus}} dokumenta",
|
||||
"currentDraft": "Trenutni Nacrt",
|
||||
"currentPublishedVersion": "Trenutna Objavljena Verzija",
|
||||
"draft": "Nacrt",
|
||||
"draftSavedSuccessfully": "Nacrt uspešno sačuvan.",
|
||||
"lastSavedAgo": "Zadnji put sačuvano pre {{distance}",
|
||||
"noFurtherVersionsFound": "Nisu pronađene naredne verzije",
|
||||
"noRowsFound": "{{label}} nije pronađeno",
|
||||
"preview": "Pregled",
|
||||
"previouslyPublished": "Prethodno objavljeno",
|
||||
"problemRestoringVersion": "Nastao je problem pri vraćanju ove verzije",
|
||||
"publish": "Objaviti",
|
||||
"publishChanges": "Objavi promene",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Pregled verzija za {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "Pregled verzije za globalni {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Потврдите поништавање објаве",
|
||||
"confirmVersionRestoration": "Потврдите враћање верзије",
|
||||
"currentDocumentStatus": "Тренутни {{docStatus}} документа",
|
||||
"currentDraft": "Trenutni nacrt",
|
||||
"currentPublishedVersion": "Trenutno objavljena verzija",
|
||||
"draft": "Нацрт",
|
||||
"draftSavedSuccessfully": "Нацрт успешно сачуван.",
|
||||
"lastSavedAgo": "Задњи пут сачувано пре {{distance}",
|
||||
"noFurtherVersionsFound": "Нису пронађене наредне верзије",
|
||||
"noRowsFound": "{{label}} није пронађено",
|
||||
"preview": "Преглед",
|
||||
"previouslyPublished": "Prethodno objavljeno",
|
||||
"problemRestoringVersion": "Настао је проблем при враћању ове верзије",
|
||||
"publish": "Објавити",
|
||||
"publishChanges": "Објави промене",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Преглед верзија за {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "Преглед верзије за глобални {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Подтвердить отмену публикации",
|
||||
"confirmVersionRestoration": "Подтвердить восстановление версии",
|
||||
"currentDocumentStatus": "Текущий статус {{docStatus}} документа",
|
||||
"currentDraft": "Текущий проект",
|
||||
"currentPublishedVersion": "Текущая опубликованная версия",
|
||||
"draft": "Черновик",
|
||||
"draftSavedSuccessfully": "Черновик успешно сохранен.",
|
||||
"lastSavedAgo": "Последний раз сохранено {{distance}} назад",
|
||||
"noFurtherVersionsFound": "Другие версии не найдены",
|
||||
"noRowsFound": "Не найдено {{label}}",
|
||||
"preview": "Предпросмотр",
|
||||
"previouslyPublished": "Ранее опубликовано",
|
||||
"problemRestoringVersion": "Возникла проблема с восстановлением этой версии",
|
||||
"publish": "Публиковать",
|
||||
"publishChanges": "Опубликовать изменения",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Просмотр версий для {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "`Просмотр версии для глобальной Коллекции {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Bekräfta avpublicering",
|
||||
"confirmVersionRestoration": "Bekräfta Versionsåterställning",
|
||||
"currentDocumentStatus": "Nuvarande {{docStatus}} dokument",
|
||||
"currentDraft": "Nuvarande utkast",
|
||||
"currentPublishedVersion": "Aktuell publicerad version",
|
||||
"draft": "Utkast",
|
||||
"draftSavedSuccessfully": "Utkastet sparades framgångsrikt.",
|
||||
"lastSavedAgo": "Senast sparad för {{distance}} sedan",
|
||||
"noFurtherVersionsFound": "Inga fler versioner hittades",
|
||||
"noRowsFound": "Inga {{label}} hittades",
|
||||
"preview": "Förhandsvisa",
|
||||
"previouslyPublished": "Tidigare Publicerad",
|
||||
"problemRestoringVersion": "Det uppstod ett problem när den här versionen skulle återställas",
|
||||
"publish": "Publicera",
|
||||
"publishChanges": "Publicera ändringar",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Visar versioner för {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "Visa versioner för den globala {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "ยืนยันการยกเลิกการเผยแพร่",
|
||||
"confirmVersionRestoration": "ยืนยันการกู้คืนเวอร์ชัน",
|
||||
"currentDocumentStatus": "เอกสารปัจจุบัน",
|
||||
"currentDraft": "ร่างปัจจุบัน",
|
||||
"currentPublishedVersion": "เวอร์ชันที่เผยแพร่ในปัจจุบัน",
|
||||
"draft": "ฉบับร่าง",
|
||||
"draftSavedSuccessfully": "บันทึกร่างสำเร็จ",
|
||||
"lastSavedAgo": "บันทึกครั้งล่าสุด {{distance}} ที่ผ่านมา",
|
||||
"noFurtherVersionsFound": "ไม่พบเวอร์ชันอื่น ๆ",
|
||||
"noRowsFound": "ไม่พบ {{label}}",
|
||||
"preview": "ตัวอย่าง",
|
||||
"previouslyPublished": "เผยแพร่ก่อนหน้านี้",
|
||||
"problemRestoringVersion": "เกิดปัญหาระหว่างการกู้คืนเวอร์ชันนี้",
|
||||
"publish": "เผยแพร่",
|
||||
"publishChanges": "เผยแพร่การแก้ไข",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "กำลังดูเวอร์ชันของ {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "กำลังดูเวอร์ชันของ global {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,10 +169,10 @@
|
||||
"create": "Oluştur",
|
||||
"createNew": "Yeni Oluştur",
|
||||
"createNewLabel": "Yeni {{label}} oluştur",
|
||||
"creatingNewLabel": "Yeni {{label}} oluşturuluyor",
|
||||
"created": "Oluşturuldu",
|
||||
"createdAt": "Oluşturulma Tarihi",
|
||||
"creating": "Oluşturuluyor",
|
||||
"creatingNewLabel": "Yeni {{label}} oluşturuluyor",
|
||||
"dark": "Koyu",
|
||||
"dashboard": "Kontrol Paneli",
|
||||
"delete": "Sil",
|
||||
@@ -225,8 +225,8 @@
|
||||
"notFound": "Bulunamadı",
|
||||
"nothingFound": "Hiçbir şey bulunamadı",
|
||||
"of": "",
|
||||
"or": "Veya",
|
||||
"open": "Aç",
|
||||
"or": "Veya",
|
||||
"order": "Sıralama",
|
||||
"pageNotFound": "Sayfa bulunamadı",
|
||||
"password": "Parola",
|
||||
@@ -248,8 +248,8 @@
|
||||
"sort": "Sırala",
|
||||
"sortByLabelDirection": "{{label}} {{direction}} göre sırala",
|
||||
"stayOnThisPage": "Bu sayfada kal",
|
||||
"submit": "Gönder",
|
||||
"submissionSuccessful": "Gönderim Başarılı.",
|
||||
"submit": "Gönder",
|
||||
"successfullyCreated": "{{label}} başarıyla oluşturuldu.",
|
||||
"successfullyDuplicated": "{{label}} başarıyla çoğaltıldı.",
|
||||
"thisLanguage": "Türkçe",
|
||||
@@ -288,10 +288,10 @@
|
||||
"dragAndDrop": "Bir dosyayı sürükleyip bırakın",
|
||||
"dragAndDropHere": "veya bir dosyayı buraya sürükleyip bırakın",
|
||||
"editImage": "Görüntüyü Düzenle",
|
||||
"focalPoint": "Odak Noktası",
|
||||
"focalPointDescription": "Odak noktasını doğrudan önizleme üzerinde sürükleyin veya aşağıdaki değerleri ayarlayın.",
|
||||
"fileName": "Dosya Adı",
|
||||
"fileSize": "Dosya Boyutu",
|
||||
"focalPoint": "Odak Noktası",
|
||||
"focalPointDescription": "Odak noktasını doğrudan önizleme üzerinde sürükleyin veya aşağıdaki değerleri ayarlayın.",
|
||||
"height": "Yükseklik",
|
||||
"lessInfo": "Daha az bilgi",
|
||||
"moreInfo": "Daha fazla bilgi",
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Yayından kaldırmayı onayla",
|
||||
"confirmVersionRestoration": "Sürüm Geri Yüklemesini Onayla",
|
||||
"currentDocumentStatus": "Geçerli {{docStatus}} belge",
|
||||
"currentDraft": "Mevcut Taslak",
|
||||
"currentPublishedVersion": "Mevcut Yayınlanan Sürüm",
|
||||
"draft": "Taslak",
|
||||
"draftSavedSuccessfully": "Taslak başarıyla kaydedildi.",
|
||||
"lastSavedAgo": "Son kaydedilme {{distance}} önce",
|
||||
"noFurtherVersionsFound": "Başka sürüm bulunamadı",
|
||||
"noRowsFound": "Hiçbir {{label}} bulunamadı",
|
||||
"preview": "Önizleme",
|
||||
"previouslyPublished": "Daha Önce Yayınlanmış",
|
||||
"problemRestoringVersion": "Bu sürümü geri yüklerken bir sorun oluştu",
|
||||
"publish": "Yayınla",
|
||||
"publishChanges": "Değişiklikleri yayınla",
|
||||
|
||||
@@ -1314,6 +1314,12 @@
|
||||
"currentDocumentStatus": {
|
||||
"type": "string"
|
||||
},
|
||||
"currentDraft": {
|
||||
"type": "string"
|
||||
},
|
||||
"currentPublishedVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"draft": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -1332,6 +1338,9 @@
|
||||
"preview": {
|
||||
"type": "string"
|
||||
},
|
||||
"previouslyPublished": {
|
||||
"type": "string"
|
||||
},
|
||||
"problemRestoringVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Підвтердити відміну публікації",
|
||||
"confirmVersionRestoration": "Підтвердити відновлення версії",
|
||||
"currentDocumentStatus": "Поточний статус {{docStatus}} документа",
|
||||
"currentDraft": "Поточний проект",
|
||||
"currentPublishedVersion": "Поточна опублікована версія",
|
||||
"draft": "Чернетка",
|
||||
"draftSavedSuccessfully": "Чернетка успішно збережена.",
|
||||
"lastSavedAgo": "Останній раз збережено {{distance}} тому",
|
||||
"noFurtherVersionsFound": "Інших версій не знайдено",
|
||||
"noRowsFound": "Не знайдено {{label}}",
|
||||
"preview": "Попередній перегляд",
|
||||
"previouslyPublished": "Раніше опубліковано",
|
||||
"problemRestoringVersion": "Виникла проблема з відновленням цієї версії",
|
||||
"publish": "Опублікувати",
|
||||
"publishChanges": "Опублікувати зміни",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Огляд версій для {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "Огляд версій для глобальної колекції {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "Xác nhận, ngưng xuất bản",
|
||||
"confirmVersionRestoration": "Xác nhận, khôi phục về phiên bản trước",
|
||||
"currentDocumentStatus": "Trạng thái tài liệu hiện tại: {{docStatus}}",
|
||||
"currentDraft": "Bản thảo hiện tại",
|
||||
"currentPublishedVersion": "Phiên bản được xuất bản hiện tại",
|
||||
"draft": "Bản nháp",
|
||||
"draftSavedSuccessfully": "Bản nháp đã được lưu thành công.",
|
||||
"lastSavedAgo": "Lần lưu cuối cùng {{distance}} trước đây",
|
||||
"noFurtherVersionsFound": "Không tìm thấy phiên bản cũ hơn",
|
||||
"noRowsFound": "Không tìm thấy: {{label}}",
|
||||
"preview": "Bản xem trước",
|
||||
"previouslyPublished": "Đã xuất bản trước đây",
|
||||
"problemRestoringVersion": "Đã xảy ra vấn đề khi khôi phục phiên bản này",
|
||||
"publish": "Công bố",
|
||||
"publishChanges": "Xuất bản tài liệu",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "Xem những phiên bản của {{entityLabel}} {{documentTitle}}",
|
||||
"viewingVersionsGlobal": "`Xem những phiên bản toàn thể (global) của {{entityLabel}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "確認取消發佈",
|
||||
"confirmVersionRestoration": "確認版本回復",
|
||||
"currentDocumentStatus": "目前{{docStatus}}文件",
|
||||
"currentDraft": "目前的草案",
|
||||
"currentPublishedVersion": "目前已發布的版本",
|
||||
"draft": "草稿",
|
||||
"draftSavedSuccessfully": "草稿儲存成功。",
|
||||
"lastSavedAgo": "上次儲存在{{distance}}之前",
|
||||
"noFurtherVersionsFound": "沒有發現其他版本",
|
||||
"noRowsFound": "沒有發現{{label}}",
|
||||
"preview": "預覽",
|
||||
"previouslyPublished": "先前發表過的",
|
||||
"problemRestoringVersion": "回復這個版本時發生了問題",
|
||||
"publish": "發佈",
|
||||
"publishChanges": "發佈修改",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "正在查看{{entityLabel}} {{documentTitle}}的版本",
|
||||
"viewingVersionsGlobal": "正在查看全域{{entityLabel}}的版本"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,12 +341,15 @@
|
||||
"confirmUnpublish": "确认取消发布",
|
||||
"confirmVersionRestoration": "确认版本恢复",
|
||||
"currentDocumentStatus": "当前{{docStatus}}文件",
|
||||
"currentDraft": "当前草案",
|
||||
"currentPublishedVersion": "当前发布的版本",
|
||||
"draft": "草稿",
|
||||
"draftSavedSuccessfully": "草稿成功保存。",
|
||||
"lastSavedAgo": "上次保存{{distance}}之前",
|
||||
"noFurtherVersionsFound": "没有发现其他版本",
|
||||
"noRowsFound": "没有发现{{label}}",
|
||||
"preview": "预览",
|
||||
"previouslyPublished": "先前发表过的",
|
||||
"problemRestoringVersion": "恢复这个版本时发生了问题",
|
||||
"publish": "发布",
|
||||
"publishChanges": "发布修改",
|
||||
@@ -378,4 +381,4 @@
|
||||
"viewingVersions": "正在查看{{entityLabel}} {{documentTitle}}的版本",
|
||||
"viewingVersionsGlobal": "正在查看全局{{entityLabel}}的版本"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { SharpOptions } from 'sharp'
|
||||
|
||||
import sharp from 'sharp'
|
||||
|
||||
export const percentToPixel = (value: string, dimension: number): number => {
|
||||
@@ -7,8 +9,14 @@ export const percentToPixel = (value: string, dimension: number): number => {
|
||||
|
||||
export default async function cropImage({ cropData, dimensions, file }) {
|
||||
try {
|
||||
const fileIsAnimated = ['image/avif', 'image/gif', 'image/webp'].includes(file.mimetype)
|
||||
|
||||
const { height, width, x, y } = cropData
|
||||
|
||||
const sharpOptions: SharpOptions = {}
|
||||
|
||||
if (fileIsAnimated) sharpOptions.animated = true
|
||||
|
||||
const formattedCropData: sharp.Region = {
|
||||
height: percentToPixel(height, dimensions.height),
|
||||
left: percentToPixel(x, dimensions.width),
|
||||
@@ -16,7 +24,7 @@ export default async function cropImage({ cropData, dimensions, file }) {
|
||||
width: percentToPixel(width, dimensions.width),
|
||||
}
|
||||
|
||||
const cropped = sharp(file.tempFilePath || file.data).extract(formattedCropData)
|
||||
const cropped = sharp(file.tempFilePath || file.data, sharpOptions).extract(formattedCropData)
|
||||
|
||||
return await cropped.toBuffer({
|
||||
resolveWithObject: true,
|
||||
|
||||
@@ -121,7 +121,7 @@ export const generateFileData = async <T>({
|
||||
let newData = data
|
||||
const filesToSave: FileToSave[] = []
|
||||
const fileData: Partial<FileData> = {}
|
||||
const fileIsAnimated = file.mimetype === 'image/gif' || file.mimetype === 'image/webp'
|
||||
const fileIsAnimated = ['image/avif', 'image/gif', 'image/webp'].includes(file.mimetype)
|
||||
const cropData =
|
||||
typeof uploadEdits === 'object' && 'crop' in uploadEdits ? uploadEdits.crop : undefined
|
||||
|
||||
@@ -135,27 +135,29 @@ export const generateFileData = async <T>({
|
||||
let mime: string
|
||||
const fileHasAdjustments =
|
||||
fileSupportsResize &&
|
||||
Boolean(resizeOptions || formatOptions || trimOptions || file.tempFilePath)
|
||||
Boolean(resizeOptions || formatOptions || imageSizes || trimOptions || file.tempFilePath)
|
||||
|
||||
const sharpOptions: SharpOptions = {}
|
||||
|
||||
if (fileIsAnimated) sharpOptions.animated = true
|
||||
|
||||
if (fileHasAdjustments) {
|
||||
if (sharp && (fileIsAnimated || fileHasAdjustments)) {
|
||||
if (file.tempFilePath) {
|
||||
sharpFile = sharp(file.tempFilePath, sharpOptions).rotate() // pass rotate() to auto-rotate based on EXIF data. https://github.com/payloadcms/payload/pull/3081
|
||||
} else {
|
||||
sharpFile = sharp(file.data, sharpOptions).rotate() // pass rotate() to auto-rotate based on EXIF data. https://github.com/payloadcms/payload/pull/3081
|
||||
}
|
||||
|
||||
if (resizeOptions) {
|
||||
sharpFile = sharpFile.resize(resizeOptions)
|
||||
}
|
||||
if (formatOptions) {
|
||||
sharpFile = sharpFile.toFormat(formatOptions.format, formatOptions.options)
|
||||
}
|
||||
if (trimOptions) {
|
||||
sharpFile = sharpFile.trim(trimOptions)
|
||||
if (fileHasAdjustments) {
|
||||
if (resizeOptions) {
|
||||
sharpFile = sharpFile.resize(resizeOptions)
|
||||
}
|
||||
if (formatOptions) {
|
||||
sharpFile = sharpFile.toFormat(formatOptions.format, formatOptions.options)
|
||||
}
|
||||
if (trimOptions) {
|
||||
sharpFile = sharpFile.trim(trimOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +225,10 @@ export const generateFileData = async <T>({
|
||||
}
|
||||
fileData.width = info.width
|
||||
fileData.height = info.height
|
||||
if (fileIsAnimated) {
|
||||
const metadata = await sharpFile.metadata()
|
||||
fileData.height = metadata.pages ? info.height / metadata.pages : info.height
|
||||
}
|
||||
fileData.filesize = info.size
|
||||
|
||||
if (file.tempFilePath) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { UploadedFile } from 'express-fileupload'
|
||||
import type { OutputInfo } from 'sharp'
|
||||
import type { OutputInfo, Sharp, SharpOptions } from 'sharp'
|
||||
|
||||
import { fromBuffer } from 'file-type'
|
||||
import fs from 'fs'
|
||||
@@ -217,7 +217,7 @@ const sanitizeResizeConfig = (resizeConfig: ImageSize): ImageSize => {
|
||||
*
|
||||
* The image will be resized according to the provided
|
||||
* resize config. If no image sizes are requested, the resolved data will be empty.
|
||||
* For every image that dos not need to be resized, an result object with `null`
|
||||
* For every image that does not need to be resized, a result object with `null`
|
||||
* parameters will be returned.
|
||||
*
|
||||
* @param resizeConfig - the resize config
|
||||
@@ -252,7 +252,13 @@ export default async function resizeAndTransformImageSizes({
|
||||
// Nothing to resize here so return as early as possible
|
||||
if (!imageSizes) return defaultResult
|
||||
|
||||
const sharpBase = sharp(file.tempFilePath || file.data).rotate() // pass rotate() to auto-rotate based on EXIF data. https://github.com/payloadcms/payload/pull/3081
|
||||
// Determine if the file is animated
|
||||
const fileIsAnimated = ['image/avif', 'image/gif', 'image/webp'].includes(file.mimetype)
|
||||
const sharpOptions: SharpOptions = {}
|
||||
|
||||
if (fileIsAnimated) sharpOptions.animated = true
|
||||
|
||||
const sharpBase: Sharp | undefined = sharp(file.tempFilePath || file.data, sharpOptions).rotate() // pass rotate() to auto-rotate based on EXIF data. https://github.com/payloadcms/payload/pull/3081
|
||||
|
||||
const results: ImageSizesResult[] = await Promise.all(
|
||||
imageSizes.map(async (imageResizeConfig): Promise<ImageSizesResult> => {
|
||||
@@ -268,6 +274,8 @@ export default async function resizeAndTransformImageSizes({
|
||||
const imageToResize = sharpBase.clone()
|
||||
let resized = imageToResize
|
||||
|
||||
const metadata = await sharpBase.metadata()
|
||||
|
||||
if (incomingFocalPoint && applyPayloadAdjustments(imageResizeConfig, dimensions)) {
|
||||
const { height: resizeHeight, width: resizeWidth } = imageResizeConfig
|
||||
const resizeAspectRatio = resizeWidth / resizeHeight
|
||||
@@ -289,14 +297,18 @@ export default async function resizeAndTransformImageSizes({
|
||||
const safeOffsetX = Math.min(Math.max(0, leftFocalEdge), maxOffsetX)
|
||||
|
||||
const safeResizeHeight = resizeHeight ?? scaledImageInfo.height
|
||||
const maxOffsetY = scaledImageInfo.height - safeResizeHeight
|
||||
|
||||
const maxOffsetY = fileIsAnimated
|
||||
? resizeHeight - safeResizeHeight
|
||||
: scaledImageInfo.height - safeResizeHeight
|
||||
|
||||
const topFocalEdge = Math.round(
|
||||
scaledImageInfo.height * (incomingFocalPoint.y / 100) - safeResizeHeight / 2,
|
||||
)
|
||||
const safeOffsetY = Math.min(Math.max(0, topFocalEdge), maxOffsetY)
|
||||
|
||||
// extract the focal area from the scaled image
|
||||
resized = scaledImage.extract({
|
||||
resized = (fileIsAnimated ? imageToResize : scaledImage).extract({
|
||||
height: safeResizeHeight,
|
||||
left: safeOffsetX,
|
||||
top: safeOffsetY,
|
||||
@@ -350,7 +362,7 @@ export default async function resizeAndTransformImageSizes({
|
||||
name: imageResizeConfig.name,
|
||||
filename: imageNameWithDimensions,
|
||||
filesize: size,
|
||||
height,
|
||||
height: fileIsAnimated && metadata.pages ? height / metadata.pages : height,
|
||||
mimeType: mimeInfo?.mime || mimeType,
|
||||
sizesToSave: [{ buffer: bufferData, path: imagePath }],
|
||||
width,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Creates a proxy for the given object that has its own property
|
||||
*/
|
||||
export default function isolateObjectProperty<T>(object: T, key): T {
|
||||
export default function isolateObjectProperty<T>(object: T, key: keyof T): T {
|
||||
const delegate = {}
|
||||
const handler = {
|
||||
deleteProperty(target, p): boolean {
|
||||
|
||||
128
pnpm-lock.yaml
generated
128
pnpm-lock.yaml
generated
@@ -20,8 +20,8 @@ importers:
|
||||
specifier: ^7.77.0
|
||||
version: 7.112.2(react@18.2.0)
|
||||
ajv:
|
||||
specifier: ^8.12.0
|
||||
version: 8.12.0
|
||||
specifier: 8.14.0
|
||||
version: 8.14.0
|
||||
react:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0
|
||||
@@ -270,6 +270,9 @@ importers:
|
||||
|
||||
packages/bundler-webpack:
|
||||
dependencies:
|
||||
ajv:
|
||||
specifier: 8.14.0
|
||||
version: 8.14.0
|
||||
compression:
|
||||
specifier: 1.7.4
|
||||
version: 1.7.4
|
||||
@@ -279,9 +282,6 @@ importers:
|
||||
css-loader:
|
||||
specifier: 5.2.7
|
||||
version: 5.2.7(webpack@5.91.0)
|
||||
css-minimizer-webpack-plugin:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.1(webpack@5.91.0)
|
||||
file-loader:
|
||||
specifier: 6.2.0
|
||||
version: 6.2.0(webpack@5.91.0)
|
||||
@@ -438,52 +438,6 @@ importers:
|
||||
specifier: ^29.1.0
|
||||
version: 29.1.2(@babel/core@7.24.4)(jest@29.7.0)(typescript@5.2.2)
|
||||
|
||||
packages/db-example:
|
||||
dependencies:
|
||||
bson-objectid:
|
||||
specifier: 2.0.4
|
||||
version: 2.0.4
|
||||
deepmerge:
|
||||
specifier: 4.3.1
|
||||
version: 4.3.1
|
||||
get-port:
|
||||
specifier: 5.1.1
|
||||
version: 5.1.1
|
||||
http-status:
|
||||
specifier: 1.6.2
|
||||
version: 1.6.2
|
||||
mongoose:
|
||||
specifier: 6.12.3
|
||||
version: 6.12.3
|
||||
mongoose-aggregate-paginate-v2:
|
||||
specifier: 1.0.6
|
||||
version: 1.0.6
|
||||
mongoose-paginate-v2:
|
||||
specifier: 1.7.22
|
||||
version: 1.7.22
|
||||
prompts:
|
||||
specifier: 2.4.2
|
||||
version: 2.4.2
|
||||
uuid:
|
||||
specifier: 9.0.0
|
||||
version: 9.0.0
|
||||
devDependencies:
|
||||
'@payloadcms/eslint-config':
|
||||
specifier: workspace:*
|
||||
version: link:../eslint-config-payload
|
||||
'@types/mongoose-aggregate-paginate-v2':
|
||||
specifier: 1.0.9
|
||||
version: 1.0.9
|
||||
mongodb:
|
||||
specifier: 4.17.1
|
||||
version: 4.17.1
|
||||
mongodb-memory-server:
|
||||
specifier: ^9
|
||||
version: 9.2.0
|
||||
payload:
|
||||
specifier: workspace:*
|
||||
version: link:../payload
|
||||
|
||||
packages/db-mongodb:
|
||||
dependencies:
|
||||
bson-objectid:
|
||||
@@ -5484,6 +5438,7 @@ packages:
|
||||
/@trysound/sax@0.2.0:
|
||||
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
dev: true
|
||||
|
||||
/@tsconfig/node10@1.0.11:
|
||||
resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
|
||||
@@ -6827,7 +6782,7 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/ajv-formats@2.1.1(ajv@8.12.0):
|
||||
/ajv-formats@2.1.1(ajv@8.14.0):
|
||||
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
|
||||
peerDependencies:
|
||||
ajv: ^8.0.0
|
||||
@@ -6835,7 +6790,7 @@ packages:
|
||||
ajv:
|
||||
optional: true
|
||||
dependencies:
|
||||
ajv: 8.12.0
|
||||
ajv: 8.14.0
|
||||
|
||||
/ajv-keywords@3.5.2(ajv@6.12.6):
|
||||
resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==}
|
||||
@@ -6844,12 +6799,12 @@ packages:
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
|
||||
/ajv-keywords@5.1.0(ajv@8.12.0):
|
||||
/ajv-keywords@5.1.0(ajv@8.14.0):
|
||||
resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==}
|
||||
peerDependencies:
|
||||
ajv: ^8.8.2
|
||||
dependencies:
|
||||
ajv: 8.12.0
|
||||
ajv: 8.14.0
|
||||
fast-deep-equal: 3.1.3
|
||||
|
||||
/ajv@6.12.6:
|
||||
@@ -6860,8 +6815,8 @@ packages:
|
||||
json-schema-traverse: 0.4.1
|
||||
uri-js: 4.4.1
|
||||
|
||||
/ajv@8.12.0:
|
||||
resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
|
||||
/ajv@8.14.0:
|
||||
resolution: {integrity: sha512-oYs1UUtO97ZO2lJ4bwnWeQW8/zvOIQLGKcvPTsWmvc2SYgBb+upuNS5NxoLaMU4h8Ju3Nbj6Cq8mD2LQoqVKFA==}
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
json-schema-traverse: 1.0.0
|
||||
@@ -7624,6 +7579,7 @@ packages:
|
||||
caniuse-lite: 1.0.30001612
|
||||
lodash.memoize: 4.1.2
|
||||
lodash.uniq: 4.5.0
|
||||
dev: true
|
||||
|
||||
/caniuse-lite@1.0.30001612:
|
||||
resolution: {integrity: sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==}
|
||||
@@ -7840,6 +7796,7 @@ packages:
|
||||
|
||||
/colord@2.9.3:
|
||||
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
|
||||
dev: true
|
||||
|
||||
/colorette@2.0.20:
|
||||
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
||||
@@ -7934,8 +7891,8 @@ packages:
|
||||
resolution: {integrity: sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
ajv: 8.12.0
|
||||
ajv-formats: 2.1.1(ajv@8.12.0)
|
||||
ajv: 8.14.0
|
||||
ajv-formats: 2.1.1(ajv@8.14.0)
|
||||
atomically: 1.7.0
|
||||
debounce-fn: 4.0.0
|
||||
dot-prop: 6.0.1
|
||||
@@ -8420,6 +8377,7 @@ packages:
|
||||
postcss: ^8.0.9
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
dev: true
|
||||
|
||||
/css-has-pseudo@6.0.3(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-qIsDxK/z0byH/mpNsv5hzQ5NOl8m1FRmOLgZpx4bG5uYHnOlO2XafeMI4mFIgNSViHwoUWcxSJZyyijaAmbs+A==}
|
||||
@@ -8482,6 +8440,7 @@ packages:
|
||||
schema-utils: 4.2.0
|
||||
serialize-javascript: 6.0.2
|
||||
webpack: 5.91.0(@swc/core@1.3.107)(webpack-cli@4.10.0)
|
||||
dev: true
|
||||
|
||||
/css-prefers-color-scheme@9.0.1(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-iFit06ochwCKPRiWagbTa1OAWCvWWVdEnIFd8BaRrgO8YrrNh4RAWUQTFcYX5tdFZgFl1DJ3iiULchZyEbnF4g==}
|
||||
@@ -8509,6 +8468,7 @@ packages:
|
||||
domhandler: 5.0.3
|
||||
domutils: 3.1.0
|
||||
nth-check: 2.1.1
|
||||
dev: true
|
||||
|
||||
/css-tree@2.2.1:
|
||||
resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==}
|
||||
@@ -8516,6 +8476,7 @@ packages:
|
||||
dependencies:
|
||||
mdn-data: 2.0.28
|
||||
source-map-js: 1.2.0
|
||||
dev: true
|
||||
|
||||
/css-tree@2.3.1:
|
||||
resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
|
||||
@@ -8523,6 +8484,7 @@ packages:
|
||||
dependencies:
|
||||
mdn-data: 2.0.30
|
||||
source-map-js: 1.2.0
|
||||
dev: true
|
||||
|
||||
/css-what@6.1.0:
|
||||
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
|
||||
@@ -8581,6 +8543,7 @@ packages:
|
||||
postcss-reduce-transforms: 6.0.2(postcss@8.4.31)
|
||||
postcss-svgo: 6.0.3(postcss@8.4.31)
|
||||
postcss-unique-selectors: 6.0.4(postcss@8.4.31)
|
||||
dev: true
|
||||
|
||||
/cssnano-utils@4.0.2(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==}
|
||||
@@ -8589,6 +8552,7 @@ packages:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
dev: true
|
||||
|
||||
/cssnano@6.1.2(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==}
|
||||
@@ -8599,12 +8563,14 @@ packages:
|
||||
cssnano-preset-default: 6.1.2(postcss@8.4.31)
|
||||
lilconfig: 3.1.1
|
||||
postcss: 8.4.31
|
||||
dev: true
|
||||
|
||||
/csso@5.0.5:
|
||||
resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
|
||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
|
||||
dependencies:
|
||||
css-tree: 2.2.1
|
||||
dev: true
|
||||
|
||||
/cssom@0.3.8:
|
||||
resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==}
|
||||
@@ -9031,6 +8997,7 @@ packages:
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
entities: 4.5.0
|
||||
dev: true
|
||||
|
||||
/domelementtype@2.3.0:
|
||||
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
|
||||
@@ -9055,6 +9022,7 @@ packages:
|
||||
engines: {node: '>= 4'}
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
dev: true
|
||||
|
||||
/domutils@2.8.0:
|
||||
resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
|
||||
@@ -9070,6 +9038,7 @@ packages:
|
||||
dom-serializer: 2.0.0
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
dev: true
|
||||
|
||||
/dot-case@3.0.4:
|
||||
resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
|
||||
@@ -9269,6 +9238,7 @@ packages:
|
||||
/entities@4.5.0:
|
||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
engines: {node: '>=0.12'}
|
||||
dev: true
|
||||
|
||||
/env-paths@2.2.1:
|
||||
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
|
||||
@@ -12915,6 +12885,7 @@ packages:
|
||||
/lilconfig@3.1.1:
|
||||
resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==}
|
||||
engines: {node: '>=14'}
|
||||
dev: true
|
||||
|
||||
/lines-and-columns@1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
@@ -13058,6 +13029,7 @@ packages:
|
||||
|
||||
/lodash.memoize@4.1.2:
|
||||
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
|
||||
dev: true
|
||||
|
||||
/lodash.merge@4.6.2:
|
||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
@@ -13069,6 +13041,7 @@ packages:
|
||||
|
||||
/lodash.uniq@4.5.0:
|
||||
resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
|
||||
dev: true
|
||||
|
||||
/lodash.uniqby@4.7.0:
|
||||
resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==}
|
||||
@@ -13216,9 +13189,11 @@ packages:
|
||||
|
||||
/mdn-data@2.0.28:
|
||||
resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==}
|
||||
dev: true
|
||||
|
||||
/mdn-data@2.0.30:
|
||||
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
||||
dev: true
|
||||
|
||||
/media-typer@0.3.0:
|
||||
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
|
||||
@@ -14584,6 +14559,7 @@ packages:
|
||||
postcss: 8.4.31
|
||||
postcss-selector-parser: 6.0.16
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-clamp@4.1.0(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==}
|
||||
@@ -14638,6 +14614,7 @@ packages:
|
||||
colord: 2.9.3
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-convert-values@6.1.0(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==}
|
||||
@@ -14648,6 +14625,7 @@ packages:
|
||||
browserslist: 4.23.0
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-custom-media@10.0.4(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-Ubs7O3wj2prghaKRa68VHBvuy3KnTQ0zbGwqDYY1mntxJD0QL2AeiAy+AMfl3HBedTCVr2IcFNktwty9YpSskA==}
|
||||
@@ -14702,6 +14680,7 @@ packages:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
dev: true
|
||||
|
||||
/postcss-discard-duplicates@6.0.3(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==}
|
||||
@@ -14710,6 +14689,7 @@ packages:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
dev: true
|
||||
|
||||
/postcss-discard-empty@6.0.3(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==}
|
||||
@@ -14718,6 +14698,7 @@ packages:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
dev: true
|
||||
|
||||
/postcss-discard-overridden@6.0.2(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==}
|
||||
@@ -14726,6 +14707,7 @@ packages:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
dev: true
|
||||
|
||||
/postcss-double-position-gradients@5.0.6(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-QJ+089FKMaqDxOhhIHsJrh4IP7h4PIHNC5jZP5PMmnfUScNu8Hji2lskqpFWCvu+5sj+2EJFyzKd13sLEWOZmQ==}
|
||||
@@ -14832,6 +14814,7 @@ packages:
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
stylehacks: 6.1.1(postcss@8.4.31)
|
||||
dev: true
|
||||
|
||||
/postcss-merge-rules@6.1.1(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==}
|
||||
@@ -14844,6 +14827,7 @@ packages:
|
||||
cssnano-utils: 4.0.2(postcss@8.4.31)
|
||||
postcss: 8.4.31
|
||||
postcss-selector-parser: 6.0.16
|
||||
dev: true
|
||||
|
||||
/postcss-minify-font-values@6.1.0(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==}
|
||||
@@ -14853,6 +14837,7 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-minify-gradients@6.0.3(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==}
|
||||
@@ -14864,6 +14849,7 @@ packages:
|
||||
cssnano-utils: 4.0.2(postcss@8.4.31)
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-minify-params@6.1.0(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==}
|
||||
@@ -14875,6 +14861,7 @@ packages:
|
||||
cssnano-utils: 4.0.2(postcss@8.4.31)
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-minify-selectors@6.0.4(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==}
|
||||
@@ -14884,6 +14871,7 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
postcss-selector-parser: 6.0.16
|
||||
dev: true
|
||||
|
||||
/postcss-modules-extract-imports@3.1.0(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==}
|
||||
@@ -14940,6 +14928,7 @@ packages:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
dev: true
|
||||
|
||||
/postcss-normalize-display-values@6.0.2(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==}
|
||||
@@ -14949,6 +14938,7 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-normalize-positions@6.0.2(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==}
|
||||
@@ -14958,6 +14948,7 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-normalize-repeat-style@6.0.2(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==}
|
||||
@@ -14967,6 +14958,7 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-normalize-string@6.0.2(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==}
|
||||
@@ -14976,6 +14968,7 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-normalize-timing-functions@6.0.2(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==}
|
||||
@@ -14985,6 +14978,7 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-normalize-unicode@6.1.0(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==}
|
||||
@@ -14995,6 +14989,7 @@ packages:
|
||||
browserslist: 4.23.0
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-normalize-url@6.0.2(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==}
|
||||
@@ -15004,6 +14999,7 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-normalize-whitespace@6.0.2(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==}
|
||||
@@ -15013,6 +15009,7 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-opacity-percentage@2.0.0(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-lyDrCOtntq5Y1JZpBFzIWm2wG9kbEdujpNt4NLannF+J9c8CgFIzPa80YQfdza+Y+yFfzbYj/rfoOsYsooUWTQ==}
|
||||
@@ -15031,6 +15028,7 @@ packages:
|
||||
cssnano-utils: 4.0.2(postcss@8.4.31)
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-overflow-shorthand@5.0.1(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-XzjBYKLd1t6vHsaokMV9URBt2EwC9a7nDhpQpjoPk2HRTSQfokPfyAS/Q7AOrzUu6q+vp/GnrDBGuj/FCaRqrQ==}
|
||||
@@ -15139,6 +15137,7 @@ packages:
|
||||
browserslist: 4.23.0
|
||||
caniuse-api: 3.0.0
|
||||
postcss: 8.4.31
|
||||
dev: true
|
||||
|
||||
/postcss-reduce-transforms@6.0.2(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==}
|
||||
@@ -15148,6 +15147,7 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-replace-overflow-wrap@4.0.0(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==}
|
||||
@@ -15181,6 +15181,7 @@ packages:
|
||||
postcss: 8.4.31
|
||||
postcss-value-parser: 4.2.0
|
||||
svgo: 3.2.0
|
||||
dev: true
|
||||
|
||||
/postcss-unique-selectors@6.0.4(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==}
|
||||
@@ -15190,6 +15191,7 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.31
|
||||
postcss-selector-parser: 6.0.16
|
||||
dev: true
|
||||
|
||||
/postcss-value-parser@4.2.0:
|
||||
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
|
||||
@@ -16293,9 +16295,9 @@ packages:
|
||||
engines: {node: '>= 12.13.0'}
|
||||
dependencies:
|
||||
'@types/json-schema': 7.0.15
|
||||
ajv: 8.12.0
|
||||
ajv-formats: 2.1.1(ajv@8.12.0)
|
||||
ajv-keywords: 5.1.0(ajv@8.12.0)
|
||||
ajv: 8.14.0
|
||||
ajv-formats: 2.1.1(ajv@8.14.0)
|
||||
ajv-keywords: 5.1.0(ajv@8.14.0)
|
||||
|
||||
/scmp@2.1.0:
|
||||
resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==}
|
||||
@@ -16992,6 +16994,7 @@ packages:
|
||||
browserslist: 4.23.0
|
||||
postcss: 8.4.31
|
||||
postcss-selector-parser: 6.0.16
|
||||
dev: true
|
||||
|
||||
/stylis@4.2.0:
|
||||
resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
|
||||
@@ -17046,6 +17049,7 @@ packages:
|
||||
css-what: 6.1.0
|
||||
csso: 5.0.5
|
||||
picocolors: 1.0.0
|
||||
dev: true
|
||||
|
||||
/swc-loader@0.2.3(@swc/core@1.3.107)(webpack@5.91.0):
|
||||
resolution: {integrity: sha512-D1p6XXURfSPleZZA/Lipb3A8pZ17fP4NObZvFCDjK/OKljroqDpPmsBdTraWhVBqUNpcWBQY1imWdoPScRlQ7A==}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -380,6 +380,29 @@ export default buildConfigWithDefaults({
|
||||
],
|
||||
},
|
||||
],
|
||||
globals: [
|
||||
{
|
||||
slug: 'global-1',
|
||||
access: {
|
||||
read: openAccess.read,
|
||||
update: openAccess.update,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'title',
|
||||
},
|
||||
{
|
||||
name: 'relationship',
|
||||
type: 'relationship',
|
||||
relationTo: 'cyclical-relationship',
|
||||
},
|
||||
],
|
||||
versions: {
|
||||
drafts: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
graphQL: {
|
||||
queries: (GraphQL) => {
|
||||
return {
|
||||
|
||||
@@ -984,6 +984,59 @@ describe('collections-graphql', () => {
|
||||
expect(queriedDoc.media.title).toEqual('example')
|
||||
})
|
||||
})
|
||||
|
||||
it('should cascade draft arg with globals', async () => {
|
||||
// publish relationship doc
|
||||
const newDoc = await payload.create({
|
||||
collection: 'cyclical-relationship',
|
||||
draft: false,
|
||||
data: {
|
||||
title: 'published relationship',
|
||||
},
|
||||
})
|
||||
|
||||
// save draft version relationship doc
|
||||
await payload.update({
|
||||
collection: 'cyclical-relationship',
|
||||
id: newDoc.id,
|
||||
draft: true,
|
||||
data: {
|
||||
title: 'draft relationship',
|
||||
},
|
||||
})
|
||||
|
||||
// update global (published data)
|
||||
await payload.updateGlobal({
|
||||
slug: 'global-1',
|
||||
data: {
|
||||
title: 'published title',
|
||||
relationship: newDoc.id,
|
||||
},
|
||||
})
|
||||
|
||||
// update global (draft data)
|
||||
await payload.updateGlobal({
|
||||
slug: 'global-1',
|
||||
draft: true,
|
||||
data: {
|
||||
title: 'draft title',
|
||||
},
|
||||
})
|
||||
|
||||
const query = `{
|
||||
Global1(draft: true) {
|
||||
title
|
||||
relationship {
|
||||
title
|
||||
}
|
||||
}
|
||||
}`
|
||||
const response = (await client.request(query)) as any
|
||||
|
||||
const queriedGlobal = response.Global1
|
||||
expect(queriedGlobal.title).toEqual('draft title')
|
||||
expect(queriedGlobal.relationship.title).toEqual('draft relationship')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Error Handler', () => {
|
||||
|
||||
@@ -78,6 +78,26 @@ describe('fields', () => {
|
||||
).toBeHidden()
|
||||
})
|
||||
|
||||
test('should not display admin.disableListColumn true field in list view column selector if toggling other fields', async () => {
|
||||
await page.goto(url.list)
|
||||
await page.locator('.list-controls__toggle-columns').click()
|
||||
|
||||
await expect(page.locator('.column-selector')).toBeVisible()
|
||||
|
||||
// Click another field in column selector
|
||||
const updatedAtButton = page.locator(`.column-selector .column-selector__column`, {
|
||||
hasText: exactText('Updated At'),
|
||||
})
|
||||
await updatedAtButton.click()
|
||||
|
||||
// Check if "Disable List Column Text" is not present in the column options
|
||||
await expect(
|
||||
page.locator(`.column-selector .column-selector__column`, {
|
||||
hasText: exactText('Disable List Column Text'),
|
||||
}),
|
||||
).toBeHidden()
|
||||
})
|
||||
|
||||
test('should display field in list view filter selector if admin.disableListColumn is true and admin.disableListFilter is false', async () => {
|
||||
await page.goto(url.list)
|
||||
await page.locator('.list-controls__toggle-where').click()
|
||||
|
||||
@@ -19,6 +19,13 @@ const access = {
|
||||
}
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
collections: [
|
||||
{
|
||||
slug: 'media',
|
||||
upload: true,
|
||||
fields: [],
|
||||
},
|
||||
],
|
||||
globals: [
|
||||
{
|
||||
access,
|
||||
@@ -31,6 +38,11 @@ export default buildConfigWithDefaults({
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'media',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
},
|
||||
],
|
||||
slug,
|
||||
},
|
||||
|
||||
29
test/globals/e2e.spec.ts
Normal file
29
test/globals/e2e.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
|
||||
import { expect, test } from '@playwright/test'
|
||||
|
||||
import { initPageConsoleErrorCatch } from '../helpers'
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil'
|
||||
import { initPayloadE2E } from '../helpers/configHelpers'
|
||||
|
||||
const { beforeAll, describe } = test
|
||||
|
||||
describe('Globals', () => {
|
||||
let page: Page
|
||||
let url: AdminUrlUtil
|
||||
|
||||
beforeAll(async ({ browser }) => {
|
||||
const { serverURL } = await initPayloadE2E(__dirname)
|
||||
url = new AdminUrlUtil(serverURL, 'media')
|
||||
|
||||
const context = await browser.newContext()
|
||||
page = await context.newPage()
|
||||
initPageConsoleErrorCatch(page)
|
||||
})
|
||||
|
||||
test('can edit media from field', async () => {
|
||||
await page.goto(url.create)
|
||||
|
||||
// const textCell = page.locator('.row-1 .cell-text')
|
||||
})
|
||||
})
|
||||
@@ -101,6 +101,13 @@ export const selectTableRow = async (page: Page, title: string): Promise<void> =
|
||||
expect(await page.locator(selector).isChecked()).toBe(true)
|
||||
}
|
||||
|
||||
export async function navigateToListCellLink(page: Page, selector = '.cell-id') {
|
||||
const cellLink = page.locator(`${selector} a`).first()
|
||||
const linkURL = await cellLink.getAttribute('href')
|
||||
await cellLink.click()
|
||||
await page.waitForURL(`**${linkURL}`)
|
||||
}
|
||||
|
||||
export const findTableCell = async (
|
||||
page: Page,
|
||||
fieldName: string,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Users } from './collections/Users'
|
||||
import { Footer } from './globals/Footer'
|
||||
import { Header } from './globals/Header'
|
||||
import { seed } from './seed'
|
||||
import { mobileBreakpoint } from './shared'
|
||||
import { desktopBreakpoint, mobileBreakpoint } from './shared'
|
||||
import { formatLivePreviewURL } from './utilities/formatLivePreviewURL'
|
||||
|
||||
const mockModulePath = path.resolve(__dirname, './mocks/mockFSModule.js')
|
||||
@@ -21,7 +21,7 @@ export default buildConfigWithDefaults({
|
||||
// You can define any of these properties on a per collection or global basis
|
||||
// The Live Preview config cascades from the top down, properties are inherited from here
|
||||
url: formatLivePreviewURL,
|
||||
breakpoints: [mobileBreakpoint],
|
||||
breakpoints: [mobileBreakpoint, desktopBreakpoint],
|
||||
collections: ['pages', 'posts'],
|
||||
globals: ['header', 'footer'],
|
||||
},
|
||||
|
||||
@@ -5,7 +5,14 @@ import { expect, test } from '@playwright/test'
|
||||
import { exactText, initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers'
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil'
|
||||
import { initPayloadE2E } from '../helpers/configHelpers'
|
||||
import { mobileBreakpoint } from './shared'
|
||||
import {
|
||||
ensureDeviceIsCentered,
|
||||
ensureDeviceIsLeftAligned,
|
||||
goToCollectionLivePreview,
|
||||
selectLivePreviewBreakpoint,
|
||||
selectLivePreviewZoom,
|
||||
} from './helpers'
|
||||
import { desktopBreakpoint, mobileBreakpoint } from './shared'
|
||||
import { startLivePreviewDemo } from './startLivePreviewDemo'
|
||||
|
||||
const { beforeAll, describe } = test
|
||||
@@ -216,4 +223,34 @@ describe('Live Preview', () => {
|
||||
const height = parseInt(heightInputValue)
|
||||
expect(height).toBe(mobileBreakpoint.height)
|
||||
})
|
||||
|
||||
test('device — centers device when smaller than frame despite zoom', async () => {
|
||||
await goToCollectionLivePreview(page, url)
|
||||
await selectLivePreviewBreakpoint(page, mobileBreakpoint.label)
|
||||
await ensureDeviceIsCentered(page)
|
||||
await selectLivePreviewZoom(page, '75%')
|
||||
await ensureDeviceIsCentered(page)
|
||||
await selectLivePreviewZoom(page, '50%')
|
||||
await ensureDeviceIsCentered(page)
|
||||
await selectLivePreviewZoom(page, '125%')
|
||||
await ensureDeviceIsCentered(page)
|
||||
await selectLivePreviewZoom(page, '200%')
|
||||
await ensureDeviceIsCentered(page)
|
||||
expect(true).toBeTruthy()
|
||||
})
|
||||
|
||||
test('device — left-aligns device when larger than frame despite zoom', async () => {
|
||||
await goToCollectionLivePreview(page, url)
|
||||
await selectLivePreviewBreakpoint(page, desktopBreakpoint.label)
|
||||
await ensureDeviceIsLeftAligned(page)
|
||||
await selectLivePreviewZoom(page, '75%')
|
||||
await ensureDeviceIsLeftAligned(page)
|
||||
await selectLivePreviewZoom(page, '50%')
|
||||
await ensureDeviceIsLeftAligned(page)
|
||||
await selectLivePreviewZoom(page, '125%')
|
||||
await ensureDeviceIsLeftAligned(page)
|
||||
await selectLivePreviewZoom(page, '200%')
|
||||
await ensureDeviceIsLeftAligned(page)
|
||||
expect(true).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
124
test/live-preview/helpers.ts
Normal file
124
test/live-preview/helpers.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
import { exactText, navigateToListCellLink } from '../helpers.js'
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
|
||||
|
||||
export const EXPECT_TIMEOUT = 8000
|
||||
export const POLL_TOPASS_TIMEOUT = EXPECT_TIMEOUT * 4
|
||||
|
||||
export const goToDoc = async (page: Page, urlUtil: AdminUrlUtil) => {
|
||||
await page.goto(urlUtil.list)
|
||||
await page.waitForURL(urlUtil.list)
|
||||
await navigateToListCellLink(page)
|
||||
}
|
||||
|
||||
export const goToCollectionLivePreview = async (
|
||||
page: Page,
|
||||
urlUtil: AdminUrlUtil,
|
||||
): Promise<void> => {
|
||||
await goToDoc(page, urlUtil)
|
||||
await page.goto(`${page.url()}/preview`)
|
||||
await page.waitForURL(`**/preview`)
|
||||
}
|
||||
|
||||
export const goToGlobalLivePreview = async (
|
||||
page: Page,
|
||||
slug: string,
|
||||
serverURL: string,
|
||||
): Promise<void> => {
|
||||
const global = new AdminUrlUtil(serverURL, slug)
|
||||
const previewURL = `${global.global(slug)}/preview`
|
||||
await page.goto(previewURL)
|
||||
await page.waitForURL(previewURL)
|
||||
}
|
||||
|
||||
export const selectLivePreviewBreakpoint = async (page: Page, breakpointLabel: string) => {
|
||||
const breakpointSelector = page.locator(
|
||||
'.live-preview-toolbar-controls__breakpoint button.popup-button',
|
||||
)
|
||||
|
||||
await expect(() => expect(breakpointSelector).toBeTruthy()).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
|
||||
await breakpointSelector.first().click()
|
||||
|
||||
await page
|
||||
.locator(`.live-preview-toolbar-controls__breakpoint button.popup-button-list__button`)
|
||||
.filter({ hasText: breakpointLabel })
|
||||
.click()
|
||||
|
||||
await expect(breakpointSelector).toContainText(breakpointLabel)
|
||||
|
||||
const option = page.locator(
|
||||
'.live-preview-toolbar-controls__breakpoint button.popup-button-list__button--selected',
|
||||
)
|
||||
|
||||
await expect(option).toHaveText(breakpointLabel)
|
||||
}
|
||||
|
||||
export const selectLivePreviewZoom = async (page: Page, zoomLabel: string) => {
|
||||
const zoomSelector = page.locator('.live-preview-toolbar-controls__zoom button.popup-button')
|
||||
|
||||
await expect(() => expect(zoomSelector).toBeTruthy()).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
|
||||
await zoomSelector.first().click()
|
||||
|
||||
const zoomOption = page.locator(
|
||||
'.live-preview-toolbar-controls__zoom button.popup-button-list__button',
|
||||
{
|
||||
hasText: exactText(zoomLabel),
|
||||
},
|
||||
)
|
||||
|
||||
expect(zoomOption).toBeTruthy()
|
||||
await zoomOption.click()
|
||||
|
||||
await expect(zoomSelector).toContainText(zoomLabel)
|
||||
|
||||
const option = page.locator(
|
||||
'.live-preview-toolbar-controls__zoom button.popup-button-list__button--selected',
|
||||
)
|
||||
|
||||
await expect(option).toHaveText(zoomLabel)
|
||||
}
|
||||
|
||||
export const ensureDeviceIsCentered = async (page: Page) => {
|
||||
const main = page.locator('.live-preview-window__main')
|
||||
const iframe = page.locator('iframe.live-preview-iframe')
|
||||
const mainBoxAfterZoom = await main.boundingBox()
|
||||
const iframeBoxAfterZoom = await iframe.boundingBox()
|
||||
const distanceFromIframeLeftToMainLeftAfterZoom = Math.abs(
|
||||
mainBoxAfterZoom?.x - iframeBoxAfterZoom?.x,
|
||||
)
|
||||
const distanceFromIFrameRightToMainRightAfterZoom = Math.abs(
|
||||
mainBoxAfterZoom?.x +
|
||||
mainBoxAfterZoom?.width -
|
||||
iframeBoxAfterZoom?.x -
|
||||
iframeBoxAfterZoom?.width,
|
||||
)
|
||||
await expect(() =>
|
||||
expect(distanceFromIframeLeftToMainLeftAfterZoom).toBe(
|
||||
distanceFromIFrameRightToMainRightAfterZoom,
|
||||
),
|
||||
).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
}
|
||||
|
||||
export const ensureDeviceIsLeftAligned = async (page: Page) => {
|
||||
const main = page.locator('.live-preview-window__main > div')
|
||||
const iframe = page.locator('iframe.live-preview-iframe')
|
||||
const mainBoxAfterZoom = await main.boundingBox()
|
||||
const iframeBoxAfterZoom = await iframe.boundingBox()
|
||||
const distanceFromIframeLeftToMainLeftAfterZoom = Math.abs(
|
||||
mainBoxAfterZoom?.x - iframeBoxAfterZoom?.x,
|
||||
)
|
||||
await expect(() => expect(distanceFromIframeLeftToMainLeftAfterZoom).toBe(0)).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
}
|
||||
@@ -8,3 +8,10 @@ export const mobileBreakpoint = {
|
||||
width: 375,
|
||||
height: 667,
|
||||
}
|
||||
|
||||
export const desktopBreakpoint = {
|
||||
label: 'Desktop',
|
||||
name: 'desktop',
|
||||
width: 1920,
|
||||
height: 1024,
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
cropOnlySlug,
|
||||
enlargeSlug,
|
||||
focalOnlySlug,
|
||||
globalWithMedia,
|
||||
mediaSlug,
|
||||
reduceSlug,
|
||||
relationSlug,
|
||||
@@ -491,6 +492,18 @@ export default buildConfigWithDefaults({
|
||||
},
|
||||
},
|
||||
],
|
||||
globals: [
|
||||
{
|
||||
slug: globalWithMedia,
|
||||
fields: [
|
||||
{
|
||||
type: 'upload',
|
||||
name: 'media',
|
||||
relationTo: cropOnlySlug,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
onInit: async (payload) => {
|
||||
const uploadsDir = path.resolve(__dirname, './media')
|
||||
removeFiles(path.normalize(uploadsDir))
|
||||
|
||||
@@ -12,7 +12,7 @@ import { AdminUrlUtil } from '../helpers/adminUrlUtil'
|
||||
import { initPayloadE2E } from '../helpers/configHelpers'
|
||||
import { RESTClient } from '../helpers/rest'
|
||||
import { adminThumbnailSrc } from './collections/admin-thumbnail'
|
||||
import { adminThumbnailSlug, audioSlug, mediaSlug, relationSlug } from './shared'
|
||||
import { adminThumbnailSlug, audioSlug, globalWithMedia, mediaSlug, relationSlug } from './shared'
|
||||
|
||||
const { beforeAll, describe } = test
|
||||
|
||||
@@ -21,6 +21,7 @@ let mediaURL: AdminUrlUtil
|
||||
let audioURL: AdminUrlUtil
|
||||
let relationURL: AdminUrlUtil
|
||||
let adminThumbnailURL: AdminUrlUtil
|
||||
let globalURL: string
|
||||
|
||||
describe('uploads', () => {
|
||||
let page: Page
|
||||
@@ -36,6 +37,7 @@ describe('uploads', () => {
|
||||
audioURL = new AdminUrlUtil(serverURL, audioSlug)
|
||||
relationURL = new AdminUrlUtil(serverURL, relationSlug)
|
||||
adminThumbnailURL = new AdminUrlUtil(serverURL, adminThumbnailSlug)
|
||||
globalURL = new AdminUrlUtil(serverURL, globalWithMedia).global(globalWithMedia)
|
||||
|
||||
const context = await browser.newContext()
|
||||
page = await context.newPage()
|
||||
@@ -323,4 +325,17 @@ describe('uploads', () => {
|
||||
expect(redDoc.filesize).toEqual(1207)
|
||||
})
|
||||
})
|
||||
|
||||
describe('globals', () => {
|
||||
test('should be able to crop media from a global', async () => {
|
||||
await page.goto(globalURL)
|
||||
await page.click('.upload__toggler.doc-drawer__toggler')
|
||||
await page.setInputFiles('input[type="file"]', path.resolve(__dirname, './image.png'))
|
||||
await page.click('.file-field__edit')
|
||||
await page.click('.btn.edit-upload__save')
|
||||
await saveDocAndAssert(page, '.drawer__content #action-save')
|
||||
await saveDocAndAssert(page)
|
||||
await expect(page.locator('.thumbnail img')).toBeVisible()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,3 +7,4 @@ export const mediaSlug = 'media'
|
||||
export const reduceSlug = 'reduce'
|
||||
export const relationSlug = 'relation'
|
||||
export const versionSlug = 'versions'
|
||||
export const globalWithMedia = 'global-with-media'
|
||||
|
||||
Reference in New Issue
Block a user