chore: eslint and prettier
This commit is contained in:
3
packages/plugin-search/.eslintrc.js
Normal file
3
packages/plugin-search/.eslintrc.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: ['@payloadcms'],
|
||||
}
|
||||
8
packages/plugin-search/.prettierrc.js
Normal file
8
packages/plugin-search/.prettierrc.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
printWidth: 100,
|
||||
parser: "typescript",
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
trailingComma: "all",
|
||||
arrowParens: "avoid",
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
export const Pages: CollectionConfig = {
|
||||
slug: 'pages',
|
||||
@@ -10,7 +10,7 @@ export const Pages: CollectionConfig = {
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
versions: {
|
||||
drafts: true
|
||||
drafts: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
@@ -23,6 +23,6 @@ export const Pages: CollectionConfig = {
|
||||
name: 'excerpt',
|
||||
label: 'Excerpt',
|
||||
type: 'text',
|
||||
}
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
export const Posts: CollectionConfig = {
|
||||
slug: 'posts',
|
||||
@@ -10,7 +10,7 @@ export const Posts: CollectionConfig = {
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
versions: {
|
||||
drafts: true
|
||||
drafts: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
@@ -23,6 +23,6 @@ export const Posts: CollectionConfig = {
|
||||
name: 'excerpt',
|
||||
label: 'Excerpt',
|
||||
type: 'text',
|
||||
}
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
export const Users: CollectionConfig = {
|
||||
slug: 'users',
|
||||
@@ -13,4 +13,4 @@ export const Users: CollectionConfig = {
|
||||
// Email added by default
|
||||
// Add more fields as needed
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,43 +1,37 @@
|
||||
import { buildConfig } from 'payload/config';
|
||||
import path from 'path';
|
||||
import path from 'path'
|
||||
import { buildConfig } from 'payload/config'
|
||||
|
||||
// import searchPlugin from '../../dist';
|
||||
import searchPlugin from '../../src';
|
||||
import { Users } from './collections/Users';
|
||||
import { Pages } from './collections/Pages';
|
||||
import { Posts } from './collections/Posts';
|
||||
import searchPlugin from '../../src'
|
||||
import { Pages } from './collections/Pages'
|
||||
import { Posts } from './collections/Posts'
|
||||
import { Users } from './collections/Users'
|
||||
|
||||
export default buildConfig({
|
||||
serverURL: 'http://localhost:3000',
|
||||
admin: {
|
||||
user: Users.slug,
|
||||
webpack: (config) => {
|
||||
webpack: config => {
|
||||
const newConfig = {
|
||||
...config,
|
||||
resolve: {
|
||||
...config.resolve,
|
||||
alias: {
|
||||
...config.resolve.alias,
|
||||
react: path.join(__dirname, "../node_modules/react"),
|
||||
"react-dom": path.join(__dirname, "../node_modules/react-dom"),
|
||||
"payload": path.join(__dirname, "../node_modules/payload")
|
||||
react: path.join(__dirname, '../node_modules/react'),
|
||||
'react-dom': path.join(__dirname, '../node_modules/react-dom'),
|
||||
payload: path.join(__dirname, '../node_modules/payload'),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return newConfig;
|
||||
return newConfig
|
||||
},
|
||||
},
|
||||
collections: [
|
||||
Users,
|
||||
Pages,
|
||||
Posts
|
||||
],
|
||||
collections: [Users, Pages, Posts],
|
||||
plugins: [
|
||||
searchPlugin({
|
||||
collections: [
|
||||
'pages',
|
||||
'posts'
|
||||
],
|
||||
collections: ['pages', 'posts'],
|
||||
searchOverrides: {
|
||||
fields: [
|
||||
{
|
||||
@@ -46,21 +40,21 @@ export default buildConfig({
|
||||
type: 'text',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
beforeSync: ({ originalDoc, searchDoc }) => ({
|
||||
...searchDoc,
|
||||
excerpt: originalDoc?.excerpt || 'This is a fallback excerpt'
|
||||
excerpt: originalDoc?.excerpt || 'This is a fallback excerpt',
|
||||
}),
|
||||
defaultPriorities: {
|
||||
pages: 10,
|
||||
posts: ({ title }) => title === 'Hello, world!' ? 30 : 20
|
||||
}
|
||||
posts: ({ title }) => (title === 'Hello, world!' ? 30 : 20),
|
||||
},
|
||||
}),
|
||||
],
|
||||
typescript: {
|
||||
outputFile: path.resolve(__dirname, 'payload-types.ts')
|
||||
outputFile: path.resolve(__dirname, 'payload-types.ts'),
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import express from 'express';
|
||||
import payload from 'payload';
|
||||
import dotenv from 'dotenv'
|
||||
import express from 'express'
|
||||
import payload from 'payload'
|
||||
|
||||
require('dotenv').config();
|
||||
const app = express();
|
||||
dotenv.config()
|
||||
const app = express()
|
||||
|
||||
// Redirect root to Admin panel
|
||||
app.get('/', (_, res) => {
|
||||
res.redirect('/admin');
|
||||
});
|
||||
res.redirect('/admin')
|
||||
})
|
||||
|
||||
// Initialize Payload
|
||||
payload.init({
|
||||
@@ -15,10 +16,10 @@ payload.init({
|
||||
mongoURL: process.env.MONGODB_URI,
|
||||
express: app,
|
||||
onInit: () => {
|
||||
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`);
|
||||
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`)
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
// Add your own express routes here
|
||||
|
||||
app.listen(3000);
|
||||
app.listen(3000)
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
"version": "1.0.0",
|
||||
"homepage:": "https://payloadcms.com",
|
||||
"repository": "git@github.com:payloadcms/plugin-search.git",
|
||||
"description": "Search plugin for Payload CMS",
|
||||
"description": "Search plugin for Payload",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint --fix --ext .ts,.tsx src"
|
||||
},
|
||||
"keywords": [
|
||||
"payload",
|
||||
@@ -25,17 +27,35 @@
|
||||
"payload": "^0.18.5",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ts-deepmerge": "^2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@payloadcms/eslint-config": "^0.0.1",
|
||||
"@types/express": "^4.17.9",
|
||||
"@types/node": "18.11.3",
|
||||
"@types/react": "18.0.21",
|
||||
"@typescript-eslint/eslint-plugin": "^5.51.0",
|
||||
"@typescript-eslint/parser": "^5.51.0",
|
||||
"copyfiles": "^2.4.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.19.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-filenames": "^1.3.2",
|
||||
"eslint-plugin-import": "2.25.4",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||
"nodemon": "^2.0.6",
|
||||
"payload": "^0.18.5",
|
||||
"react": "^17.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"prettier": "^2.7.1",
|
||||
"react": "^18.0.0",
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"types.js",
|
||||
"types.d.ts"
|
||||
],
|
||||
"dependencies": {
|
||||
"ts-deepmerge": "^2.0.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { CollectionAfterDeleteHook } from 'payload/types';
|
||||
import type { CollectionAfterDeleteHook } from 'payload/types'
|
||||
|
||||
const deleteFromSearch: CollectionAfterDeleteHook = ({ req: { payload }, doc }) => {
|
||||
try {
|
||||
const deleteSearchDoc = async () => {
|
||||
const deleteSearchDoc = async (): Promise<any> => {
|
||||
const searchDocQuery = await payload.find({
|
||||
collection: 'search',
|
||||
where: {
|
||||
@@ -11,22 +11,24 @@ const deleteFromSearch: CollectionAfterDeleteHook = ({ req: { payload }, doc })
|
||||
},
|
||||
},
|
||||
depth: 0,
|
||||
}) as any;
|
||||
})
|
||||
|
||||
if (searchDocQuery?.docs?.[0]) {
|
||||
payload.delete({
|
||||
collection: 'search',
|
||||
id: searchDocQuery?.docs?.[0]?.id,
|
||||
});
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
deleteSearchDoc();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
deleteSearchDoc()
|
||||
} catch (err: unknown) {
|
||||
payload.logger.error({
|
||||
err: `Error deleting search doc: ${err}`,
|
||||
})
|
||||
}
|
||||
|
||||
return doc;
|
||||
};
|
||||
return doc
|
||||
}
|
||||
|
||||
export default deleteFromSearch;
|
||||
export default deleteFromSearch
|
||||
|
||||
@@ -1,28 +1,19 @@
|
||||
import { SearchConfig, SyncWithSearch } from '../../types';
|
||||
import type { SearchConfig, SyncWithSearch } from '../../types'
|
||||
|
||||
const syncWithSearch: SyncWithSearch = async (args) => {
|
||||
const syncWithSearch: SyncWithSearch = async args => {
|
||||
const {
|
||||
req: { payload },
|
||||
doc,
|
||||
operation,
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
collection,
|
||||
// @ts-ignore
|
||||
searchConfig
|
||||
} = args;
|
||||
// @ts-expect-error
|
||||
searchConfig,
|
||||
} = args
|
||||
|
||||
const {
|
||||
title,
|
||||
id,
|
||||
_status: status,
|
||||
} = doc || {};
|
||||
const { title, id, _status: status } = doc || {}
|
||||
|
||||
const {
|
||||
beforeSync,
|
||||
syncDrafts,
|
||||
deleteDrafts,
|
||||
defaultPriorities,
|
||||
} = searchConfig as SearchConfig; // todo fix SyncWithSearch type, see note in ./types.ts
|
||||
const { beforeSync, syncDrafts, deleteDrafts, defaultPriorities } = searchConfig as SearchConfig // todo fix SyncWithSearch type, see note in ./types.ts
|
||||
|
||||
let dataToSave = {
|
||||
title,
|
||||
@@ -30,35 +21,35 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
||||
relationTo: collection,
|
||||
value: id,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof beforeSync === 'function') {
|
||||
dataToSave = await beforeSync({
|
||||
originalDoc: doc,
|
||||
searchDoc: dataToSave,
|
||||
payload
|
||||
});
|
||||
payload,
|
||||
})
|
||||
}
|
||||
|
||||
let defaultPriority = 0;
|
||||
let defaultPriority = 0
|
||||
if (defaultPriorities) {
|
||||
const {
|
||||
[collection]: priority,
|
||||
} = defaultPriorities;
|
||||
const { [collection]: priority } = defaultPriorities
|
||||
|
||||
if (typeof priority === 'function') {
|
||||
try {
|
||||
defaultPriority = await priority(doc);
|
||||
} catch (err) {
|
||||
payload.logger.error(err);
|
||||
payload.logger.error(`Error gathering default priority for search documents related to ${collection}`);
|
||||
defaultPriority = await priority(doc)
|
||||
} catch (err: unknown) {
|
||||
payload.logger.error(err)
|
||||
payload.logger.error(
|
||||
`Error gathering default priority for search documents related to ${collection}`,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
defaultPriority = priority;
|
||||
defaultPriority = priority
|
||||
}
|
||||
}
|
||||
|
||||
const doSync = syncDrafts || (!syncDrafts && status !== 'draft');
|
||||
const doSync = syncDrafts || (!syncDrafts && status !== 'draft')
|
||||
|
||||
try {
|
||||
if (operation === 'create') {
|
||||
@@ -69,7 +60,7 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
||||
...dataToSave,
|
||||
priority: defaultPriority,
|
||||
},
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,32 +75,34 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
||||
},
|
||||
},
|
||||
depth: 0,
|
||||
}) as any;
|
||||
})
|
||||
|
||||
const docs: {
|
||||
const docs: Array<{
|
||||
id: string
|
||||
priority?: number
|
||||
}[] = searchDocQuery?.docs || [];
|
||||
}> = searchDocQuery?.docs || []
|
||||
|
||||
const [foundDoc, ...duplicativeDocs] = docs;
|
||||
const [foundDoc, ...duplicativeDocs] = docs
|
||||
|
||||
// delete all duplicative search docs (docs that reference the same page)
|
||||
// to ensure the same, out-of-date result does not appear twice (where only syncing the first found doc)
|
||||
if (duplicativeDocs.length > 0) {
|
||||
try {
|
||||
Promise.all(duplicativeDocs.map(({ id: duplicativeDocID }) => payload.delete({
|
||||
collection: 'search',
|
||||
id: duplicativeDocID,
|
||||
})));
|
||||
} catch (err) {
|
||||
payload.logger.error(`Error deleting duplicative search documents.`);
|
||||
Promise.all(
|
||||
duplicativeDocs.map(({ id: duplicativeDocID }) =>
|
||||
payload.delete({
|
||||
collection: 'search',
|
||||
id: duplicativeDocID,
|
||||
}),
|
||||
), // eslint-disable-line function-paren-newline
|
||||
)
|
||||
} catch (err: unknown) {
|
||||
payload.logger.error(`Error deleting duplicative search documents.`)
|
||||
}
|
||||
}
|
||||
|
||||
if (foundDoc) {
|
||||
const {
|
||||
id: searchDocID,
|
||||
} = foundDoc;
|
||||
const { id: searchDocID } = foundDoc
|
||||
|
||||
if (doSync) {
|
||||
// update the doc normally
|
||||
@@ -121,9 +114,9 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
||||
...dataToSave,
|
||||
priority: foundDoc.priority || defaultPriority,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
payload.logger.error(`Error updating search document.`);
|
||||
})
|
||||
} catch (err: unknown) {
|
||||
payload.logger.error(`Error updating search document.`)
|
||||
}
|
||||
}
|
||||
if (deleteDrafts && status === 'draft') {
|
||||
@@ -132,9 +125,9 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
||||
payload.delete({
|
||||
collection: 'search',
|
||||
id: searchDocID,
|
||||
});
|
||||
} catch (err) {
|
||||
payload.logger.error(`Error deleting search document.`);
|
||||
})
|
||||
} catch (err: unknown) {
|
||||
payload.logger.error(`Error deleting search document: ${err}`)
|
||||
}
|
||||
}
|
||||
} else if (doSync) {
|
||||
@@ -145,22 +138,22 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
||||
...dataToSave,
|
||||
priority: defaultPriority,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
payload.logger.error(err);
|
||||
payload.logger.error(`Error creating search document.`);
|
||||
})
|
||||
} catch (err: unknown) {
|
||||
payload.logger.error(`Error creating search document: ${err}`)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
payload.logger.error(`Error finding search document.`);
|
||||
} catch (err: unknown) {
|
||||
payload.logger.error(`Error finding search document: ${err}`)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
payload.logger.error(err);
|
||||
payload.logger.error(`Error syncing search document related to ${collection} with id: '${id}'`);
|
||||
} catch (err: unknown) {
|
||||
payload.logger.error(
|
||||
`Error syncing search document related to ${collection} with id: '${id}': ${err}`,
|
||||
)
|
||||
}
|
||||
|
||||
return doc;
|
||||
};
|
||||
return doc
|
||||
}
|
||||
|
||||
export default syncWithSearch;
|
||||
export default syncWithSearch
|
||||
|
||||
@@ -1,63 +1,67 @@
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
import { SearchConfig } from '../types';
|
||||
import deepMerge from 'ts-deepmerge';
|
||||
import { LinkToDoc } from './ui';
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
import deepMerge from 'ts-deepmerge'
|
||||
|
||||
import type { SearchConfig } from '../types'
|
||||
import { LinkToDoc } from './ui'
|
||||
|
||||
// all settings can be overridden by the config
|
||||
export const generateSearchCollection = (searchConfig: SearchConfig): CollectionConfig => deepMerge({
|
||||
slug: 'search',
|
||||
labels: {
|
||||
singular: 'Search Result',
|
||||
plural: 'Search Results',
|
||||
},
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
defaultColumns: [
|
||||
'title',
|
||||
],
|
||||
description: 'This is a collection of automatically created search results. These results are used by the global site search and will be updated automatically as documents in the CMS are created or updated.',
|
||||
enableRichTextRelationship: false,
|
||||
},
|
||||
access: {
|
||||
read: (): boolean => true,
|
||||
create: (): boolean => false,
|
||||
},
|
||||
fields: [
|
||||
export const generateSearchCollection = (searchConfig: SearchConfig): CollectionConfig =>
|
||||
deepMerge(
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'priority',
|
||||
type: 'number',
|
||||
admin: {
|
||||
position: 'sidebar'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'doc',
|
||||
type: 'relationship',
|
||||
relationTo: searchConfig?.collections || [],
|
||||
required: true,
|
||||
index: true,
|
||||
maxDepth: 0,
|
||||
admin: {
|
||||
readOnly: true,
|
||||
position: 'sidebar'
|
||||
slug: 'search',
|
||||
labels: {
|
||||
singular: 'Search Result',
|
||||
plural: 'Search Results',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'docUrl',
|
||||
type: 'ui',
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
components: {
|
||||
Field: LinkToDoc
|
||||
}
|
||||
useAsTitle: 'title',
|
||||
defaultColumns: ['title'],
|
||||
description:
|
||||
'This is a collection of automatically created search results. These results are used by the global site search and will be updated automatically as documents in the CMS are created or updated.',
|
||||
enableRichTextRelationship: false,
|
||||
},
|
||||
access: {
|
||||
read: (): boolean => true,
|
||||
create: (): boolean => false,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'priority',
|
||||
type: 'number',
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'doc',
|
||||
type: 'relationship',
|
||||
relationTo: searchConfig?.collections || [],
|
||||
required: true,
|
||||
index: true,
|
||||
maxDepth: 0,
|
||||
admin: {
|
||||
readOnly: true,
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'docUrl',
|
||||
type: 'ui',
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
components: {
|
||||
Field: LinkToDoc,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}, searchConfig?.searchOverrides || {});
|
||||
searchConfig?.searchOverrides || {},
|
||||
)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import { useWatchForm } from 'payload/components/forms';
|
||||
import CopyToClipboard from 'payload/dist/admin/components/elements/CopyToClipboard';
|
||||
import { UIField } from 'payload/dist/fields/config/types';
|
||||
import { Fields } from 'payload/dist/admin/components/forms/Form/types';
|
||||
import { useConfig } from 'payload/components/utilities';
|
||||
import React from 'react'
|
||||
import { useWatchForm } from 'payload/components/forms'
|
||||
import { useConfig } from 'payload/components/utilities'
|
||||
import CopyToClipboard from 'payload/dist/admin/components/elements/CopyToClipboard'
|
||||
import { Fields } from 'payload/dist/admin/components/forms/Form/types'
|
||||
import { UIField } from 'payload/dist/fields/config/types'
|
||||
|
||||
type FieldsWithDoc = Fields & {
|
||||
doc: {
|
||||
@@ -15,26 +15,23 @@ type FieldsWithDoc = Fields & {
|
||||
}
|
||||
|
||||
export const LinkToDoc: React.FC<UIField> = () => {
|
||||
const form = useWatchForm();
|
||||
const fields = form.fields as FieldsWithDoc;
|
||||
const form = useWatchForm()
|
||||
const fields = form.fields as FieldsWithDoc
|
||||
|
||||
const {
|
||||
doc: {
|
||||
value: {
|
||||
relationTo,
|
||||
value: docId
|
||||
}
|
||||
}
|
||||
} = fields;
|
||||
value: { relationTo, value: docId },
|
||||
},
|
||||
} = fields
|
||||
|
||||
const config = useConfig();
|
||||
const config = useConfig()
|
||||
|
||||
const {
|
||||
serverURL,
|
||||
routes: {
|
||||
admin: adminRoute, // already includes leading slash
|
||||
} = {},
|
||||
} = config;
|
||||
} = config
|
||||
|
||||
const href = `${serverURL}${adminRoute}/collections/${relationTo}/${docId}`
|
||||
|
||||
@@ -44,26 +41,22 @@ export const LinkToDoc: React.FC<UIField> = () => {
|
||||
<span
|
||||
className="label"
|
||||
style={{
|
||||
color: '#9A9A9A'
|
||||
color: '#9A9A9A',
|
||||
}}
|
||||
>
|
||||
Doc URL
|
||||
</span>
|
||||
<CopyToClipboard
|
||||
value={href as string}
|
||||
/>
|
||||
<CopyToClipboard value={href as string} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
fontWeight: '600'
|
||||
fontWeight: '600',
|
||||
}}
|
||||
>
|
||||
<a href={href as string}>
|
||||
{href}
|
||||
</a>
|
||||
<a href={href as string}>{href}</a>
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
};
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,66 +1,64 @@
|
||||
import { Config } from 'payload/config';
|
||||
import { generateSearchCollection } from './Search';
|
||||
import syncWithSearch from './Search/hooks/syncWithSearch';
|
||||
import deleteFromSearch from './Search/hooks/deleteFromSearch';
|
||||
import { SearchConfig } from './types';
|
||||
import type { Config } from 'payload/config'
|
||||
|
||||
const Search = (incomingSearchConfig: SearchConfig) => (config: Config): Config => {
|
||||
const {
|
||||
collections
|
||||
} = config;
|
||||
import { generateSearchCollection } from './Search'
|
||||
import deleteFromSearch from './Search/hooks/deleteFromSearch'
|
||||
import syncWithSearch from './Search/hooks/syncWithSearch'
|
||||
import type { SearchConfig } from './types'
|
||||
|
||||
if (collections) {
|
||||
const searchConfig: SearchConfig = {
|
||||
...incomingSearchConfig,
|
||||
syncDrafts: false,
|
||||
deleteDrafts: true
|
||||
// write any config defaults here
|
||||
};
|
||||
const Search =
|
||||
(incomingSearchConfig: SearchConfig) =>
|
||||
(config: Config): Config => {
|
||||
const { collections } = config
|
||||
|
||||
// add a beforeChange hook to every search-enabled collection
|
||||
const collectionsWithSearchHooks = config?.collections?.map((collection) => {
|
||||
const {
|
||||
hooks: existingHooks
|
||||
} = collection;
|
||||
|
||||
const enabledCollections = searchConfig.collections || [];
|
||||
const isEnabled = enabledCollections.indexOf(collection.slug) > -1;
|
||||
if (isEnabled) {
|
||||
return {
|
||||
...collection,
|
||||
hooks: {
|
||||
...collection.hooks,
|
||||
afterChange: [
|
||||
...(existingHooks?.afterChange || []),
|
||||
async (args: any) => {
|
||||
syncWithSearch({
|
||||
...args,
|
||||
collection: collection.slug,
|
||||
searchConfig
|
||||
})
|
||||
},
|
||||
],
|
||||
afterDelete: [
|
||||
...(existingHooks?.afterDelete || []),
|
||||
deleteFromSearch,
|
||||
],
|
||||
},
|
||||
};
|
||||
if (collections) {
|
||||
const searchConfig: SearchConfig = {
|
||||
...incomingSearchConfig,
|
||||
syncDrafts: false,
|
||||
deleteDrafts: true,
|
||||
// write any config defaults here
|
||||
}
|
||||
|
||||
return collection;
|
||||
}).filter(Boolean);
|
||||
// add a beforeChange hook to every search-enabled collection
|
||||
const collectionsWithSearchHooks = config?.collections
|
||||
?.map(collection => {
|
||||
const { hooks: existingHooks } = collection
|
||||
|
||||
return {
|
||||
...config,
|
||||
collections: [
|
||||
...collectionsWithSearchHooks || [],
|
||||
generateSearchCollection(searchConfig),
|
||||
],
|
||||
};
|
||||
const enabledCollections = searchConfig.collections || []
|
||||
const isEnabled = enabledCollections.indexOf(collection.slug) > -1
|
||||
if (isEnabled) {
|
||||
return {
|
||||
...collection,
|
||||
hooks: {
|
||||
...collection.hooks,
|
||||
afterChange: [
|
||||
...(existingHooks?.afterChange || []),
|
||||
async (args: any) => {
|
||||
syncWithSearch({
|
||||
...args,
|
||||
collection: collection.slug,
|
||||
searchConfig,
|
||||
})
|
||||
},
|
||||
],
|
||||
afterDelete: [...(existingHooks?.afterDelete || []), deleteFromSearch],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return collection
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
return {
|
||||
...config,
|
||||
collections: [
|
||||
...(collectionsWithSearchHooks || []),
|
||||
generateSearchCollection(searchConfig),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
export default Search;
|
||||
export default Search
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Payload } from 'payload';
|
||||
import { CollectionAfterChangeHook, CollectionConfig } from 'payload/types';
|
||||
import type { Payload } from 'payload'
|
||||
import type { CollectionAfterChangeHook, CollectionConfig } from 'payload/types'
|
||||
|
||||
export type DocToSync = {
|
||||
export interface DocToSync {
|
||||
[key: string]: any
|
||||
title: string
|
||||
doc: {
|
||||
@@ -16,9 +16,9 @@ export type BeforeSync = (args: {
|
||||
}
|
||||
searchDoc: DocToSync
|
||||
payload: Payload
|
||||
}) => DocToSync | Promise<DocToSync>;
|
||||
}) => DocToSync | Promise<DocToSync>
|
||||
|
||||
export type SearchConfig = {
|
||||
export interface SearchConfig {
|
||||
searchOverrides?: Partial<CollectionConfig>
|
||||
collections?: string[]
|
||||
defaultPriorities?: {
|
||||
@@ -32,4 +32,4 @@ export type SearchConfig = {
|
||||
// TODO: extend this hook with additional args
|
||||
// searchConfig: SearchConfig
|
||||
// collection: string
|
||||
export type SyncWithSearch = CollectionAfterChangeHook;
|
||||
export type SyncWithSearch = CollectionAfterChangeHook
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user