@mvriu5/payload-ai 0.5.8 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AIActionProposalList.d.ts +2 -1
- package/dist/components/AIActionProposalList.js +74 -6
- package/dist/components/AIActionProposalList.module.css +49 -5
- package/dist/components/AIInput.js +125 -10
- package/dist/components/AIInput.module.css +27 -6
- package/dist/components/DiffDialog.d.ts +12 -0
- package/dist/components/DiffDialog.js +310 -0
- package/dist/components/DiffDialog.module.css +249 -0
- package/dist/components/Icons.d.ts +4 -0
- package/dist/components/Icons.js +87 -0
- package/dist/components/RecentChangesList.d.ts +18 -0
- package/dist/components/RecentChangesList.js +66 -0
- package/dist/components/RecentChangesList.module.css +135 -0
- package/dist/endpoints/aiApplyActionEndpointHandler.d.ts +1 -0
- package/dist/endpoints/aiApplyActionEndpointHandler.js +200 -4
- package/dist/endpoints/aiChatEndpointHandler.js +85 -24
- package/dist/endpoints/aiProposalDiffEndpointHandler.d.ts +7 -0
- package/dist/endpoints/aiProposalDiffEndpointHandler.js +138 -0
- package/dist/endpoints/aiRecentChangesEndpointHandler.d.ts +6 -0
- package/dist/endpoints/aiRecentChangesEndpointHandler.js +35 -0
- package/dist/index.js +111 -0
- package/dist/payload/schemaContext.d.ts +44 -1
- package/dist/payload/schemaContext.js +100 -12
- package/package.json +1 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { verifyAIActionProposal } from "../ai/proposals.js";
|
|
2
|
+
import { redactSensitiveData } from "../ai/sensitiveData.js";
|
|
3
|
+
import { getCollectionFields, normalizeAuthData, normalizeDataForFields } from "../payload/normalizeData.js";
|
|
4
|
+
import { isCollectionActionAllowed } from "../payload/collectionPermissions.js";
|
|
5
|
+
const isRecord = (value)=>{
|
|
6
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
7
|
+
};
|
|
8
|
+
const isActionProposal = (proposal)=>{
|
|
9
|
+
if (!isRecord(proposal) || typeof proposal.label !== "string") return false;
|
|
10
|
+
if (proposal.action === "create") {
|
|
11
|
+
return typeof proposal.collection === "string" && isRecord(proposal.data);
|
|
12
|
+
}
|
|
13
|
+
if (proposal.action === "update") {
|
|
14
|
+
return typeof proposal.collection === "string" && typeof proposal.id === "string" && isRecord(proposal.data);
|
|
15
|
+
}
|
|
16
|
+
if (proposal.action === "delete") {
|
|
17
|
+
return typeof proposal.collection === "string" && typeof proposal.id === "string";
|
|
18
|
+
}
|
|
19
|
+
if (proposal.action === "updateGlobal") {
|
|
20
|
+
return typeof proposal.slug === "string" && isRecord(proposal.data);
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
};
|
|
24
|
+
const mergeData = (current, next)=>{
|
|
25
|
+
return Object.fromEntries(Object.entries({
|
|
26
|
+
...current,
|
|
27
|
+
...next
|
|
28
|
+
}).map(([key, value])=>{
|
|
29
|
+
const currentValue = current[key];
|
|
30
|
+
if (isRecord(currentValue) && isRecord(value)) {
|
|
31
|
+
return [
|
|
32
|
+
key,
|
|
33
|
+
mergeData(currentValue, value)
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
return [
|
|
37
|
+
key,
|
|
38
|
+
value
|
|
39
|
+
];
|
|
40
|
+
}));
|
|
41
|
+
};
|
|
42
|
+
export const createAIProposalDiffEndpointHandler = (options = {})=>async (req)=>{
|
|
43
|
+
if (!req.user) return Response.json({
|
|
44
|
+
error: "Unauthorized"
|
|
45
|
+
}, {
|
|
46
|
+
status: 401
|
|
47
|
+
});
|
|
48
|
+
const body = req.json ? await req.json().catch(()=>null) : null;
|
|
49
|
+
const proposal = body?.proposal;
|
|
50
|
+
if (!proposal) return Response.json({
|
|
51
|
+
error: "Proposal is required"
|
|
52
|
+
}, {
|
|
53
|
+
status: 400
|
|
54
|
+
});
|
|
55
|
+
if (!verifyAIActionProposal(proposal)) return Response.json({
|
|
56
|
+
error: "Proposal signature is invalid or expired."
|
|
57
|
+
}, {
|
|
58
|
+
status: 400
|
|
59
|
+
});
|
|
60
|
+
if (!isActionProposal(proposal)) return Response.json({
|
|
61
|
+
error: "Proposal is invalid."
|
|
62
|
+
}, {
|
|
63
|
+
status: 400
|
|
64
|
+
});
|
|
65
|
+
try {
|
|
66
|
+
if (proposal.action === "updateGlobal") {
|
|
67
|
+
const globalConfig = req.payload.config.globals?.find((global)=>global.slug === proposal.slug);
|
|
68
|
+
if (!globalConfig) return Response.json({
|
|
69
|
+
error: "Unknown global"
|
|
70
|
+
}, {
|
|
71
|
+
status: 400
|
|
72
|
+
});
|
|
73
|
+
const normalized = normalizeDataForFields(globalConfig.fields || [], proposal.data);
|
|
74
|
+
const doc = await req.payload.findGlobal({
|
|
75
|
+
depth: 2,
|
|
76
|
+
overrideAccess: false,
|
|
77
|
+
req,
|
|
78
|
+
slug: proposal.slug
|
|
79
|
+
});
|
|
80
|
+
return Response.json({
|
|
81
|
+
after: redactSensitiveData(mergeData(doc, normalized.data)),
|
|
82
|
+
before: redactSensitiveData(doc)
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (!isCollectionActionAllowed({
|
|
86
|
+
action: proposal.action === "delete" ? "delete" : "read",
|
|
87
|
+
permissions: options.collections,
|
|
88
|
+
req,
|
|
89
|
+
slug: proposal.collection
|
|
90
|
+
})) return Response.json({
|
|
91
|
+
error: "Unknown collection"
|
|
92
|
+
}, {
|
|
93
|
+
status: 400
|
|
94
|
+
});
|
|
95
|
+
if (proposal.action === "delete") {
|
|
96
|
+
const doc = await req.payload.findByID({
|
|
97
|
+
collection: proposal.collection,
|
|
98
|
+
depth: 2,
|
|
99
|
+
id: proposal.id,
|
|
100
|
+
overrideAccess: false,
|
|
101
|
+
req
|
|
102
|
+
});
|
|
103
|
+
return Response.json({
|
|
104
|
+
after: {},
|
|
105
|
+
before: redactSensitiveData(doc)
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
const collectionConfig = req.payload.config.collections.find((collection)=>collection.slug === proposal.collection);
|
|
109
|
+
const normalized = normalizeAuthData(collectionConfig, normalizeDataForFields(getCollectionFields(collectionConfig), proposal.data));
|
|
110
|
+
if (proposal.action === "create") {
|
|
111
|
+
return Response.json({
|
|
112
|
+
after: redactSensitiveData(normalized.data),
|
|
113
|
+
before: {}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const doc = await req.payload.findByID({
|
|
117
|
+
collection: proposal.collection,
|
|
118
|
+
depth: 2,
|
|
119
|
+
id: proposal.id,
|
|
120
|
+
overrideAccess: false,
|
|
121
|
+
req
|
|
122
|
+
});
|
|
123
|
+
return Response.json({
|
|
124
|
+
after: redactSensitiveData(mergeData(doc, normalized.data)),
|
|
125
|
+
before: redactSensitiveData(doc)
|
|
126
|
+
});
|
|
127
|
+
} catch (err) {
|
|
128
|
+
req.payload.logger.error({
|
|
129
|
+
err,
|
|
130
|
+
msg: "AI proposal diff failed"
|
|
131
|
+
});
|
|
132
|
+
return Response.json({
|
|
133
|
+
error: "Could not load proposal diff."
|
|
134
|
+
}, {
|
|
135
|
+
status: 400
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const getNumber = (value)=>{
|
|
2
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
3
|
+
};
|
|
4
|
+
const getString = (value)=>{
|
|
5
|
+
return typeof value === "string" ? value : null;
|
|
6
|
+
};
|
|
7
|
+
export const createAIRecentChangesEndpointHandler = (options)=>async (req)=>{
|
|
8
|
+
if (!req.user) return Response.json({
|
|
9
|
+
error: "Unauthorized"
|
|
10
|
+
}, {
|
|
11
|
+
status: 401
|
|
12
|
+
});
|
|
13
|
+
const result = await req.payload.find({
|
|
14
|
+
collection: options.changeLogCollection,
|
|
15
|
+
depth: 0,
|
|
16
|
+
limit: 12,
|
|
17
|
+
overrideAccess: false,
|
|
18
|
+
req,
|
|
19
|
+
sort: "-createdAt"
|
|
20
|
+
});
|
|
21
|
+
return Response.json({
|
|
22
|
+
changes: result.docs.map((doc)=>({
|
|
23
|
+
action: getString(doc.action),
|
|
24
|
+
additions: getNumber(doc.additions),
|
|
25
|
+
after: doc.after,
|
|
26
|
+
before: doc.before,
|
|
27
|
+
collection: getString(doc.collection),
|
|
28
|
+
documentID: getString(doc.documentID),
|
|
29
|
+
removals: getNumber(doc.removals),
|
|
30
|
+
slug: getString(doc.slug),
|
|
31
|
+
title: getString(doc.title) || "AI change",
|
|
32
|
+
url: getString(doc.targetURL)
|
|
33
|
+
}))
|
|
34
|
+
});
|
|
35
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,101 @@ import { aiProviders, getResolvedAIModelConfig } from "./ai/providerOptions.js";
|
|
|
2
2
|
import { createAIApplyActionEndpointHandler } from "./endpoints/aiApplyActionEndpointHandler.js";
|
|
3
3
|
import { createAIChatEndpointHandler } from "./endpoints/aiChatEndpointHandler.js";
|
|
4
4
|
import { createAIMentionSuggestionsEndpointHandler } from "./endpoints/aiMentionSuggestionsEndpointHandler.js";
|
|
5
|
+
import { createAIProposalDiffEndpointHandler } from "./endpoints/aiProposalDiffEndpointHandler.js";
|
|
6
|
+
import { createAIRecentChangesEndpointHandler } from "./endpoints/aiRecentChangesEndpointHandler.js";
|
|
5
7
|
import { resolveCollectionPermissions } from "./payload/collectionPermissions.js";
|
|
6
8
|
import { isInternalCollection } from "./payload/shared.js";
|
|
9
|
+
const aiChangesCollectionSlug = "payload-ai-changes";
|
|
10
|
+
const createAIChangesCollection = ()=>({
|
|
11
|
+
slug: aiChangesCollectionSlug,
|
|
12
|
+
access: {
|
|
13
|
+
create: ()=>false,
|
|
14
|
+
delete: ()=>false,
|
|
15
|
+
read: ({ req })=>Boolean(req.user),
|
|
16
|
+
update: ()=>false
|
|
17
|
+
},
|
|
18
|
+
admin: {
|
|
19
|
+
defaultColumns: [
|
|
20
|
+
"title",
|
|
21
|
+
"action",
|
|
22
|
+
"additions",
|
|
23
|
+
"removals",
|
|
24
|
+
"createdAt"
|
|
25
|
+
],
|
|
26
|
+
group: "AI",
|
|
27
|
+
useAsTitle: "title"
|
|
28
|
+
},
|
|
29
|
+
fields: [
|
|
30
|
+
{
|
|
31
|
+
name: "title",
|
|
32
|
+
type: "text",
|
|
33
|
+
required: true
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "action",
|
|
37
|
+
type: "select",
|
|
38
|
+
options: [
|
|
39
|
+
"create",
|
|
40
|
+
"update",
|
|
41
|
+
"delete",
|
|
42
|
+
"updateGlobal"
|
|
43
|
+
],
|
|
44
|
+
required: true
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "targetType",
|
|
48
|
+
type: "select",
|
|
49
|
+
options: [
|
|
50
|
+
"collection",
|
|
51
|
+
"global"
|
|
52
|
+
],
|
|
53
|
+
required: true
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "collection",
|
|
57
|
+
type: "text"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "slug",
|
|
61
|
+
type: "text"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "documentID",
|
|
65
|
+
type: "text"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "targetURL",
|
|
69
|
+
type: "text"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "additions",
|
|
73
|
+
type: "number",
|
|
74
|
+
defaultValue: 0
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "removals",
|
|
78
|
+
type: "number",
|
|
79
|
+
defaultValue: 0
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "before",
|
|
83
|
+
type: "json"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "after",
|
|
87
|
+
type: "json"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "proposal",
|
|
91
|
+
type: "json"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "userID",
|
|
95
|
+
type: "text"
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
timestamps: true
|
|
99
|
+
});
|
|
7
100
|
const addAccountFields = ({ allowUserApiKeys, config })=>{
|
|
8
101
|
const adminUserSlug = config.admin?.user;
|
|
9
102
|
if (!adminUserSlug || !config.collections) return;
|
|
@@ -34,6 +127,9 @@ export const payloadAiPlugin = (pluginOptions)=>(config)=>{
|
|
|
34
127
|
const allowUserApiKeys = pluginOptions.allowUserApiKeys !== false;
|
|
35
128
|
const modelConfig = getResolvedAIModelConfig(pluginOptions.models);
|
|
36
129
|
if (!config.collections) config.collections = [];
|
|
130
|
+
if (!config.collections.some((collection)=>collection.slug === aiChangesCollectionSlug)) {
|
|
131
|
+
config.collections.push(createAIChangesCollection());
|
|
132
|
+
}
|
|
37
133
|
addAccountFields({
|
|
38
134
|
allowUserApiKeys,
|
|
39
135
|
config
|
|
@@ -65,11 +161,26 @@ export const payloadAiPlugin = (pluginOptions)=>(config)=>{
|
|
|
65
161
|
});
|
|
66
162
|
config.endpoints.push({
|
|
67
163
|
handler: createAIApplyActionEndpointHandler({
|
|
164
|
+
changeLogCollection: aiChangesCollectionSlug,
|
|
68
165
|
collections: collectionPermissions
|
|
69
166
|
}),
|
|
70
167
|
method: "post",
|
|
71
168
|
path: "/ai-apply-action"
|
|
72
169
|
});
|
|
170
|
+
config.endpoints.push({
|
|
171
|
+
handler: createAIRecentChangesEndpointHandler({
|
|
172
|
+
changeLogCollection: aiChangesCollectionSlug
|
|
173
|
+
}),
|
|
174
|
+
method: "get",
|
|
175
|
+
path: "/ai-recent-changes"
|
|
176
|
+
});
|
|
177
|
+
config.endpoints.push({
|
|
178
|
+
handler: createAIProposalDiffEndpointHandler({
|
|
179
|
+
collections: collectionPermissions
|
|
180
|
+
}),
|
|
181
|
+
method: "post",
|
|
182
|
+
path: "/ai-proposal-diff"
|
|
183
|
+
});
|
|
73
184
|
config.endpoints.push({
|
|
74
185
|
handler: createAIMentionSuggestionsEndpointHandler({
|
|
75
186
|
collections: collectionPermissions
|
|
@@ -9,11 +9,19 @@ export type AIChatMention = {
|
|
|
9
9
|
type?: "block" | "collection" | "doc" | "global";
|
|
10
10
|
};
|
|
11
11
|
export type FieldConfig = {
|
|
12
|
+
admin?: {
|
|
13
|
+
condition?: unknown;
|
|
14
|
+
};
|
|
12
15
|
blocks?: BlockConfig[];
|
|
13
16
|
fields?: FieldConfig[];
|
|
14
17
|
hasMany?: boolean;
|
|
15
18
|
label?: unknown;
|
|
19
|
+
localized?: boolean;
|
|
16
20
|
name?: string;
|
|
21
|
+
options?: (string | {
|
|
22
|
+
label?: unknown;
|
|
23
|
+
value?: string;
|
|
24
|
+
})[];
|
|
17
25
|
relationTo?: unknown;
|
|
18
26
|
required?: boolean;
|
|
19
27
|
type?: string;
|
|
@@ -26,16 +34,51 @@ type BlockConfig = {
|
|
|
26
34
|
};
|
|
27
35
|
slug: string;
|
|
28
36
|
};
|
|
37
|
+
type VersionConfig = boolean | {
|
|
38
|
+
drafts?: boolean | Record<string, unknown>;
|
|
39
|
+
};
|
|
40
|
+
type CollectionLikeConfig = {
|
|
41
|
+
access?: Record<string, unknown>;
|
|
42
|
+
auth?: unknown;
|
|
43
|
+
fields?: FieldConfig[];
|
|
44
|
+
label?: unknown;
|
|
45
|
+
labels?: {
|
|
46
|
+
plural?: unknown;
|
|
47
|
+
singular?: unknown;
|
|
48
|
+
};
|
|
49
|
+
slug: string;
|
|
50
|
+
versions?: VersionConfig;
|
|
51
|
+
};
|
|
29
52
|
type MentionContext = {
|
|
30
53
|
blockContexts: (Record<string, unknown> & {
|
|
31
54
|
parent: string;
|
|
32
55
|
slug: string;
|
|
33
56
|
})[];
|
|
34
57
|
collectionSlugs: string[];
|
|
58
|
+
collections?: ResolvedAICollectionPermissionMap;
|
|
35
59
|
globalSlugs: string[];
|
|
36
60
|
mentions?: AIChatMention[];
|
|
37
61
|
req: Parameters<PayloadHandler>[0];
|
|
38
62
|
};
|
|
63
|
+
export declare const describeCollectionLikeConfig: ({ config, permissions, type, }: {
|
|
64
|
+
config: CollectionLikeConfig;
|
|
65
|
+
permissions?: ResolvedAICollectionPermissionMap;
|
|
66
|
+
type: "collection" | "global";
|
|
67
|
+
}) => {
|
|
68
|
+
access: {
|
|
69
|
+
aiPermissions: Record<import("./collectionPermissions.js").AICollectionAction, boolean> | {
|
|
70
|
+
read: boolean;
|
|
71
|
+
update: boolean;
|
|
72
|
+
};
|
|
73
|
+
hasPayloadAccessControl: boolean;
|
|
74
|
+
};
|
|
75
|
+
fields: Record<string, unknown>[];
|
|
76
|
+
hasAuth: true | undefined;
|
|
77
|
+
hasDrafts: true | undefined;
|
|
78
|
+
label: {};
|
|
79
|
+
slug: string;
|
|
80
|
+
type: "collection" | "global";
|
|
81
|
+
};
|
|
39
82
|
export declare const describeField: (field: FieldConfig) => Record<string, unknown>;
|
|
40
83
|
export declare const collectBlocks: ({ fields, parent, }: {
|
|
41
84
|
fields: FieldConfig[];
|
|
@@ -45,7 +88,7 @@ export declare const collectBlocks: ({ fields, parent, }: {
|
|
|
45
88
|
slug: string;
|
|
46
89
|
})[];
|
|
47
90
|
export declare const getAllowedCollectionSlugs: (req: Parameters<PayloadHandler>[0], collections?: ResolvedAICollectionPermissionMap) => string[];
|
|
48
|
-
export declare const getMentionContext: ({ blockContexts, collectionSlugs, globalSlugs, mentions, req, }: MentionContext) => Promise<Record<string, unknown>[]>;
|
|
91
|
+
export declare const getMentionContext: ({ blockContexts, collectionSlugs, collections, globalSlugs, mentions, req, }: MentionContext) => Promise<Record<string, unknown>[]>;
|
|
49
92
|
export declare const buildPromptWithMentionContext: ({ mentionContext, prompt, }: {
|
|
50
93
|
mentionContext: Record<string, unknown>[];
|
|
51
94
|
prompt: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getCollectionSlugsForAction } from "./collectionPermissions.js";
|
|
1
|
+
import { getCollectionPermissions, getCollectionSlugsForAction } from "./collectionPermissions.js";
|
|
2
|
+
import { getCollectionFields, isAuthCollection } from "./normalizeData.js";
|
|
2
3
|
import { getSerializableLabel, isInternalCollection } from "./shared.js";
|
|
3
4
|
const getSerializableRelationTo = (relationTo)=>{
|
|
4
5
|
if (typeof relationTo === "string") {
|
|
@@ -9,9 +10,88 @@ const getSerializableRelationTo = (relationTo)=>{
|
|
|
9
10
|
}
|
|
10
11
|
return undefined;
|
|
11
12
|
};
|
|
13
|
+
const getSerializableOptions = (options)=>{
|
|
14
|
+
if (!Array.isArray(options)) return undefined;
|
|
15
|
+
const serializedOptions = options.map((option)=>{
|
|
16
|
+
if (typeof option === "string") {
|
|
17
|
+
return {
|
|
18
|
+
label: option,
|
|
19
|
+
value: option
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (!option || typeof option !== "object") return null;
|
|
23
|
+
const label = "label" in option ? getSerializableLabel(option.label) : undefined;
|
|
24
|
+
const value = "value" in option && typeof option.value === "string" ? option.value : undefined;
|
|
25
|
+
if (!label && !value) return null;
|
|
26
|
+
return {
|
|
27
|
+
...label ? {
|
|
28
|
+
label
|
|
29
|
+
} : {},
|
|
30
|
+
...value ? {
|
|
31
|
+
value
|
|
32
|
+
} : {}
|
|
33
|
+
};
|
|
34
|
+
}).filter(Boolean);
|
|
35
|
+
return serializedOptions.length > 0 ? serializedOptions : undefined;
|
|
36
|
+
};
|
|
37
|
+
const hasDrafts = (config)=>{
|
|
38
|
+
const versions = config?.versions;
|
|
39
|
+
if (!versions || versions === true) return false;
|
|
40
|
+
if (typeof versions !== "object") return false;
|
|
41
|
+
return Boolean(versions.drafts);
|
|
42
|
+
};
|
|
43
|
+
const toNormalizeCollectionConfig = (config)=>{
|
|
44
|
+
if (!config) return undefined;
|
|
45
|
+
return {
|
|
46
|
+
auth: config.auth,
|
|
47
|
+
fields: config.fields || [],
|
|
48
|
+
slug: config.slug
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
const getSchemaFields = (config)=>{
|
|
52
|
+
const normalizedConfig = toNormalizeCollectionConfig(config);
|
|
53
|
+
const fields = isAuthCollection(normalizedConfig) ? getCollectionFields(normalizedConfig) : [
|
|
54
|
+
...config?.fields || []
|
|
55
|
+
];
|
|
56
|
+
if (hasDrafts(config)) {
|
|
57
|
+
fields.push({
|
|
58
|
+
label: "Status",
|
|
59
|
+
name: "_status",
|
|
60
|
+
options: [
|
|
61
|
+
"draft",
|
|
62
|
+
"published"
|
|
63
|
+
],
|
|
64
|
+
required: true,
|
|
65
|
+
type: "select"
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return fields;
|
|
69
|
+
};
|
|
70
|
+
export const describeCollectionLikeConfig = ({ config, permissions, type })=>{
|
|
71
|
+
const slug = config.slug;
|
|
72
|
+
return {
|
|
73
|
+
access: {
|
|
74
|
+
aiPermissions: type === "collection" ? getCollectionPermissions({
|
|
75
|
+
permissions,
|
|
76
|
+
slug
|
|
77
|
+
}) : {
|
|
78
|
+
read: true,
|
|
79
|
+
update: true
|
|
80
|
+
},
|
|
81
|
+
hasPayloadAccessControl: Boolean(config.access)
|
|
82
|
+
},
|
|
83
|
+
fields: getSchemaFields(config).map(describeField),
|
|
84
|
+
hasAuth: isAuthCollection(toNormalizeCollectionConfig(config)) || undefined,
|
|
85
|
+
hasDrafts: hasDrafts(config) || undefined,
|
|
86
|
+
label: type === "collection" ? config.labels?.plural || config.labels?.singular || slug : getSerializableLabel(config.label) || slug,
|
|
87
|
+
slug,
|
|
88
|
+
type
|
|
89
|
+
};
|
|
90
|
+
};
|
|
12
91
|
export const describeField = (field)=>{
|
|
13
92
|
const label = getSerializableLabel(field.label);
|
|
14
93
|
const relationTo = getSerializableRelationTo(field.relationTo);
|
|
94
|
+
const options = getSerializableOptions(field.options);
|
|
15
95
|
return {
|
|
16
96
|
...label ? {
|
|
17
97
|
label
|
|
@@ -28,9 +108,18 @@ export const describeField = (field)=>{
|
|
|
28
108
|
...field.hasMany ? {
|
|
29
109
|
hasMany: field.hasMany
|
|
30
110
|
} : {},
|
|
111
|
+
...field.localized ? {
|
|
112
|
+
localized: field.localized
|
|
113
|
+
} : {},
|
|
31
114
|
...relationTo ? {
|
|
32
115
|
relationTo
|
|
33
116
|
} : {},
|
|
117
|
+
...options ? {
|
|
118
|
+
options
|
|
119
|
+
} : {},
|
|
120
|
+
...field.admin?.condition ? {
|
|
121
|
+
hasCondition: true
|
|
122
|
+
} : {},
|
|
34
123
|
...field.fields ? {
|
|
35
124
|
fields: field.fields.map(describeField)
|
|
36
125
|
} : {},
|
|
@@ -78,7 +167,7 @@ export const getAllowedCollectionSlugs = (req, collections)=>{
|
|
|
78
167
|
req
|
|
79
168
|
});
|
|
80
169
|
};
|
|
81
|
-
export const getMentionContext = async ({ blockContexts, collectionSlugs, globalSlugs, mentions, req })=>{
|
|
170
|
+
export const getMentionContext = async ({ blockContexts, collectionSlugs, collections, globalSlugs, mentions, req })=>{
|
|
82
171
|
if (!mentions || mentions.length === 0) return [];
|
|
83
172
|
const context = [];
|
|
84
173
|
const seen = new Set();
|
|
@@ -90,12 +179,11 @@ export const getMentionContext = async ({ blockContexts, collectionSlugs, global
|
|
|
90
179
|
const collectionConfig = req.payload.config.collections.find((collection)=>collection.slug === slug);
|
|
91
180
|
if (!collectionConfig) continue;
|
|
92
181
|
seen.add(key);
|
|
93
|
-
context.push({
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
slug,
|
|
182
|
+
context.push(describeCollectionLikeConfig({
|
|
183
|
+
config: collectionConfig,
|
|
184
|
+
permissions: collections,
|
|
97
185
|
type: "collection"
|
|
98
|
-
});
|
|
186
|
+
}));
|
|
99
187
|
}
|
|
100
188
|
if (mention.type === "global" && mention.slug) {
|
|
101
189
|
const slug = mention.slug;
|
|
@@ -111,11 +199,11 @@ export const getMentionContext = async ({ blockContexts, collectionSlugs, global
|
|
|
111
199
|
}).catch(()=>null);
|
|
112
200
|
seen.add(key);
|
|
113
201
|
context.push({
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
202
|
+
...describeCollectionLikeConfig({
|
|
203
|
+
config: globalConfig,
|
|
204
|
+
type: "global"
|
|
205
|
+
}),
|
|
206
|
+
doc: globalDoc
|
|
119
207
|
});
|
|
120
208
|
}
|
|
121
209
|
if (mention.type === "block" && mention.slug) {
|