@jhb.software/payload-alt-text-plugin 0.3.0 → 0.4.0
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/README.md +86 -0
- package/dist/components/AltTextHealthWidget.d.ts +2 -0
- package/dist/components/AltTextHealthWidget.js +199 -0
- package/dist/components/AltTextHealthWidget.js.map +1 -0
- package/dist/components/BulkGenerateAltTextsButton.js +10 -11
- package/dist/components/BulkGenerateAltTextsButton.js.map +1 -1
- package/dist/components/GenerateAltTextButton.js +14 -15
- package/dist/components/GenerateAltTextButton.js.map +1 -1
- package/dist/endpoints/altTextHealth.d.ts +3 -0
- package/dist/endpoints/altTextHealth.js +30 -0
- package/dist/endpoints/altTextHealth.js.map +1 -0
- package/dist/endpoints/bulkGenerateAltTexts.d.ts +2 -1
- package/dist/endpoints/bulkGenerateAltTexts.js +89 -73
- package/dist/endpoints/bulkGenerateAltTexts.js.map +1 -1
- package/dist/endpoints/generateAltText.d.ts +8 -2
- package/dist/endpoints/generateAltText.js +112 -75
- package/dist/endpoints/generateAltText.js.map +1 -1
- package/dist/exports/server.d.ts +3 -0
- package/dist/exports/server.js +4 -0
- package/dist/exports/server.js.map +1 -0
- package/dist/fields/altTextField.js +14 -9
- package/dist/fields/altTextField.js.map +1 -1
- package/dist/hooks/revalidateAltTextHealth.d.ts +3 -0
- package/dist/hooks/revalidateAltTextHealth.js +32 -0
- package/dist/hooks/revalidateAltTextHealth.js.map +1 -0
- package/dist/plugin.js +86 -6
- package/dist/plugin.js.map +1 -1
- package/dist/translations/de.js +11 -1
- package/dist/translations/de.js.map +1 -1
- package/dist/translations/en.js +11 -1
- package/dist/translations/en.js.map +1 -1
- package/dist/translations/translation-schema.json +44 -26
- package/dist/types/AltTextPluginConfig.d.ts +23 -1
- package/dist/types/AltTextPluginConfig.js.map +1 -1
- package/dist/utilities/altTextHealth.d.ts +37 -0
- package/dist/utilities/altTextHealth.js +150 -0
- package/dist/utilities/altTextHealth.js.map +1 -0
- package/dist/utilities/altTextHealthCache.d.ts +11 -0
- package/dist/utilities/altTextHealthCache.js +8 -0
- package/dist/utilities/altTextHealthCache.js.map +1 -0
- package/dist/utilities/altTextHealthWidgetDisplay.d.ts +6 -0
- package/dist/utilities/altTextHealthWidgetDisplay.js +11 -0
- package/dist/utilities/altTextHealthWidgetDisplay.js.map +1 -0
- package/dist/utilities/getCollectionLabel.d.ts +2 -0
- package/dist/utilities/getCollectionLabel.js +17 -0
- package/dist/utilities/getCollectionLabel.js.map +1 -0
- package/dist/utilities/summarizeCollection.d.ts +17 -0
- package/dist/utilities/summarizeCollection.js +62 -0
- package/dist/utilities/summarizeCollection.js.map +1 -0
- package/package.json +59 -38
- package/dist/utils/usePluginTranslation.d.ts +0 -5
- package/dist/utils/usePluginTranslation.js +0 -16
- package/dist/utils/usePluginTranslation.js.map +0 -1
package/dist/plugin.js
CHANGED
|
@@ -1,9 +1,51 @@
|
|
|
1
|
+
import { altTextHealthEndpoint } from './endpoints/altTextHealth.js';
|
|
1
2
|
import { bulkGenerateAltTextsEndpoint } from './endpoints/bulkGenerateAltTexts.js';
|
|
2
3
|
import { generateAltTextEndpoint } from './endpoints/generateAltText.js';
|
|
3
4
|
import { altTextField } from './fields/altTextField.js';
|
|
4
5
|
import { keywordsField } from './fields/keywordsField.js';
|
|
6
|
+
import { createRevalidateAltTextHealthAfterChangeHook, createRevalidateAltTextHealthAfterDeleteHook } from './hooks/revalidateAltTextHealth.js';
|
|
5
7
|
import { translations } from './translations/index.js';
|
|
6
8
|
import { deepMergeSimple } from './utils/deepMergeSimple.js';
|
|
9
|
+
const altTextHealthWidgetDefinition = {
|
|
10
|
+
slug: 'alt-text-health',
|
|
11
|
+
Component: '@jhb.software/payload-alt-text-plugin/server#AltTextHealthWidget',
|
|
12
|
+
label: {
|
|
13
|
+
de: 'Alternativtexte Zustand',
|
|
14
|
+
en: 'Alt text health'
|
|
15
|
+
},
|
|
16
|
+
maxWidth: 'full',
|
|
17
|
+
minWidth: 'medium'
|
|
18
|
+
};
|
|
19
|
+
const defaultAltTextHealthWidgetLayout = {
|
|
20
|
+
widgetSlug: 'alt-text-health',
|
|
21
|
+
width: 'full'
|
|
22
|
+
};
|
|
23
|
+
function appendAltTextHealthWidgetToLayout(layout) {
|
|
24
|
+
if (layout.some((widget)=>widget.widgetSlug === 'alt-text-health')) {
|
|
25
|
+
return layout;
|
|
26
|
+
}
|
|
27
|
+
return [
|
|
28
|
+
...layout,
|
|
29
|
+
defaultAltTextHealthWidgetLayout
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
function getDashboardDefaultLayout(defaultLayout) {
|
|
33
|
+
if (!defaultLayout) {
|
|
34
|
+
return [
|
|
35
|
+
{
|
|
36
|
+
widgetSlug: 'collections',
|
|
37
|
+
width: 'full'
|
|
38
|
+
},
|
|
39
|
+
defaultAltTextHealthWidgetLayout
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(defaultLayout)) {
|
|
43
|
+
return appendAltTextHealthWidgetToLayout(defaultLayout);
|
|
44
|
+
}
|
|
45
|
+
return async ({ req })=>appendAltTextHealthWidgetToLayout(await defaultLayout({
|
|
46
|
+
req
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
7
49
|
export const payloadAltTextPlugin = (incomingPluginConfig)=>(incomingConfig)=>{
|
|
8
50
|
const config = {
|
|
9
51
|
...incomingConfig
|
|
@@ -13,11 +55,14 @@ export const payloadAltTextPlugin = (incomingPluginConfig)=>(incomingConfig)=>{
|
|
|
13
55
|
return config;
|
|
14
56
|
}
|
|
15
57
|
const locales = config.localization ? config.localization.locales.map((localeConfig)=>typeof localeConfig === 'string' ? localeConfig : localeConfig.code) : [];
|
|
58
|
+
const enableHealthCheck = incomingPluginConfig.healthCheck !== false;
|
|
16
59
|
const pluginConfig = {
|
|
60
|
+
access: incomingPluginConfig.access ?? (({ req })=>!!req.user),
|
|
17
61
|
collections: incomingPluginConfig.collections,
|
|
18
62
|
enabled: incomingPluginConfig.enabled ?? true,
|
|
19
63
|
fieldsOverride: incomingPluginConfig.fieldsOverride,
|
|
20
64
|
getImageThumbnail: incomingPluginConfig.getImageThumbnail,
|
|
65
|
+
healthCheck: enableHealthCheck,
|
|
21
66
|
locale: incomingPluginConfig.locale,
|
|
22
67
|
locales,
|
|
23
68
|
maxBulkGenerateConcurrency: incomingPluginConfig.maxBulkGenerateConcurrency ?? 16,
|
|
@@ -74,13 +119,41 @@ export const payloadAltTextPlugin = (incomingPluginConfig)=>(incomingConfig)=>{
|
|
|
74
119
|
fields: [
|
|
75
120
|
...collectionConfig.fields ?? [],
|
|
76
121
|
...fields
|
|
77
|
-
]
|
|
122
|
+
],
|
|
123
|
+
hooks: {
|
|
124
|
+
...collectionConfig.hooks,
|
|
125
|
+
...enableHealthCheck && {
|
|
126
|
+
afterChange: [
|
|
127
|
+
...collectionConfig.hooks?.afterChange ?? [],
|
|
128
|
+
createRevalidateAltTextHealthAfterChangeHook(collectionConfig.slug)
|
|
129
|
+
],
|
|
130
|
+
afterDelete: [
|
|
131
|
+
...collectionConfig.hooks?.afterDelete ?? [],
|
|
132
|
+
createRevalidateAltTextHealthAfterDeleteHook(collectionConfig.slug)
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
78
136
|
};
|
|
79
137
|
}
|
|
80
138
|
return collectionConfig;
|
|
81
139
|
});
|
|
140
|
+
const existingWidgets = config.admin?.dashboard?.widgets ?? [];
|
|
141
|
+
const widgets = !enableHealthCheck || existingWidgets.some((widget)=>widget.slug === 'alt-text-health') ? existingWidgets : [
|
|
142
|
+
...existingWidgets,
|
|
143
|
+
altTextHealthWidgetDefinition
|
|
144
|
+
];
|
|
82
145
|
return {
|
|
83
146
|
...config,
|
|
147
|
+
admin: {
|
|
148
|
+
...config.admin,
|
|
149
|
+
dashboard: {
|
|
150
|
+
...config.admin?.dashboard,
|
|
151
|
+
...enableHealthCheck && {
|
|
152
|
+
defaultLayout: getDashboardDefaultLayout(config.admin?.dashboard?.defaultLayout)
|
|
153
|
+
},
|
|
154
|
+
widgets
|
|
155
|
+
}
|
|
156
|
+
},
|
|
84
157
|
custom: {
|
|
85
158
|
...config.custom,
|
|
86
159
|
// Make plugin config available in hooks/actions
|
|
@@ -89,15 +162,22 @@ export const payloadAltTextPlugin = (incomingPluginConfig)=>(incomingConfig)=>{
|
|
|
89
162
|
endpoints: [
|
|
90
163
|
...config.endpoints ?? [],
|
|
91
164
|
{
|
|
92
|
-
handler: generateAltTextEndpoint,
|
|
165
|
+
handler: generateAltTextEndpoint(pluginConfig.access),
|
|
93
166
|
method: 'post',
|
|
94
|
-
path: '/alt-text-plugin/generate
|
|
167
|
+
path: '/alt-text-plugin/generate'
|
|
95
168
|
},
|
|
96
169
|
{
|
|
97
|
-
handler: bulkGenerateAltTextsEndpoint,
|
|
170
|
+
handler: bulkGenerateAltTextsEndpoint(pluginConfig.access),
|
|
98
171
|
method: 'post',
|
|
99
|
-
path: '/alt-text-plugin/bulk
|
|
100
|
-
}
|
|
172
|
+
path: '/alt-text-plugin/generate/bulk'
|
|
173
|
+
},
|
|
174
|
+
...enableHealthCheck ? [
|
|
175
|
+
{
|
|
176
|
+
handler: altTextHealthEndpoint(pluginConfig.access),
|
|
177
|
+
method: 'get',
|
|
178
|
+
path: '/alt-text-plugin/health'
|
|
179
|
+
}
|
|
180
|
+
] : []
|
|
101
181
|
],
|
|
102
182
|
i18n: {
|
|
103
183
|
...config.i18n,
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Config } from 'payload'\n\nimport type {\n AltTextPluginConfig,\n IncomingAltTextPluginConfig,\n} from './types/AltTextPluginConfig.js'\n\nimport { bulkGenerateAltTextsEndpoint } from './endpoints/bulkGenerateAltTexts.js'\nimport { generateAltTextEndpoint } from './endpoints/generateAltText.js'\nimport { altTextField } from './fields/altTextField.js'\nimport { keywordsField } from './fields/keywordsField.js'\nimport { translations } from './translations/index.js'\nimport { deepMergeSimple } from './utils/deepMergeSimple.js'\n\nexport const payloadAltTextPlugin =\n (incomingPluginConfig: IncomingAltTextPluginConfig) =>\n (incomingConfig: Config): Config => {\n const config = { ...incomingConfig }\n\n // If the plugin is disabled, return the config without modifying it\n if (incomingPluginConfig.enabled === false) {\n return config\n }\n\n const locales = config.localization\n ? config.localization.locales.map((localeConfig) =>\n typeof localeConfig === 'string' ? localeConfig : localeConfig.code,\n )\n : []\n\n const pluginConfig: AltTextPluginConfig = {\n collections: incomingPluginConfig.collections,\n enabled: incomingPluginConfig.enabled ?? true,\n fieldsOverride: incomingPluginConfig.fieldsOverride,\n getImageThumbnail: incomingPluginConfig.getImageThumbnail,\n locale: incomingPluginConfig.locale,\n locales,\n maxBulkGenerateConcurrency: incomingPluginConfig.maxBulkGenerateConcurrency ?? 16,\n resolver: incomingPluginConfig.resolver,\n }\n\n // Validate locale requirement for non-localized mode\n if (locales.length === 0 && !incomingPluginConfig.locale) {\n throw new Error(\n 'The alt-text plugin requires a \"locale\" option when Payload localization is disabled. ' +\n 'Please add { locale: \"en\" } (or your preferred locale) to your plugin configuration.',\n )\n }\n\n const defaultFields = [\n altTextField({\n localized: Boolean(config.localization),\n }),\n keywordsField({\n localized: Boolean(config.localization),\n }),\n ]\n\n const fields =\n incomingPluginConfig.fieldsOverride &&\n typeof incomingPluginConfig.fieldsOverride === 'function'\n ? incomingPluginConfig.fieldsOverride({ defaultFields })\n : defaultFields\n\n // Ensure collections array exists\n config.collections = config.collections || []\n\n // Map over collections and inject AI alt text fields into specified ones\n config.collections = config.collections.map((collectionConfig) => {\n if (pluginConfig.collections.includes(collectionConfig.slug)) {\n if (!collectionConfig.upload) {\n console.warn(\n `AI Alt Text Plugin: Collection \"${collectionConfig.slug}\" is not an upload collection. Skipping field injection.`,\n )\n return collectionConfig\n }\n\n return {\n ...collectionConfig,\n admin: {\n ...collectionConfig.admin,\n components: {\n ...(collectionConfig.admin?.components ?? {}),\n // TODO: use the beforeBulkAction custom component slot once available: https://github.com/payloadcms/payload/pull/11719\n beforeListTable: [\n ...(collectionConfig.admin?.components?.beforeListTable ?? []),\n {\n path: '@jhb.software/payload-alt-text-plugin/client#BulkGenerateAltTextsButton',\n props: {\n collectionSlug: collectionConfig.slug,\n },\n },\n ],\n },\n // enhance the search by adding the filename, keywords and alt fields (if the user has not provided their own listSearchableFields)\n listSearchableFields: collectionConfig.admin?.listSearchableFields ?? [\n 'filename',\n 'keywords',\n 'alt',\n ],\n },\n fields: [...(collectionConfig.fields ?? []), ...fields],\n }\n }\n\n return collectionConfig\n })\n\n return {\n ...config,\n custom: {\n ...config.custom,\n // Make plugin config available in hooks/actions\n altTextPluginConfig: pluginConfig,\n },\n endpoints: [\n ...(config.endpoints ?? []),\n {\n handler: generateAltTextEndpoint,\n method: 'post',\n path: '/alt-text-plugin/generate-alt-text',\n },\n {\n handler: bulkGenerateAltTextsEndpoint,\n method: 'post',\n path: '/alt-text-plugin/bulk-generate-alt-texts',\n },\n ],\n i18n: {\n ...config.i18n,\n translations: deepMergeSimple(translations, incomingConfig.i18n?.translations ?? {}),\n },\n }\n }\n"],"names":["bulkGenerateAltTextsEndpoint","generateAltTextEndpoint","altTextField","keywordsField","translations","deepMergeSimple","payloadAltTextPlugin","incomingPluginConfig","incomingConfig","config","enabled","locales","localization","map","localeConfig","code","pluginConfig","collections","fieldsOverride","getImageThumbnail","locale","maxBulkGenerateConcurrency","resolver","length","Error","defaultFields","localized","Boolean","fields","collectionConfig","includes","slug","upload","console","warn","admin","components","beforeListTable","path","props","collectionSlug","listSearchableFields","custom","altTextPluginConfig","endpoints","handler","method","i18n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Config, PayloadRequest, Widget, WidgetInstance } from 'payload'\n\nimport type {\n AltTextPluginConfig,\n IncomingAltTextPluginConfig,\n} from './types/AltTextPluginConfig.js'\n\nimport { altTextHealthEndpoint } from './endpoints/altTextHealth.js'\nimport { bulkGenerateAltTextsEndpoint } from './endpoints/bulkGenerateAltTexts.js'\nimport { generateAltTextEndpoint } from './endpoints/generateAltText.js'\nimport { altTextField } from './fields/altTextField.js'\nimport { keywordsField } from './fields/keywordsField.js'\nimport {\n createRevalidateAltTextHealthAfterChangeHook,\n createRevalidateAltTextHealthAfterDeleteHook,\n} from './hooks/revalidateAltTextHealth.js'\nimport { translations } from './translations/index.js'\nimport { deepMergeSimple } from './utils/deepMergeSimple.js'\n\nconst altTextHealthWidgetDefinition: Widget = {\n slug: 'alt-text-health',\n Component: '@jhb.software/payload-alt-text-plugin/server#AltTextHealthWidget',\n label: {\n de: 'Alternativtexte Zustand',\n en: 'Alt text health',\n },\n maxWidth: 'full',\n minWidth: 'medium',\n}\n\ntype DashboardDefaultLayout = Config['admin'] extends infer TAdmin\n ? TAdmin extends { dashboard?: infer TDashboard }\n ? TDashboard extends { defaultLayout?: infer TDefaultLayout }\n ? TDefaultLayout\n : never\n : never\n : never\n\nconst defaultAltTextHealthWidgetLayout: WidgetInstance = {\n widgetSlug: 'alt-text-health',\n width: 'full',\n}\n\nfunction appendAltTextHealthWidgetToLayout(layout: WidgetInstance[]): WidgetInstance[] {\n if (layout.some((widget) => widget.widgetSlug === 'alt-text-health')) {\n return layout\n }\n\n return [...layout, defaultAltTextHealthWidgetLayout]\n}\n\nfunction getDashboardDefaultLayout(defaultLayout: DashboardDefaultLayout | undefined) {\n if (!defaultLayout) {\n return [\n {\n widgetSlug: 'collections',\n width: 'full',\n },\n defaultAltTextHealthWidgetLayout,\n ] satisfies WidgetInstance[]\n }\n\n if (Array.isArray(defaultLayout)) {\n return appendAltTextHealthWidgetToLayout(defaultLayout)\n }\n\n return async ({ req }: { req: PayloadRequest }) =>\n appendAltTextHealthWidgetToLayout(await defaultLayout({ req }))\n}\n\nexport const payloadAltTextPlugin =\n (incomingPluginConfig: IncomingAltTextPluginConfig) =>\n (incomingConfig: Config): Config => {\n const config = { ...incomingConfig }\n\n // If the plugin is disabled, return the config without modifying it\n if (incomingPluginConfig.enabled === false) {\n return config\n }\n\n const locales = config.localization\n ? config.localization.locales.map((localeConfig) =>\n typeof localeConfig === 'string' ? localeConfig : localeConfig.code,\n )\n : []\n\n const enableHealthCheck = incomingPluginConfig.healthCheck !== false\n\n const pluginConfig: AltTextPluginConfig = {\n access: incomingPluginConfig.access ?? (({ req }) => !!req.user),\n collections: incomingPluginConfig.collections,\n enabled: incomingPluginConfig.enabled ?? true,\n fieldsOverride: incomingPluginConfig.fieldsOverride,\n getImageThumbnail: incomingPluginConfig.getImageThumbnail,\n healthCheck: enableHealthCheck,\n locale: incomingPluginConfig.locale,\n locales,\n maxBulkGenerateConcurrency: incomingPluginConfig.maxBulkGenerateConcurrency ?? 16,\n resolver: incomingPluginConfig.resolver,\n }\n\n // Validate locale requirement for non-localized mode\n if (locales.length === 0 && !incomingPluginConfig.locale) {\n throw new Error(\n 'The alt-text plugin requires a \"locale\" option when Payload localization is disabled. ' +\n 'Please add { locale: \"en\" } (or your preferred locale) to your plugin configuration.',\n )\n }\n\n const defaultFields = [\n altTextField({\n localized: Boolean(config.localization),\n }),\n keywordsField({\n localized: Boolean(config.localization),\n }),\n ]\n\n const fields =\n incomingPluginConfig.fieldsOverride &&\n typeof incomingPluginConfig.fieldsOverride === 'function'\n ? incomingPluginConfig.fieldsOverride({ defaultFields })\n : defaultFields\n\n // Ensure collections array exists\n config.collections = config.collections || []\n\n // Map over collections and inject AI alt text fields into specified ones\n config.collections = config.collections.map((collectionConfig) => {\n if (pluginConfig.collections.includes(collectionConfig.slug)) {\n if (!collectionConfig.upload) {\n console.warn(\n `AI Alt Text Plugin: Collection \"${collectionConfig.slug}\" is not an upload collection. Skipping field injection.`,\n )\n return collectionConfig\n }\n\n return {\n ...collectionConfig,\n admin: {\n ...collectionConfig.admin,\n components: {\n ...(collectionConfig.admin?.components ?? {}),\n // TODO: use the beforeBulkAction custom component slot once available: https://github.com/payloadcms/payload/pull/11719\n beforeListTable: [\n ...(collectionConfig.admin?.components?.beforeListTable ?? []),\n {\n path: '@jhb.software/payload-alt-text-plugin/client#BulkGenerateAltTextsButton',\n props: {\n collectionSlug: collectionConfig.slug,\n },\n },\n ],\n },\n // enhance the search by adding the filename, keywords and alt fields (if the user has not provided their own listSearchableFields)\n listSearchableFields: collectionConfig.admin?.listSearchableFields ?? [\n 'filename',\n 'keywords',\n 'alt',\n ],\n },\n fields: [...(collectionConfig.fields ?? []), ...fields],\n hooks: {\n ...collectionConfig.hooks,\n ...(enableHealthCheck && {\n afterChange: [\n ...(collectionConfig.hooks?.afterChange ?? []),\n createRevalidateAltTextHealthAfterChangeHook(collectionConfig.slug),\n ],\n afterDelete: [\n ...(collectionConfig.hooks?.afterDelete ?? []),\n createRevalidateAltTextHealthAfterDeleteHook(collectionConfig.slug),\n ],\n }),\n },\n }\n }\n\n return collectionConfig\n })\n\n const existingWidgets = config.admin?.dashboard?.widgets ?? []\n const widgets =\n !enableHealthCheck || existingWidgets.some((widget) => widget.slug === 'alt-text-health')\n ? existingWidgets\n : [...existingWidgets, altTextHealthWidgetDefinition]\n\n return {\n ...config,\n admin: {\n ...config.admin,\n dashboard: {\n ...config.admin?.dashboard,\n ...(enableHealthCheck && {\n defaultLayout: getDashboardDefaultLayout(config.admin?.dashboard?.defaultLayout),\n }),\n widgets,\n },\n },\n custom: {\n ...config.custom,\n // Make plugin config available in hooks/actions\n altTextPluginConfig: pluginConfig,\n },\n endpoints: [\n ...(config.endpoints ?? []),\n {\n handler: generateAltTextEndpoint(pluginConfig.access),\n method: 'post',\n path: '/alt-text-plugin/generate',\n },\n {\n handler: bulkGenerateAltTextsEndpoint(pluginConfig.access),\n method: 'post',\n path: '/alt-text-plugin/generate/bulk',\n },\n ...(enableHealthCheck\n ? [\n {\n handler: altTextHealthEndpoint(pluginConfig.access),\n method: 'get' as const,\n path: '/alt-text-plugin/health',\n },\n ]\n : []),\n ],\n i18n: {\n ...config.i18n,\n translations: deepMergeSimple(translations, incomingConfig.i18n?.translations ?? {}),\n },\n }\n }\n"],"names":["altTextHealthEndpoint","bulkGenerateAltTextsEndpoint","generateAltTextEndpoint","altTextField","keywordsField","createRevalidateAltTextHealthAfterChangeHook","createRevalidateAltTextHealthAfterDeleteHook","translations","deepMergeSimple","altTextHealthWidgetDefinition","slug","Component","label","de","en","maxWidth","minWidth","defaultAltTextHealthWidgetLayout","widgetSlug","width","appendAltTextHealthWidgetToLayout","layout","some","widget","getDashboardDefaultLayout","defaultLayout","Array","isArray","req","payloadAltTextPlugin","incomingPluginConfig","incomingConfig","config","enabled","locales","localization","map","localeConfig","code","enableHealthCheck","healthCheck","pluginConfig","access","user","collections","fieldsOverride","getImageThumbnail","locale","maxBulkGenerateConcurrency","resolver","length","Error","defaultFields","localized","Boolean","fields","collectionConfig","includes","upload","console","warn","admin","components","beforeListTable","path","props","collectionSlug","listSearchableFields","hooks","afterChange","afterDelete","existingWidgets","dashboard","widgets","custom","altTextPluginConfig","endpoints","handler","method","i18n"],"mappings":"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"}
|
package/dist/translations/de.js
CHANGED
|
@@ -26,7 +26,17 @@ export const de = {
|
|
|
26
26
|
// Tooltips
|
|
27
27
|
pleaseSaveDocumentFirst: 'Bitte speichern Sie zuerst das Dokument',
|
|
28
28
|
// Validation messages
|
|
29
|
-
theAlternateTextIsRequired: 'Der Alternativtext ist erforderlich.'
|
|
29
|
+
theAlternateTextIsRequired: 'Der Alternativtext ist erforderlich.',
|
|
30
|
+
// Dashboard widget
|
|
31
|
+
altTextHealthDescription: 'Status der Bilder mit gesetztem Alternativtext.',
|
|
32
|
+
altTextHealthWidget: 'Alternativtexte Zustand',
|
|
33
|
+
collectionCheckFailed: 'Prüfung nicht verfügbar',
|
|
34
|
+
healthCheckPartialWarning: 'Einige Sammlungen konnten gerade nicht geprüft werden.',
|
|
35
|
+
localeCount: '{count} Sprachen',
|
|
36
|
+
noImagesFound: 'In den konfigurierten Sammlungen wurden noch keine Bilder gefunden.',
|
|
37
|
+
statusHealthy: 'Alternativtexte vorhanden',
|
|
38
|
+
statusUnhealthy: 'fehlende Alternativtexte',
|
|
39
|
+
totalImageCount: '{count} Bilder'
|
|
30
40
|
}
|
|
31
41
|
};
|
|
32
42
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/translations/de.ts"],"sourcesContent":["import type { GenericTranslationsObject } from './index.js'\n\nexport const de: GenericTranslationsObject = {\n $schema: './translation-schema.json',\n '@jhb.software/payload-alt-text-plugin': {\n // Field labels\n alternateText: 'Alternativtext',\n keywords: 'Schlüsselwörter',\n keywordsDescription:\n 'Schlüsselwörter, die das Bild beschreiben. Wird bei der Suche nach dem Bild verwendet.',\n\n // Button labels\n generateAltText: 'Alternativtext generieren',\n generateAltTextFor: 'Alternativtext generieren für',\n image: 'Bild',\n images: 'Bilder',\n\n // Toast messages\n altTextGeneratedSuccess:\n 'Alternativtext erfolgreich generiert. Bitte überprüfen und speichern Sie das Dokument.',\n cannotGenerateMissingFields:\n 'Alternativtext kann nicht generiert werden. Erforderliche Felder fehlen.',\n errorGeneratingAltText:\n 'Fehler beim Generieren des Alternativtextes. Bitte versuchen Sie es erneut.',\n failedToGenerate:\n 'Generierung des Alternativtextes fehlgeschlagen. Bitte versuchen Sie es erneut.',\n failedToGenerateForXImages: 'Generierung des Alternativtextes für {X} Bilder fehlgeschlagen.',\n noAltTextGenerated: 'Kein Alternativtext generiert. Bitte versuchen Sie es erneut.',\n xOfYImagesUpdated: '{X} von {Y} Bildern aktualisiert.',\n\n // Help text\n altTextDescription:\n 'Alternativtext für das Bild. Dieser wird für Screenreader und SEO verwendet. Er sollte die folgenden Anforderungen erfüllen:',\n altTextRequirement1: 'Beschreibt in 1-2 Sätzen, was auf dem Bild zu sehen ist.',\n altTextRequirement2:\n 'Sollte möglichst die gleichen Informationen oder den gleichen Zweck wie das Bild vermitteln.',\n altTextRequirement3:\n 'Phrasen wie \"Bild von\" oder \"Foto von\" sind überflüssig, da Screenreader bereits anzeigen, dass es sich um ein Bild handelt.',\n\n // Tooltips\n pleaseSaveDocumentFirst: 'Bitte speichern Sie zuerst das Dokument',\n\n // Validation messages\n theAlternateTextIsRequired: 'Der Alternativtext ist erforderlich.',\n },\n}\n"],"names":["de","$schema","alternateText","keywords","keywordsDescription","generateAltText","generateAltTextFor","image","images","altTextGeneratedSuccess","cannotGenerateMissingFields","errorGeneratingAltText","failedToGenerate","failedToGenerateForXImages","noAltTextGenerated","xOfYImagesUpdated","altTextDescription","altTextRequirement1","altTextRequirement2","altTextRequirement3","pleaseSaveDocumentFirst","theAlternateTextIsRequired"],"mappings":"AAEA,OAAO,MAAMA,KAAgC;IAC3CC,SAAS;IACT,yCAAyC;QACvC,eAAe;QACfC,eAAe;QACfC,UAAU;QACVC,qBACE;QAEF,gBAAgB;QAChBC,iBAAiB;QACjBC,oBAAoB;QACpBC,OAAO;QACPC,QAAQ;QAER,iBAAiB;QACjBC,yBACE;QACFC,6BACE;QACFC,wBACE;QACFC,kBACE;QACFC,4BAA4B;QAC5BC,oBAAoB;QACpBC,mBAAmB;QAEnB,YAAY;QACZC,oBACE;QACFC,qBAAqB;QACrBC,qBACE;QACFC,qBACE;QAEF,WAAW;QACXC,yBAAyB;QAEzB,sBAAsB;QACtBC,4BAA4B;
|
|
1
|
+
{"version":3,"sources":["../../src/translations/de.ts"],"sourcesContent":["import type { GenericTranslationsObject } from './index.js'\n\nexport const de: GenericTranslationsObject = {\n $schema: './translation-schema.json',\n '@jhb.software/payload-alt-text-plugin': {\n // Field labels\n alternateText: 'Alternativtext',\n keywords: 'Schlüsselwörter',\n keywordsDescription:\n 'Schlüsselwörter, die das Bild beschreiben. Wird bei der Suche nach dem Bild verwendet.',\n\n // Button labels\n generateAltText: 'Alternativtext generieren',\n generateAltTextFor: 'Alternativtext generieren für',\n image: 'Bild',\n images: 'Bilder',\n\n // Toast messages\n altTextGeneratedSuccess:\n 'Alternativtext erfolgreich generiert. Bitte überprüfen und speichern Sie das Dokument.',\n cannotGenerateMissingFields:\n 'Alternativtext kann nicht generiert werden. Erforderliche Felder fehlen.',\n errorGeneratingAltText:\n 'Fehler beim Generieren des Alternativtextes. Bitte versuchen Sie es erneut.',\n failedToGenerate:\n 'Generierung des Alternativtextes fehlgeschlagen. Bitte versuchen Sie es erneut.',\n failedToGenerateForXImages: 'Generierung des Alternativtextes für {X} Bilder fehlgeschlagen.',\n noAltTextGenerated: 'Kein Alternativtext generiert. Bitte versuchen Sie es erneut.',\n xOfYImagesUpdated: '{X} von {Y} Bildern aktualisiert.',\n\n // Help text\n altTextDescription:\n 'Alternativtext für das Bild. Dieser wird für Screenreader und SEO verwendet. Er sollte die folgenden Anforderungen erfüllen:',\n altTextRequirement1: 'Beschreibt in 1-2 Sätzen, was auf dem Bild zu sehen ist.',\n altTextRequirement2:\n 'Sollte möglichst die gleichen Informationen oder den gleichen Zweck wie das Bild vermitteln.',\n altTextRequirement3:\n 'Phrasen wie \"Bild von\" oder \"Foto von\" sind überflüssig, da Screenreader bereits anzeigen, dass es sich um ein Bild handelt.',\n\n // Tooltips\n pleaseSaveDocumentFirst: 'Bitte speichern Sie zuerst das Dokument',\n\n // Validation messages\n theAlternateTextIsRequired: 'Der Alternativtext ist erforderlich.',\n\n // Dashboard widget\n altTextHealthDescription: 'Status der Bilder mit gesetztem Alternativtext.',\n altTextHealthWidget: 'Alternativtexte Zustand',\n collectionCheckFailed: 'Prüfung nicht verfügbar',\n healthCheckPartialWarning: 'Einige Sammlungen konnten gerade nicht geprüft werden.',\n localeCount: '{count} Sprachen',\n noImagesFound: 'In den konfigurierten Sammlungen wurden noch keine Bilder gefunden.',\n statusHealthy: 'Alternativtexte vorhanden',\n statusUnhealthy: 'fehlende Alternativtexte',\n totalImageCount: '{count} Bilder',\n },\n}\n"],"names":["de","$schema","alternateText","keywords","keywordsDescription","generateAltText","generateAltTextFor","image","images","altTextGeneratedSuccess","cannotGenerateMissingFields","errorGeneratingAltText","failedToGenerate","failedToGenerateForXImages","noAltTextGenerated","xOfYImagesUpdated","altTextDescription","altTextRequirement1","altTextRequirement2","altTextRequirement3","pleaseSaveDocumentFirst","theAlternateTextIsRequired","altTextHealthDescription","altTextHealthWidget","collectionCheckFailed","healthCheckPartialWarning","localeCount","noImagesFound","statusHealthy","statusUnhealthy","totalImageCount"],"mappings":"AAEA,OAAO,MAAMA,KAAgC;IAC3CC,SAAS;IACT,yCAAyC;QACvC,eAAe;QACfC,eAAe;QACfC,UAAU;QACVC,qBACE;QAEF,gBAAgB;QAChBC,iBAAiB;QACjBC,oBAAoB;QACpBC,OAAO;QACPC,QAAQ;QAER,iBAAiB;QACjBC,yBACE;QACFC,6BACE;QACFC,wBACE;QACFC,kBACE;QACFC,4BAA4B;QAC5BC,oBAAoB;QACpBC,mBAAmB;QAEnB,YAAY;QACZC,oBACE;QACFC,qBAAqB;QACrBC,qBACE;QACFC,qBACE;QAEF,WAAW;QACXC,yBAAyB;QAEzB,sBAAsB;QACtBC,4BAA4B;QAE5B,mBAAmB;QACnBC,0BAA0B;QAC1BC,qBAAqB;QACrBC,uBAAuB;QACvBC,2BAA2B;QAC3BC,aAAa;QACbC,eAAe;QACfC,eAAe;QACfC,iBAAiB;QACjBC,iBAAiB;IACnB;AACF,EAAC"}
|
package/dist/translations/en.js
CHANGED
|
@@ -26,7 +26,17 @@ export const en = {
|
|
|
26
26
|
// Tooltips
|
|
27
27
|
pleaseSaveDocumentFirst: 'Please save the document first',
|
|
28
28
|
// Validation messages
|
|
29
|
-
theAlternateTextIsRequired: 'An alternate text is required.'
|
|
29
|
+
theAlternateTextIsRequired: 'An alternate text is required.',
|
|
30
|
+
// Dashboard widget
|
|
31
|
+
altTextHealthDescription: 'Alt text status across your upload collections.',
|
|
32
|
+
altTextHealthWidget: 'Alt text health',
|
|
33
|
+
collectionCheckFailed: 'Health check unavailable',
|
|
34
|
+
healthCheckPartialWarning: 'Some collections could not be checked right now.',
|
|
35
|
+
localeCount: '{count} locales',
|
|
36
|
+
noImagesFound: 'No images found in the configured collections yet.',
|
|
37
|
+
statusHealthy: 'All set',
|
|
38
|
+
statusUnhealthy: 'missing alt text',
|
|
39
|
+
totalImageCount: '{count} images'
|
|
30
40
|
}
|
|
31
41
|
};
|
|
32
42
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/translations/en.ts"],"sourcesContent":["import type { GenericTranslationsObject } from './index.js'\n\nexport const en: GenericTranslationsObject = {\n $schema: './translation-schema.json',\n '@jhb.software/payload-alt-text-plugin': {\n // Field labels\n alternateText: 'Alternate text',\n keywords: 'Keywords',\n keywordsDescription: 'Keywords which describe the image. Used when searching for the image.',\n\n // Button labels\n generateAltText: 'Generate alt text',\n generateAltTextFor: 'Generate alt text for',\n image: 'image',\n images: 'images',\n\n // Toast messages\n altTextGeneratedSuccess:\n 'Alt text generated successfully. Please review and save the document.',\n cannotGenerateMissingFields: 'Cannot generate alt text. Missing required fields.',\n errorGeneratingAltText: 'Error generating alt text. Please try again.',\n failedToGenerate: 'Failed to generate alt text. Please try again.',\n failedToGenerateForXImages: 'Failed to generate alt text for {X} images.',\n noAltTextGenerated: 'No alt text generated. Please try again.',\n xOfYImagesUpdated: '{X} of {Y} images updated.',\n\n // Help text\n altTextDescription:\n 'Alternate text for the image. This will be used for screen readers and SEO. It should meet the following requirements:',\n altTextRequirement1: 'Describes in 1-2 sentences, what is visible in the image.',\n altTextRequirement2:\n 'Should convey the same information or purpose as the image, whenever possible.',\n altTextRequirement3:\n 'Phrases like \"image of\" or \"picture of\" are unnecessary, since screen readers already announce that it\\'s an image.',\n\n // Tooltips\n pleaseSaveDocumentFirst: 'Please save the document first',\n\n // Validation messages\n theAlternateTextIsRequired: 'An alternate text is required.',\n },\n}\n"],"names":["en","$schema","alternateText","keywords","keywordsDescription","generateAltText","generateAltTextFor","image","images","altTextGeneratedSuccess","cannotGenerateMissingFields","errorGeneratingAltText","failedToGenerate","failedToGenerateForXImages","noAltTextGenerated","xOfYImagesUpdated","altTextDescription","altTextRequirement1","altTextRequirement2","altTextRequirement3","pleaseSaveDocumentFirst","theAlternateTextIsRequired"],"mappings":"AAEA,OAAO,MAAMA,KAAgC;IAC3CC,SAAS;IACT,yCAAyC;QACvC,eAAe;QACfC,eAAe;QACfC,UAAU;QACVC,qBAAqB;QAErB,gBAAgB;QAChBC,iBAAiB;QACjBC,oBAAoB;QACpBC,OAAO;QACPC,QAAQ;QAER,iBAAiB;QACjBC,yBACE;QACFC,6BAA6B;QAC7BC,wBAAwB;QACxBC,kBAAkB;QAClBC,4BAA4B;QAC5BC,oBAAoB;QACpBC,mBAAmB;QAEnB,YAAY;QACZC,oBACE;QACFC,qBAAqB;QACrBC,qBACE;QACFC,qBACE;QAEF,WAAW;QACXC,yBAAyB;QAEzB,sBAAsB;QACtBC,4BAA4B;
|
|
1
|
+
{"version":3,"sources":["../../src/translations/en.ts"],"sourcesContent":["import type { GenericTranslationsObject } from './index.js'\n\nexport const en: GenericTranslationsObject = {\n $schema: './translation-schema.json',\n '@jhb.software/payload-alt-text-plugin': {\n // Field labels\n alternateText: 'Alternate text',\n keywords: 'Keywords',\n keywordsDescription: 'Keywords which describe the image. Used when searching for the image.',\n\n // Button labels\n generateAltText: 'Generate alt text',\n generateAltTextFor: 'Generate alt text for',\n image: 'image',\n images: 'images',\n\n // Toast messages\n altTextGeneratedSuccess:\n 'Alt text generated successfully. Please review and save the document.',\n cannotGenerateMissingFields: 'Cannot generate alt text. Missing required fields.',\n errorGeneratingAltText: 'Error generating alt text. Please try again.',\n failedToGenerate: 'Failed to generate alt text. Please try again.',\n failedToGenerateForXImages: 'Failed to generate alt text for {X} images.',\n noAltTextGenerated: 'No alt text generated. Please try again.',\n xOfYImagesUpdated: '{X} of {Y} images updated.',\n\n // Help text\n altTextDescription:\n 'Alternate text for the image. This will be used for screen readers and SEO. It should meet the following requirements:',\n altTextRequirement1: 'Describes in 1-2 sentences, what is visible in the image.',\n altTextRequirement2:\n 'Should convey the same information or purpose as the image, whenever possible.',\n altTextRequirement3:\n 'Phrases like \"image of\" or \"picture of\" are unnecessary, since screen readers already announce that it\\'s an image.',\n\n // Tooltips\n pleaseSaveDocumentFirst: 'Please save the document first',\n\n // Validation messages\n theAlternateTextIsRequired: 'An alternate text is required.',\n\n // Dashboard widget\n altTextHealthDescription: 'Alt text status across your upload collections.',\n altTextHealthWidget: 'Alt text health',\n collectionCheckFailed: 'Health check unavailable',\n healthCheckPartialWarning: 'Some collections could not be checked right now.',\n localeCount: '{count} locales',\n noImagesFound: 'No images found in the configured collections yet.',\n statusHealthy: 'All set',\n statusUnhealthy: 'missing alt text',\n totalImageCount: '{count} images',\n },\n}\n"],"names":["en","$schema","alternateText","keywords","keywordsDescription","generateAltText","generateAltTextFor","image","images","altTextGeneratedSuccess","cannotGenerateMissingFields","errorGeneratingAltText","failedToGenerate","failedToGenerateForXImages","noAltTextGenerated","xOfYImagesUpdated","altTextDescription","altTextRequirement1","altTextRequirement2","altTextRequirement3","pleaseSaveDocumentFirst","theAlternateTextIsRequired","altTextHealthDescription","altTextHealthWidget","collectionCheckFailed","healthCheckPartialWarning","localeCount","noImagesFound","statusHealthy","statusUnhealthy","totalImageCount"],"mappings":"AAEA,OAAO,MAAMA,KAAgC;IAC3CC,SAAS;IACT,yCAAyC;QACvC,eAAe;QACfC,eAAe;QACfC,UAAU;QACVC,qBAAqB;QAErB,gBAAgB;QAChBC,iBAAiB;QACjBC,oBAAoB;QACpBC,OAAO;QACPC,QAAQ;QAER,iBAAiB;QACjBC,yBACE;QACFC,6BAA6B;QAC7BC,wBAAwB;QACxBC,kBAAkB;QAClBC,4BAA4B;QAC5BC,oBAAoB;QACpBC,mBAAmB;QAEnB,YAAY;QACZC,oBACE;QACFC,qBAAqB;QACrBC,qBACE;QACFC,qBACE;QAEF,WAAW;QACXC,yBAAyB;QAEzB,sBAAsB;QACtBC,4BAA4B;QAE5B,mBAAmB;QACnBC,0BAA0B;QAC1BC,qBAAqB;QACrBC,uBAAuB;QACvBC,2BAA2B;QAC3BC,aAAa;QACbC,eAAe;QACfC,eAAe;QACfC,iBAAiB;QACjBC,iBAAiB;IACnB;AACF,EAAC"}
|
|
@@ -6,47 +6,65 @@
|
|
|
6
6
|
"type": "object",
|
|
7
7
|
"properties": {
|
|
8
8
|
"alternateText": { "type": "string" },
|
|
9
|
-
"
|
|
10
|
-
"
|
|
9
|
+
"altTextDescription": { "type": "string" },
|
|
10
|
+
"altTextGeneratedSuccess": { "type": "string" },
|
|
11
|
+
"altTextHealthDescription": { "type": "string" },
|
|
12
|
+
"altTextHealthWidget": { "type": "string" },
|
|
13
|
+
"altTextRequirement1": { "type": "string" },
|
|
14
|
+
"altTextRequirement2": { "type": "string" },
|
|
15
|
+
"altTextRequirement3": { "type": "string" },
|
|
16
|
+
"cannotGenerateMissingFields": { "type": "string" },
|
|
17
|
+
"collectionCheckFailed": { "type": "string" },
|
|
18
|
+
"errorGeneratingAltText": { "type": "string" },
|
|
19
|
+
"failedToGenerate": { "type": "string" },
|
|
20
|
+
"failedToGenerateForXImages": { "type": "string" },
|
|
11
21
|
"generateAltText": { "type": "string" },
|
|
12
22
|
"generateAltTextFor": { "type": "string" },
|
|
23
|
+
"healthCheckPartialWarning": { "type": "string" },
|
|
13
24
|
"image": { "type": "string" },
|
|
14
25
|
"images": { "type": "string" },
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
26
|
+
"keywords": { "type": "string" },
|
|
27
|
+
"localeCount": { "type": "string" },
|
|
28
|
+
"keywordsDescription": { "type": "string" },
|
|
18
29
|
"noAltTextGenerated": { "type": "string" },
|
|
19
|
-
"
|
|
20
|
-
"failedToGenerateForXImages": { "type": "string" },
|
|
21
|
-
"xOfYImagesUpdated": { "type": "string" },
|
|
22
|
-
"altTextDescription": { "type": "string" },
|
|
23
|
-
"altTextRequirement1": { "type": "string" },
|
|
24
|
-
"altTextRequirement2": { "type": "string" },
|
|
25
|
-
"altTextRequirement3": { "type": "string" },
|
|
30
|
+
"noImagesFound": { "type": "string" },
|
|
26
31
|
"pleaseSaveDocumentFirst": { "type": "string" },
|
|
27
|
-
"
|
|
32
|
+
"statusHealthy": { "type": "string" },
|
|
33
|
+
"statusUnhealthy": { "type": "string" },
|
|
34
|
+
"theAlternateTextIsRequired": { "type": "string" },
|
|
35
|
+
"totalImageCount": { "type": "string" },
|
|
36
|
+
"xOfYImagesUpdated": { "type": "string" }
|
|
28
37
|
},
|
|
29
38
|
"required": [
|
|
30
39
|
"alternateText",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
40
|
+
"altTextDescription",
|
|
41
|
+
"altTextGeneratedSuccess",
|
|
42
|
+
"altTextHealthDescription",
|
|
43
|
+
"altTextHealthWidget",
|
|
44
|
+
"altTextRequirement1",
|
|
45
|
+
"altTextRequirement2",
|
|
46
|
+
"altTextRequirement3",
|
|
47
|
+
"cannotGenerateMissingFields",
|
|
48
|
+
"collectionCheckFailed",
|
|
49
|
+
"errorGeneratingAltText",
|
|
50
|
+
"failedToGenerate",
|
|
51
|
+
"failedToGenerateForXImages",
|
|
33
52
|
"generateAltText",
|
|
34
53
|
"generateAltTextFor",
|
|
54
|
+
"healthCheckPartialWarning",
|
|
35
55
|
"image",
|
|
36
56
|
"images",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
57
|
+
"keywords",
|
|
58
|
+
"keywordsDescription",
|
|
59
|
+
"localeCount",
|
|
40
60
|
"noAltTextGenerated",
|
|
41
|
-
"
|
|
42
|
-
"failedToGenerateForXImages",
|
|
43
|
-
"xOfYImagesUpdated",
|
|
44
|
-
"altTextDescription",
|
|
45
|
-
"altTextRequirement1",
|
|
46
|
-
"altTextRequirement2",
|
|
47
|
-
"altTextRequirement3",
|
|
61
|
+
"noImagesFound",
|
|
48
62
|
"pleaseSaveDocumentFirst",
|
|
49
|
-
"
|
|
63
|
+
"statusHealthy",
|
|
64
|
+
"statusUnhealthy",
|
|
65
|
+
"theAlternateTextIsRequired",
|
|
66
|
+
"totalImageCount",
|
|
67
|
+
"xOfYImagesUpdated"
|
|
50
68
|
]
|
|
51
69
|
}
|
|
52
70
|
},
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import type { CollectionSlug, Field } from 'payload';
|
|
1
|
+
import type { CollectionSlug, Field, PayloadRequest } from 'payload';
|
|
2
2
|
import type { AltTextResolver } from '../resolvers/types.js';
|
|
3
3
|
/** Configuration options for the alt text plugin. */
|
|
4
4
|
export type IncomingAltTextPluginConfig = {
|
|
5
|
+
/**
|
|
6
|
+
* Custom access control for plugin endpoints.
|
|
7
|
+
* Return `true` to allow access, `false` to deny.
|
|
8
|
+
*
|
|
9
|
+
* @default ({ req }) => !!req.user — requires authentication
|
|
10
|
+
*/
|
|
11
|
+
access?: (args: {
|
|
12
|
+
req: PayloadRequest;
|
|
13
|
+
}) => boolean | Promise<boolean>;
|
|
5
14
|
/** Collection slugs to enable the plugin for. */
|
|
6
15
|
collections: CollectionSlug[];
|
|
7
16
|
/** Whether the plugin is enabled. */
|
|
@@ -19,6 +28,13 @@ export type IncomingAltTextPluginConfig = {
|
|
|
19
28
|
* - Use a thumbnail/preview version of the image when possible (e.g. from the sizes field)
|
|
20
29
|
*/
|
|
21
30
|
getImageThumbnail: (doc: Record<string, unknown>) => string;
|
|
31
|
+
/**
|
|
32
|
+
* Enable alt text health tracking (REST endpoint, cache revalidation hooks, and dashboard widget).
|
|
33
|
+
* Set to `false` to disable the entire feature.
|
|
34
|
+
*
|
|
35
|
+
* @default true
|
|
36
|
+
*/
|
|
37
|
+
healthCheck?: boolean;
|
|
22
38
|
/**
|
|
23
39
|
* The locale to generate alt texts in when localization is disabled.
|
|
24
40
|
*
|
|
@@ -37,6 +53,10 @@ export type IncomingAltTextPluginConfig = {
|
|
|
37
53
|
};
|
|
38
54
|
/** Configuration of the alt text plugin after defaults have been applied. */
|
|
39
55
|
export type AltTextPluginConfig = {
|
|
56
|
+
/** Access control for plugin endpoints. */
|
|
57
|
+
access: (args: {
|
|
58
|
+
req: PayloadRequest;
|
|
59
|
+
}) => boolean | Promise<boolean>;
|
|
40
60
|
/** Collection slugs to enable the plugin for. */
|
|
41
61
|
collections: CollectionSlug[];
|
|
42
62
|
/** Whether the plugin is enabled. */
|
|
@@ -47,6 +67,8 @@ export type AltTextPluginConfig = {
|
|
|
47
67
|
}) => Field[];
|
|
48
68
|
/** Function to get the thumbnail URL of an image document. */
|
|
49
69
|
getImageThumbnail: (doc: Record<string, unknown>) => string;
|
|
70
|
+
/** Whether alt text health tracking is enabled. */
|
|
71
|
+
healthCheck: boolean;
|
|
50
72
|
/** The locale to generate alt texts in when localization is disabled. */
|
|
51
73
|
locale?: string;
|
|
52
74
|
/** The locales to generate alt texts for. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types/AltTextPluginConfig.ts"],"sourcesContent":["import type { CollectionSlug, Field } from 'payload'\n\nimport type { AltTextResolver } from '../resolvers/types.js'\n\n/** Configuration options for the alt text plugin. */\nexport type IncomingAltTextPluginConfig = {\n /** Collection slugs to enable the plugin for. */\n collections: CollectionSlug[]\n\n /** Whether the plugin is enabled. */\n enabled?: boolean\n\n /** Override the default fields inserted by the plugin via a function that receives the default fields and returns the new fields */\n fieldsOverride?: (args: { defaultFields: Field[] }) => Field[]\n\n /**\n * Function to get the thumbnail URL of an image document.\n * This URL will be sent to the LLM for analysis.\n *\n * @remarks\n * - The URL must be publicly accessible so the LLM can fetch it\n * - Use a thumbnail/preview version of the image when possible (e.g. from the sizes field)\n */\n getImageThumbnail: (doc: Record<string, unknown>) => string\n\n /**\n * The locale to generate alt texts in when localization is disabled.\n *\n * Required when localization is disabled, ignored when localization is enabled.\n * @example 'en'\n */\n locale?: string\n\n /**\n * Maximum number of concurrent API requests for bulk generate operations.\n *\n * @default 16\n */\n maxBulkGenerateConcurrency?: number\n\n /** The resolver to use for generating alt text (e.g., openAIResolver) */\n resolver: AltTextResolver\n}\n\n/** Configuration of the alt text plugin after defaults have been applied. */\nexport type AltTextPluginConfig = {\n /** Collection slugs to enable the plugin for. */\n collections: CollectionSlug[]\n\n /** Whether the plugin is enabled. */\n enabled: boolean\n\n /** Override the default fields inserted by the plugin via a function that receives the default fields and returns the new fields */\n fieldsOverride?: (args: { defaultFields: Field[] }) => Field[]\n\n /** Function to get the thumbnail URL of an image document. */\n getImageThumbnail: (doc: Record<string, unknown>) => string\n\n /** The locale to generate alt texts in when localization is disabled. */\n locale?: string\n\n /** The locales to generate alt texts for. */\n locales: string[]\n\n /** Maximum number of concurrent API requests for bulk generate operations. */\n maxBulkGenerateConcurrency: number\n\n /** The resolver to use for generating alt text */\n resolver: AltTextResolver\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/types/AltTextPluginConfig.ts"],"sourcesContent":["import type { CollectionSlug, Field, PayloadRequest } from 'payload'\n\nimport type { AltTextResolver } from '../resolvers/types.js'\n\n/** Configuration options for the alt text plugin. */\nexport type IncomingAltTextPluginConfig = {\n /**\n * Custom access control for plugin endpoints.\n * Return `true` to allow access, `false` to deny.\n *\n * @default ({ req }) => !!req.user — requires authentication\n */\n access?: (args: { req: PayloadRequest }) => boolean | Promise<boolean>\n\n /** Collection slugs to enable the plugin for. */\n collections: CollectionSlug[]\n\n /** Whether the plugin is enabled. */\n enabled?: boolean\n\n /** Override the default fields inserted by the plugin via a function that receives the default fields and returns the new fields */\n fieldsOverride?: (args: { defaultFields: Field[] }) => Field[]\n\n /**\n * Function to get the thumbnail URL of an image document.\n * This URL will be sent to the LLM for analysis.\n *\n * @remarks\n * - The URL must be publicly accessible so the LLM can fetch it\n * - Use a thumbnail/preview version of the image when possible (e.g. from the sizes field)\n */\n getImageThumbnail: (doc: Record<string, unknown>) => string\n\n /**\n * Enable alt text health tracking (REST endpoint, cache revalidation hooks, and dashboard widget).\n * Set to `false` to disable the entire feature.\n *\n * @default true\n */\n healthCheck?: boolean\n\n /**\n * The locale to generate alt texts in when localization is disabled.\n *\n * Required when localization is disabled, ignored when localization is enabled.\n * @example 'en'\n */\n locale?: string\n\n /**\n * Maximum number of concurrent API requests for bulk generate operations.\n *\n * @default 16\n */\n maxBulkGenerateConcurrency?: number\n\n /** The resolver to use for generating alt text (e.g., openAIResolver) */\n resolver: AltTextResolver\n}\n\n/** Configuration of the alt text plugin after defaults have been applied. */\nexport type AltTextPluginConfig = {\n /** Access control for plugin endpoints. */\n access: (args: { req: PayloadRequest }) => boolean | Promise<boolean>\n\n /** Collection slugs to enable the plugin for. */\n collections: CollectionSlug[]\n\n /** Whether the plugin is enabled. */\n enabled: boolean\n\n /** Override the default fields inserted by the plugin via a function that receives the default fields and returns the new fields */\n fieldsOverride?: (args: { defaultFields: Field[] }) => Field[]\n\n /** Function to get the thumbnail URL of an image document. */\n getImageThumbnail: (doc: Record<string, unknown>) => string\n\n /** Whether alt text health tracking is enabled. */\n healthCheck: boolean\n\n /** The locale to generate alt texts in when localization is disabled. */\n locale?: string\n\n /** The locales to generate alt texts for. */\n locales: string[]\n\n /** Maximum number of concurrent API requests for bulk generate operations. */\n maxBulkGenerateConcurrency: number\n\n /** The resolver to use for generating alt text */\n resolver: AltTextResolver\n}\n"],"names":[],"mappings":"AA4DA,2EAA2E,GAC3E,WA8BC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { PayloadRequest } from 'payload';
|
|
2
|
+
export declare const ALT_TEXT_HEALTH_PLUGIN_SLUG = "alt-text";
|
|
3
|
+
export declare const ALT_TEXT_HEALTH_CACHE_TTL = 3600;
|
|
4
|
+
export declare const ALT_TEXT_HEALTH_GLOBAL_TAG = "alt-text-health";
|
|
5
|
+
export type AltTextHealthErrorCode = 'ALT_TEXT_COLLECTION_READ_FAILED' | 'ALT_TEXT_PLUGIN_CONFIG_MISSING';
|
|
6
|
+
export type AltTextHealthError = {
|
|
7
|
+
code: AltTextHealthErrorCode;
|
|
8
|
+
collection?: string;
|
|
9
|
+
message: string;
|
|
10
|
+
operation?: 'find';
|
|
11
|
+
};
|
|
12
|
+
export type AltTextHealthScanCollection = {
|
|
13
|
+
collection: string;
|
|
14
|
+
completeDocs: number;
|
|
15
|
+
error?: AltTextHealthError;
|
|
16
|
+
invalidDocIds: (number | string)[] | undefined;
|
|
17
|
+
missingDocs: number;
|
|
18
|
+
partialDocs: number;
|
|
19
|
+
totalDocs: number;
|
|
20
|
+
};
|
|
21
|
+
export type AltTextHealthScan = {
|
|
22
|
+
checkedAt: string;
|
|
23
|
+
collections: AltTextHealthScanCollection[];
|
|
24
|
+
errors: AltTextHealthError[];
|
|
25
|
+
isLocalized: boolean;
|
|
26
|
+
localeCodes: string[];
|
|
27
|
+
};
|
|
28
|
+
export type AltTextHealthWidgetData = {
|
|
29
|
+
collections: AltTextHealthScanCollection[];
|
|
30
|
+
errors: AltTextHealthError[];
|
|
31
|
+
isLocalized: boolean;
|
|
32
|
+
localeCount: number;
|
|
33
|
+
totalDocs: number;
|
|
34
|
+
};
|
|
35
|
+
export declare const getAltTextHealthCollectionTag: (collectionSlug: string) => string;
|
|
36
|
+
export declare function getAltTextHealth(req: PayloadRequest): Promise<AltTextHealthScan>;
|
|
37
|
+
export declare function getAltTextHealthWidgetData(req: PayloadRequest): Promise<AltTextHealthWidgetData>;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { unstable_cache } from 'next/cache.js';
|
|
2
|
+
import { createCachedAltTextHealthScan } from './altTextHealthCache.js';
|
|
3
|
+
import { localesFromConfig } from './localesFromConfig.js';
|
|
4
|
+
import { summarizeCollection } from './summarizeCollection.js';
|
|
5
|
+
export const ALT_TEXT_HEALTH_PLUGIN_SLUG = 'alt-text';
|
|
6
|
+
export const ALT_TEXT_HEALTH_CACHE_TTL = 3600;
|
|
7
|
+
export const ALT_TEXT_HEALTH_GLOBAL_TAG = 'alt-text-health';
|
|
8
|
+
const createUnknownScan = ({ error, isLocalized, localeCodes })=>({
|
|
9
|
+
checkedAt: new Date().toISOString(),
|
|
10
|
+
collections: [],
|
|
11
|
+
errors: [
|
|
12
|
+
error
|
|
13
|
+
],
|
|
14
|
+
isLocalized,
|
|
15
|
+
localeCodes
|
|
16
|
+
});
|
|
17
|
+
const createCollectionReadError = (collection, message)=>({
|
|
18
|
+
code: 'ALT_TEXT_COLLECTION_READ_FAILED',
|
|
19
|
+
collection,
|
|
20
|
+
message,
|
|
21
|
+
operation: 'find'
|
|
22
|
+
});
|
|
23
|
+
const PAGE_SIZE = 500;
|
|
24
|
+
async function fetchAllDocs(payload, collection, isLocalized) {
|
|
25
|
+
const docs = [];
|
|
26
|
+
let page = 1;
|
|
27
|
+
let hasMore = true;
|
|
28
|
+
while(hasMore){
|
|
29
|
+
const result = await payload.find({
|
|
30
|
+
collection,
|
|
31
|
+
depth: 0,
|
|
32
|
+
fallbackLocale: isLocalized ? false : undefined,
|
|
33
|
+
limit: PAGE_SIZE,
|
|
34
|
+
locale: isLocalized ? 'all' : undefined,
|
|
35
|
+
overrideAccess: true,
|
|
36
|
+
page,
|
|
37
|
+
select: {
|
|
38
|
+
alt: true
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
for (const doc of result.docs){
|
|
42
|
+
docs.push({
|
|
43
|
+
id: doc.id,
|
|
44
|
+
alt: 'alt' in doc ? doc.alt : undefined
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
hasMore = result.hasNextPage;
|
|
48
|
+
page++;
|
|
49
|
+
}
|
|
50
|
+
return docs;
|
|
51
|
+
}
|
|
52
|
+
async function computeAltTextHealthScan({ collections, isLocalized, localeCodes, payload }) {
|
|
53
|
+
const collectionSummaries = await Promise.all(collections.map(async (collection)=>{
|
|
54
|
+
try {
|
|
55
|
+
const docs = await fetchAllDocs(payload, collection, isLocalized);
|
|
56
|
+
return summarizeCollection({
|
|
57
|
+
collection,
|
|
58
|
+
docs,
|
|
59
|
+
isLocalized,
|
|
60
|
+
localeCodes
|
|
61
|
+
});
|
|
62
|
+
} catch (error) {
|
|
63
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
64
|
+
const collectionError = createCollectionReadError(collection, message);
|
|
65
|
+
payload.logger.error({
|
|
66
|
+
collection,
|
|
67
|
+
err: error,
|
|
68
|
+
msg: 'Alt text health check failed while reading a collection.',
|
|
69
|
+
operation: 'find',
|
|
70
|
+
plugin: ALT_TEXT_HEALTH_PLUGIN_SLUG
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
collection,
|
|
74
|
+
completeDocs: 0,
|
|
75
|
+
error: collectionError,
|
|
76
|
+
invalidDocIds: undefined,
|
|
77
|
+
missingDocs: 0,
|
|
78
|
+
partialDocs: 0,
|
|
79
|
+
totalDocs: 0
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}));
|
|
83
|
+
const errors = collectionSummaries.filter((summary)=>summary.error).map((summary)=>summary.error);
|
|
84
|
+
return {
|
|
85
|
+
checkedAt: new Date().toISOString(),
|
|
86
|
+
collections: collectionSummaries,
|
|
87
|
+
errors,
|
|
88
|
+
isLocalized,
|
|
89
|
+
localeCodes
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export const getAltTextHealthCollectionTag = (collectionSlug)=>`${ALT_TEXT_HEALTH_GLOBAL_TAG}:${collectionSlug}`;
|
|
93
|
+
async function getAltTextHealthScan(req) {
|
|
94
|
+
const { payload } = req;
|
|
95
|
+
const pluginConfig = payload.config.custom?.altTextPluginConfig;
|
|
96
|
+
const localeCodes = localesFromConfig(payload.config) ?? (pluginConfig?.locale ? [
|
|
97
|
+
pluginConfig.locale
|
|
98
|
+
] : []);
|
|
99
|
+
const isLocalized = Boolean(payload.config.localization);
|
|
100
|
+
if (!pluginConfig) {
|
|
101
|
+
return createUnknownScan({
|
|
102
|
+
error: {
|
|
103
|
+
code: 'ALT_TEXT_PLUGIN_CONFIG_MISSING',
|
|
104
|
+
message: 'Alt text plugin config not found'
|
|
105
|
+
},
|
|
106
|
+
isLocalized,
|
|
107
|
+
localeCodes
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const collections = pluginConfig.collections;
|
|
111
|
+
const cacheKeyParts = [
|
|
112
|
+
ALT_TEXT_HEALTH_GLOBAL_TAG,
|
|
113
|
+
[
|
|
114
|
+
...collections
|
|
115
|
+
].sort().join(','),
|
|
116
|
+
localeCodes.join(',')
|
|
117
|
+
];
|
|
118
|
+
const tags = [
|
|
119
|
+
ALT_TEXT_HEALTH_GLOBAL_TAG,
|
|
120
|
+
...new Set(collections.map((collection)=>getAltTextHealthCollectionTag(collection)))
|
|
121
|
+
];
|
|
122
|
+
const getCachedHealthScan = createCachedAltTextHealthScan({
|
|
123
|
+
cacheFactory: unstable_cache,
|
|
124
|
+
cacheKeyParts,
|
|
125
|
+
compute: async ()=>computeAltTextHealthScan({
|
|
126
|
+
collections,
|
|
127
|
+
isLocalized,
|
|
128
|
+
localeCodes,
|
|
129
|
+
payload
|
|
130
|
+
}),
|
|
131
|
+
revalidate: ALT_TEXT_HEALTH_CACHE_TTL,
|
|
132
|
+
tags
|
|
133
|
+
});
|
|
134
|
+
return getCachedHealthScan();
|
|
135
|
+
}
|
|
136
|
+
export async function getAltTextHealth(req) {
|
|
137
|
+
return getAltTextHealthScan(req);
|
|
138
|
+
}
|
|
139
|
+
export async function getAltTextHealthWidgetData(req) {
|
|
140
|
+
const scan = await getAltTextHealthScan(req);
|
|
141
|
+
return {
|
|
142
|
+
collections: scan.collections,
|
|
143
|
+
errors: scan.errors,
|
|
144
|
+
isLocalized: scan.isLocalized,
|
|
145
|
+
localeCount: scan.localeCodes.length,
|
|
146
|
+
totalDocs: scan.collections.reduce((total, c)=>total + c.totalDocs, 0)
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//# sourceMappingURL=altTextHealth.js.map
|