@nitrogenbuilder/connector-payload 0.1.33 → 0.1.35
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/collections/NitrogenComponentCatalog.d.ts +2 -0
- package/dist/collections/NitrogenComponentCatalog.js +44 -0
- package/dist/collections/NitrogenComponentUsage.d.ts +2 -0
- package/dist/collections/NitrogenComponentUsage.js +81 -0
- package/dist/components/LockedJsonField.d.ts +2 -9
- package/dist/components/LockedJsonField.js +7 -6
- package/dist/components/LockedJsonFieldRuntime.d.ts +3 -7
- package/dist/components/LockedJsonFieldRuntime.js +21 -22
- package/dist/components/NitrogenComponentInventoryClient.d.ts +13 -0
- package/dist/components/NitrogenComponentInventoryClient.js +309 -0
- package/dist/components/NitrogenComponentInventoryField.d.ts +3 -0
- package/dist/components/NitrogenComponentInventoryField.js +26 -0
- package/dist/components/NitrogenComponentInventoryNavLink.d.ts +1 -0
- package/dist/components/NitrogenComponentInventoryNavLink.js +75 -0
- package/dist/components/NitrogenComponentInventoryReindexButton.d.ts +1 -0
- package/dist/components/NitrogenComponentInventoryReindexButton.js +91 -0
- package/dist/components/NitrogenComponentInventoryView.d.ts +2 -0
- package/dist/components/NitrogenComponentInventoryView.js +28 -0
- package/dist/components/NitrogenDataViewer.d.ts +2 -2
- package/dist/components/NitrogenDataViewer.js +7 -6
- package/dist/components/NitrogenDataViewerRuntime.d.ts +6 -2
- package/dist/components/NitrogenDataViewerRuntime.js +24 -40
- package/dist/components/NitrogenNavGroup.d.ts +1 -0
- package/dist/components/NitrogenNavGroup.js +74 -0
- package/dist/editor/NitrogenEditorPage.d.ts +1 -2
- package/dist/endpoints/collection-endpoints.js +50 -5
- package/dist/endpoints/component-inventory.d.ts +6 -0
- package/dist/endpoints/component-inventory.js +20 -0
- package/dist/frontend/NitrogenWrapper.d.ts +1 -2
- package/dist/globals/NitrogenComponents.d.ts +2 -0
- package/dist/globals/NitrogenComponents.js +22 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.js +94 -3
- package/dist/inventory/indexing.d.ts +31 -0
- package/dist/inventory/indexing.js +230 -0
- package/dist/inventory/manifest.d.ts +3 -0
- package/dist/inventory/manifest.js +22 -0
- package/dist/types.d.ts +35 -1
- package/package.json +7 -2
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { usePathname } from 'next/navigation';
|
|
3
|
+
import { useEffect } from 'react';
|
|
4
|
+
const groupSelector = '#nav-group-Nitrogen .nav-group__content';
|
|
5
|
+
export default function NitrogenComponentInventoryNavLink() {
|
|
6
|
+
const pathname = usePathname();
|
|
7
|
+
const isActive = pathname === '/admin/nitrogen/components' || pathname?.startsWith('/admin/nitrogen/components/');
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const linkId = 'nitrogen-components-nav-link';
|
|
10
|
+
const renderLink = () => {
|
|
11
|
+
const target = document.querySelector(groupSelector);
|
|
12
|
+
if (!target) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const existing = document.getElementById(linkId);
|
|
16
|
+
if (existing) {
|
|
17
|
+
existing.remove();
|
|
18
|
+
}
|
|
19
|
+
const link = document.createElement('a');
|
|
20
|
+
link.id = linkId;
|
|
21
|
+
link.href = '/admin/nitrogen/components';
|
|
22
|
+
link.textContent = 'Nitrogen Components';
|
|
23
|
+
link.style.alignItems = 'center';
|
|
24
|
+
link.style.color = 'inherit';
|
|
25
|
+
link.style.display = 'flex';
|
|
26
|
+
link.style.fontSize = '18px';
|
|
27
|
+
link.style.fontWeight = isActive ? '700' : '500';
|
|
28
|
+
link.style.gap = '12px';
|
|
29
|
+
link.style.minHeight = '40px';
|
|
30
|
+
link.style.opacity = isActive ? '1' : '0.92';
|
|
31
|
+
link.style.padding = '6px 0';
|
|
32
|
+
link.style.textDecoration = 'none';
|
|
33
|
+
const icon = document.createElement('span');
|
|
34
|
+
icon.ariaHidden = 'true';
|
|
35
|
+
icon.style.color = '#6b7280';
|
|
36
|
+
icon.style.display = 'inline-flex';
|
|
37
|
+
icon.style.fontSize = '16px';
|
|
38
|
+
icon.style.justifyContent = 'center';
|
|
39
|
+
icon.style.width = '20px';
|
|
40
|
+
icon.innerHTML = `
|
|
41
|
+
<svg fill="none" height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg">
|
|
42
|
+
<path
|
|
43
|
+
d="M4 5.5C4 4.67157 4.67157 4 5.5 4H14.5C15.3284 4 16 4.67157 16 5.5V14.5C16 15.3284 15.3284 16 14.5 16H5.5C4.67157 16 4 15.3284 4 14.5V5.5Z"
|
|
44
|
+
stroke="currentColor"
|
|
45
|
+
stroke-width="1.5"
|
|
46
|
+
/>
|
|
47
|
+
<path d="M7 8H13" stroke="currentColor" stroke-linecap="round" stroke-width="1.5" />
|
|
48
|
+
<path d="M7 10.5H13" stroke="currentColor" stroke-linecap="round" stroke-width="1.5" />
|
|
49
|
+
<path d="M7 13H10.5" stroke="currentColor" stroke-linecap="round" stroke-width="1.5" />
|
|
50
|
+
</svg>
|
|
51
|
+
`;
|
|
52
|
+
const label = document.createElement('span');
|
|
53
|
+
label.textContent = 'Nitrogen Components';
|
|
54
|
+
link.textContent = '';
|
|
55
|
+
link.append(icon, label);
|
|
56
|
+
if (isActive) {
|
|
57
|
+
link.setAttribute('aria-current', 'page');
|
|
58
|
+
}
|
|
59
|
+
target.append(link);
|
|
60
|
+
};
|
|
61
|
+
renderLink();
|
|
62
|
+
const observer = new MutationObserver(() => {
|
|
63
|
+
renderLink();
|
|
64
|
+
});
|
|
65
|
+
observer.observe(document.body, {
|
|
66
|
+
childList: true,
|
|
67
|
+
subtree: true,
|
|
68
|
+
});
|
|
69
|
+
return () => {
|
|
70
|
+
observer.disconnect();
|
|
71
|
+
document.getElementById(linkId)?.remove();
|
|
72
|
+
};
|
|
73
|
+
}, [isActive]);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function NitrogenComponentInventoryReindexButton(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
const statusStorageKey = 'nitrogen-component-inventory:last-reindex-status';
|
|
5
|
+
export default function NitrogenComponentInventoryReindexButton() {
|
|
6
|
+
const [loading, setLoading] = useState(false);
|
|
7
|
+
const [status, setStatus] = useState(null);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const rawValue = window.sessionStorage.getItem(statusStorageKey);
|
|
10
|
+
if (!rawValue) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
setStatus(JSON.parse(rawValue));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
window.sessionStorage.removeItem(statusStorageKey);
|
|
18
|
+
}
|
|
19
|
+
}, []);
|
|
20
|
+
function persistStatus(nextStatus) {
|
|
21
|
+
setStatus(nextStatus);
|
|
22
|
+
window.sessionStorage.setItem(statusStorageKey, JSON.stringify(nextStatus));
|
|
23
|
+
}
|
|
24
|
+
async function handleClick() {
|
|
25
|
+
try {
|
|
26
|
+
setLoading(true);
|
|
27
|
+
const response = await fetch('/api/nitrogen/v1/component-inventory/reindex', {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
});
|
|
30
|
+
const data = await response.json();
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
persistStatus({
|
|
33
|
+
kind: 'error',
|
|
34
|
+
message: data?.error || 'Failed to reindex component inventory.',
|
|
35
|
+
timestamp: new Date().toISOString(),
|
|
36
|
+
});
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
persistStatus({
|
|
40
|
+
kind: 'success',
|
|
41
|
+
message: `Reindexed ${data.documentCount} documents and ${data.usageCount} component usages.`,
|
|
42
|
+
timestamp: new Date().toISOString(),
|
|
43
|
+
});
|
|
44
|
+
window.location.reload();
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
console.error(error);
|
|
48
|
+
persistStatus({
|
|
49
|
+
kind: 'error',
|
|
50
|
+
message: 'Failed to reindex component inventory.',
|
|
51
|
+
timestamp: new Date().toISOString(),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
setLoading(false);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function clearStatus() {
|
|
59
|
+
setStatus(null);
|
|
60
|
+
window.sessionStorage.removeItem(statusStorageKey);
|
|
61
|
+
}
|
|
62
|
+
return (_jsxs("div", { style: { display: 'grid', gap: 12 }, children: [_jsx("div", { style: { display: 'flex', gap: 12, alignItems: 'center', flexWrap: 'wrap' }, children: _jsx("button", { type: "button", onClick: handleClick, disabled: loading, style: {
|
|
63
|
+
border: 'none',
|
|
64
|
+
borderRadius: 6,
|
|
65
|
+
background: '#171717',
|
|
66
|
+
color: '#fff',
|
|
67
|
+
cursor: loading ? 'wait' : 'pointer',
|
|
68
|
+
fontSize: 14,
|
|
69
|
+
fontWeight: 600,
|
|
70
|
+
padding: '10px 14px',
|
|
71
|
+
}, children: loading ? 'Reindexing...' : 'Reindex Components' }) }), status ? (_jsxs("div", { style: {
|
|
72
|
+
alignItems: 'start',
|
|
73
|
+
background: status.kind === 'success' ? '#ecfdf5' : '#fef2f2',
|
|
74
|
+
border: `1px solid ${status.kind === 'success' ? '#a7f3d0' : '#fecaca'}`,
|
|
75
|
+
borderRadius: 10,
|
|
76
|
+
color: status.kind === 'success' ? '#065f46' : '#991b1b',
|
|
77
|
+
display: 'grid',
|
|
78
|
+
gap: 6,
|
|
79
|
+
gridTemplateColumns: '1fr auto',
|
|
80
|
+
padding: '12px 14px',
|
|
81
|
+
}, children: [_jsxs("div", { children: [_jsx("div", { style: { fontSize: 13, fontWeight: 700 }, children: status.kind === 'success' ? 'Last Reindex Completed' : 'Reindex Failed' }), _jsx("div", { style: { fontSize: 13, marginTop: 2 }, children: status.message }), _jsx("div", { style: { fontSize: 12, marginTop: 4, opacity: 0.75 }, children: new Date(status.timestamp).toLocaleString() })] }), _jsx("button", { type: "button", onClick: clearStatus, style: {
|
|
82
|
+
appearance: 'none',
|
|
83
|
+
background: 'transparent',
|
|
84
|
+
border: 'none',
|
|
85
|
+
color: 'inherit',
|
|
86
|
+
cursor: 'pointer',
|
|
87
|
+
fontSize: 12,
|
|
88
|
+
fontWeight: 700,
|
|
89
|
+
padding: 0,
|
|
90
|
+
}, children: "Dismiss" })] })) : null] }));
|
|
91
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// @ts-expect-error The consuming Payload app provides @payloadcms/next at runtime.
|
|
3
|
+
import { DefaultTemplate } from '@payloadcms/next/templates';
|
|
4
|
+
import { findAllDocs, NITROGEN_COMPONENT_CATALOG_COLLECTION, NITROGEN_COMPONENT_USAGE_COLLECTION, } from '../inventory/indexing';
|
|
5
|
+
import NitrogenComponentInventoryClient from './NitrogenComponentInventoryClient';
|
|
6
|
+
import NitrogenComponentInventoryReindexButton from './NitrogenComponentInventoryReindexButton';
|
|
7
|
+
export default async function NitrogenComponentInventoryView({ clientConfig, initPageResult, i18n, locale, params, searchParams, viewActions, viewType, }) {
|
|
8
|
+
const payload = initPageResult.req.payload;
|
|
9
|
+
const [catalogDocs, usageDocs] = await Promise.all([
|
|
10
|
+
findAllDocs(payload, NITROGEN_COMPONENT_CATALOG_COLLECTION),
|
|
11
|
+
findAllDocs(payload, NITROGEN_COMPONENT_USAGE_COLLECTION),
|
|
12
|
+
]);
|
|
13
|
+
const catalogByName = new Map(catalogDocs.map((doc) => [doc.componentName, doc.definition]));
|
|
14
|
+
const usageByName = new Map();
|
|
15
|
+
for (const usageDoc of usageDocs) {
|
|
16
|
+
const docs = usageByName.get(usageDoc.componentName) || [];
|
|
17
|
+
docs.push(usageDoc);
|
|
18
|
+
usageByName.set(usageDoc.componentName, docs);
|
|
19
|
+
}
|
|
20
|
+
const componentNames = Array.from(new Set([...catalogByName.keys(), ...usageByName.keys()])).sort((a, b) => a.localeCompare(b));
|
|
21
|
+
const components = componentNames.map((componentName) => ({
|
|
22
|
+
componentName,
|
|
23
|
+
definition: catalogByName.get(componentName),
|
|
24
|
+
isUnknown: !catalogByName.get(componentName),
|
|
25
|
+
usages: usageByName.get(componentName) || [],
|
|
26
|
+
}));
|
|
27
|
+
return (_jsx(DefaultTemplate, { i18n: i18n, locale: locale, params: params, payload: payload, req: initPageResult.req, searchParams: searchParams, user: initPageResult.req.user, viewActions: viewActions, viewType: viewType, visibleEntities: initPageResult.visibleEntities, children: _jsxs("div", { style: { padding: 24 }, children: [_jsxs("div", { style: { display: 'grid', gap: 12, marginBottom: 24 }, children: [_jsx("h1", { style: { margin: 0, fontSize: 28 }, children: "Nitrogen Components" }), _jsx("p", { style: { margin: 0, color: '#4b5563', maxWidth: 920 }, children: "Inventory view for the registered Nitrogen component manifest and all indexed usages across Nitrogen-enabled documents and templates." }), _jsx(NitrogenComponentInventoryReindexButton, {})] }), _jsx(NitrogenComponentInventoryClient, { adminRoute: clientConfig.routes.admin, components: components })] }) }));
|
|
28
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
declare const NitrogenDataViewer:
|
|
1
|
+
import type { JSONFieldServerComponent } from 'payload';
|
|
2
|
+
declare const NitrogenDataViewer: JSONFieldServerComponent;
|
|
3
3
|
export default NitrogenDataViewer;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
const NitrogenDataViewer =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
});
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import NitrogenDataViewerRuntime from './NitrogenDataViewerRuntime';
|
|
3
|
+
const NitrogenDataViewer = ({ field, value }) => {
|
|
4
|
+
const label = typeof field.label === 'string' ? field.label : field.name;
|
|
5
|
+
const description = typeof field.admin?.description === 'string' ? field.admin.description : undefined;
|
|
6
|
+
return (_jsx(NitrogenDataViewerRuntime, { description: description, label: label, value: value }));
|
|
7
|
+
};
|
|
7
8
|
export default NitrogenDataViewer;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
declare const NitrogenDataViewerRuntime:
|
|
1
|
+
import React from 'react';
|
|
2
|
+
declare const NitrogenDataViewerRuntime: React.FC<{
|
|
3
|
+
description?: string;
|
|
4
|
+
label: string;
|
|
5
|
+
value?: unknown;
|
|
6
|
+
}>;
|
|
3
7
|
export default NitrogenDataViewerRuntime;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useCallback } from 'react';
|
|
4
|
-
import { Collapsible, useField } from '@payloadcms/ui';
|
|
5
4
|
function updateAtPath(root, path, newValue) {
|
|
6
5
|
if (path.length === 0)
|
|
7
6
|
return newValue;
|
|
@@ -281,13 +280,11 @@ function ensureStyles() {
|
|
|
281
280
|
`;
|
|
282
281
|
document.head.appendChild(style);
|
|
283
282
|
}
|
|
284
|
-
const NitrogenDataViewerRuntime = ({
|
|
285
|
-
const { value, setValue } = useField({ path });
|
|
283
|
+
const NitrogenDataViewerRuntime = ({ description, label, value }) => {
|
|
286
284
|
const [copied, setCopied] = useState(false);
|
|
287
|
-
const [
|
|
285
|
+
const [collapsed, setCollapsed] = useState(true);
|
|
288
286
|
const [forceOpen, setForceOpen] = useState(null);
|
|
289
287
|
const [treeKey, setTreeKey] = useState(0);
|
|
290
|
-
const [unlocked, setUnlocked] = useState(false);
|
|
291
288
|
ensureStyles();
|
|
292
289
|
let parsed = [];
|
|
293
290
|
try {
|
|
@@ -304,19 +301,6 @@ const NitrogenDataViewerRuntime = ({ path, field }) => {
|
|
|
304
301
|
setTimeout(() => setCopied(false), 2000);
|
|
305
302
|
});
|
|
306
303
|
}, [jsonString]);
|
|
307
|
-
const handlePaste = useCallback(() => {
|
|
308
|
-
navigator.clipboard.readText().then((text) => {
|
|
309
|
-
try {
|
|
310
|
-
const parsedValue = JSON.parse(text);
|
|
311
|
-
setValue(parsedValue);
|
|
312
|
-
setPasted(true);
|
|
313
|
-
setTimeout(() => setPasted(false), 2000);
|
|
314
|
-
}
|
|
315
|
-
catch {
|
|
316
|
-
// ignore invalid JSON
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
}, [setValue]);
|
|
320
304
|
const expandAll = useCallback(() => {
|
|
321
305
|
setForceOpen(true);
|
|
322
306
|
setTreeKey((k) => k + 1);
|
|
@@ -326,28 +310,28 @@ const NitrogenDataViewerRuntime = ({ path, field }) => {
|
|
|
326
310
|
setTreeKey((k) => k + 1);
|
|
327
311
|
}, []);
|
|
328
312
|
const callbacks = {
|
|
329
|
-
onUpdate: (
|
|
330
|
-
onDelete: (
|
|
331
|
-
onRenameKey: (
|
|
332
|
-
onAddChild: (
|
|
313
|
+
onUpdate: () => undefined,
|
|
314
|
+
onDelete: () => undefined,
|
|
315
|
+
onRenameKey: () => undefined,
|
|
316
|
+
onAddChild: () => undefined,
|
|
333
317
|
};
|
|
334
|
-
const header = (_jsxs("span", { children: [
|
|
335
|
-
return (_jsxs("div", { className: "njv-root field-type", style: { marginBottom: '1.5rem' }, children: [
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
318
|
+
const header = (_jsxs("span", { children: [label, moduleCount !== null && (_jsxs("span", { style: { opacity: 0.5, fontWeight: 400, marginLeft: 8 }, children: ["(", moduleCount, " item", moduleCount !== 1 ? 's' : '', ")"] }))] }));
|
|
319
|
+
return (_jsxs("div", { className: "njv-root field-type", style: { marginBottom: '1.5rem' }, children: [_jsxs("div", { style: { border: '1px solid var(--njv-border)', borderRadius: '4px', overflow: 'hidden' }, children: [_jsxs("button", { type: "button", onClick: () => setCollapsed((current) => !current), style: {
|
|
320
|
+
alignItems: 'center',
|
|
321
|
+
background: 'var(--theme-elevation-50, #f8f8f8)',
|
|
322
|
+
border: 'none',
|
|
323
|
+
borderBottom: collapsed ? 'none' : '1px solid var(--njv-border)',
|
|
324
|
+
cursor: 'pointer',
|
|
325
|
+
display: 'flex',
|
|
326
|
+
justifyContent: 'space-between',
|
|
327
|
+
padding: '12px 16px',
|
|
328
|
+
width: '100%',
|
|
329
|
+
}, children: [header, _jsx("span", { style: { fontSize: 12, opacity: 0.65 }, children: collapsed ? 'Show' : 'Hide' })] }), !collapsed && (_jsxs("div", { children: [_jsxs("div", { className: "njv-toolbar", children: [_jsx("button", { type: "button", className: "btn btn--size-small btn--style-secondary", onClick: handleCopy, children: copied ? '✓ Copied' : 'Copy' }), _jsx("button", { type: "button", className: "btn btn--size-small btn--style-secondary", onClick: expandAll, children: "Expand All" }), _jsx("button", { type: "button", className: "btn btn--size-small btn--style-secondary", onClick: collapseAll, children: "Collapse All" })] }), _jsx("div", { className: "njv-body", style: {
|
|
330
|
+
maxHeight: '50vh',
|
|
331
|
+
overflow: 'auto',
|
|
332
|
+
fontFamily: 'var(--font-mono, "SF Mono", Menlo, Consolas, monospace)',
|
|
333
|
+
fontSize: 'var(--font-body-size, 13px)',
|
|
334
|
+
backgroundColor: 'var(--njv-bg)',
|
|
335
|
+
}, children: _jsx(JsonNode, { value: parsed ?? [], depth: 0, forceOpen: forceOpen, path: [], unlocked: false, callbacks: callbacks }, treeKey) })] }))] }), typeof description === 'string' && (_jsx("p", { style: { fontSize: '12px', color: '#888', marginTop: '4px' }, children: description }))] }));
|
|
352
336
|
};
|
|
353
337
|
export default NitrogenDataViewerRuntime;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function NitrogenNavGroup(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { usePathname } from 'next/navigation';
|
|
4
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
5
|
+
const items = [
|
|
6
|
+
{
|
|
7
|
+
href: '/admin/collections/nitrogen-templates',
|
|
8
|
+
label: 'Templates',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
href: '/admin/globals/nitrogen-settings',
|
|
12
|
+
label: 'Settings',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
href: '/admin/nitrogen/components',
|
|
16
|
+
label: 'Components',
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
export default function NitrogenNavGroup() {
|
|
20
|
+
const pathname = usePathname();
|
|
21
|
+
const hasActiveChild = useMemo(() => items.some((item) => pathname === item.href || pathname?.startsWith(`${item.href}/`)), [pathname]);
|
|
22
|
+
const [collapsed, setCollapsed] = useState(!hasActiveChild);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (hasActiveChild) {
|
|
25
|
+
setCollapsed(false);
|
|
26
|
+
}
|
|
27
|
+
}, [hasActiveChild]);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
const styleId = 'nitrogen-custom-nav-group-style';
|
|
30
|
+
if (document.getElementById(styleId)) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const style = document.createElement('style');
|
|
34
|
+
style.id = styleId;
|
|
35
|
+
style.textContent = `
|
|
36
|
+
#nav-group-Nitrogen {
|
|
37
|
+
display: none;
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
document.head.appendChild(style);
|
|
41
|
+
return () => {
|
|
42
|
+
style.remove();
|
|
43
|
+
};
|
|
44
|
+
}, []);
|
|
45
|
+
return (_jsxs("div", { style: { marginTop: 12 }, children: [_jsxs("button", { type: "button", onClick: () => setCollapsed((current) => !current), style: {
|
|
46
|
+
alignItems: 'center',
|
|
47
|
+
background: 'transparent',
|
|
48
|
+
border: 'none',
|
|
49
|
+
color: 'inherit',
|
|
50
|
+
cursor: 'pointer',
|
|
51
|
+
display: 'flex',
|
|
52
|
+
font: 'inherit',
|
|
53
|
+
justifyContent: 'space-between',
|
|
54
|
+
padding: '6px 0',
|
|
55
|
+
width: '100%',
|
|
56
|
+
}, children: [_jsx("span", { style: { fontSize: 13, fontWeight: 700, letterSpacing: '0.01em' }, children: "Nitrogen" }), _jsx("span", { "aria-hidden": "true", style: {
|
|
57
|
+
display: 'inline-block',
|
|
58
|
+
fontSize: 12,
|
|
59
|
+
opacity: 0.65,
|
|
60
|
+
transform: collapsed ? 'rotate(-90deg)' : 'rotate(0deg)',
|
|
61
|
+
transition: 'transform 160ms ease',
|
|
62
|
+
}, children: "\u25BE" })] }), !collapsed && (_jsx("div", { style: { display: 'grid', gap: 2, paddingBottom: 4, paddingLeft: 12 }, children: items.map((item) => {
|
|
63
|
+
const isActive = pathname === item.href || pathname?.startsWith(`${item.href}/`);
|
|
64
|
+
return (_jsx("a", { "aria-current": isActive ? 'page' : undefined, href: item.href, style: {
|
|
65
|
+
borderLeft: isActive ? '2px solid currentColor' : '2px solid transparent',
|
|
66
|
+
display: 'block',
|
|
67
|
+
fontSize: 13,
|
|
68
|
+
fontWeight: isActive ? 700 : 500,
|
|
69
|
+
opacity: isActive ? 1 : 0.82,
|
|
70
|
+
padding: '6px 0 6px 10px',
|
|
71
|
+
textDecoration: 'none',
|
|
72
|
+
}, children: item.label }, item.href));
|
|
73
|
+
}) }))] }));
|
|
74
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { SanitizedConfig } from "payload";
|
|
2
1
|
interface NitrogenEditorSearchParams {
|
|
3
2
|
pageId?: string;
|
|
4
3
|
collection?: string;
|
|
@@ -16,7 +15,7 @@ interface NitrogenEditorSearchParams {
|
|
|
16
15
|
*
|
|
17
16
|
* Accessible at `/nitrogen-editor?pageId=xxx`.
|
|
18
17
|
*/
|
|
19
|
-
export declare function createNitrogenEditorPage(config: Promise<
|
|
18
|
+
export declare function createNitrogenEditorPage(config: Promise<any>): ({ searchParams, }: {
|
|
20
19
|
searchParams: Promise<NitrogenEditorSearchParams>;
|
|
21
20
|
}) => Promise<import("react/jsx-runtime").JSX.Element>;
|
|
22
21
|
export {};
|
|
@@ -103,7 +103,33 @@ export function createCollectionEndpoints(collectionSlug, endpointPrefix) {
|
|
|
103
103
|
if (!data?.title) {
|
|
104
104
|
return Response.json({ error: 'Title is required' }, { status: 400 });
|
|
105
105
|
}
|
|
106
|
+
let existingDoc = null;
|
|
107
|
+
try {
|
|
108
|
+
existingDoc = (await payload.findByID({
|
|
109
|
+
collection,
|
|
110
|
+
id,
|
|
111
|
+
depth: 0,
|
|
112
|
+
disableErrors: true,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
existingDoc = null;
|
|
117
|
+
}
|
|
106
118
|
const updateData = { title: data.title };
|
|
119
|
+
if (existingDoc) {
|
|
120
|
+
if ('slug' in existingDoc && existingDoc.slug !== undefined) {
|
|
121
|
+
updateData.slug = existingDoc.slug;
|
|
122
|
+
}
|
|
123
|
+
if ('generateSlug' in existingDoc) {
|
|
124
|
+
updateData.generateSlug = false;
|
|
125
|
+
}
|
|
126
|
+
if ('parent' in existingDoc) {
|
|
127
|
+
updateData.parent = existingDoc.parent;
|
|
128
|
+
}
|
|
129
|
+
if ('breadcrumbs' in existingDoc) {
|
|
130
|
+
updateData.breadcrumbs = [];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
107
133
|
if (data.author) {
|
|
108
134
|
updateData.author = data.author;
|
|
109
135
|
}
|
|
@@ -114,11 +140,30 @@ export function createCollectionEndpoints(collectionSlug, endpointPrefix) {
|
|
|
114
140
|
if (data.settings !== undefined) {
|
|
115
141
|
updateData.pageSettings = data.settings;
|
|
116
142
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
143
|
+
try {
|
|
144
|
+
await payload.update({
|
|
145
|
+
collection,
|
|
146
|
+
id,
|
|
147
|
+
data: updateData,
|
|
148
|
+
depth: 0,
|
|
149
|
+
overrideAccess: true,
|
|
150
|
+
req,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
payload.logger.error({
|
|
155
|
+
msg: 'Nitrogen page update failed',
|
|
156
|
+
collection,
|
|
157
|
+
id,
|
|
158
|
+
error,
|
|
159
|
+
});
|
|
160
|
+
return Response.json({
|
|
161
|
+
error: error instanceof Error ? error.message : 'Failed to update page',
|
|
162
|
+
details: error && typeof error === 'object' && 'data' in error
|
|
163
|
+
? error.data
|
|
164
|
+
: undefined,
|
|
165
|
+
}, { status: 400 });
|
|
166
|
+
}
|
|
122
167
|
return Response.json({ success: true });
|
|
123
168
|
},
|
|
124
169
|
},
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Endpoint } from 'payload';
|
|
2
|
+
import type { NitrogenComponentManifestInput } from '../inventory/manifest';
|
|
3
|
+
export declare function createComponentInventoryEndpoints(args: {
|
|
4
|
+
collections: string[];
|
|
5
|
+
componentManifest?: NitrogenComponentManifestInput;
|
|
6
|
+
}): Endpoint[];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { requireAuth } from './helpers';
|
|
2
|
+
import { reindexAllComponentInventory } from '../inventory/indexing';
|
|
3
|
+
export function createComponentInventoryEndpoints(args) {
|
|
4
|
+
return [
|
|
5
|
+
{
|
|
6
|
+
path: '/nitrogen/v1/component-inventory/reindex',
|
|
7
|
+
method: 'post',
|
|
8
|
+
handler: async (req) => {
|
|
9
|
+
const authError = requireAuth(req);
|
|
10
|
+
if (authError)
|
|
11
|
+
return authError;
|
|
12
|
+
const result = await reindexAllComponentInventory(req.payload, args.collections, args.componentManifest);
|
|
13
|
+
return Response.json({
|
|
14
|
+
success: true,
|
|
15
|
+
...result,
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { SanitizedConfig } from 'payload';
|
|
3
2
|
import type { BuilderModule } from '@nitrogenbuilder/types';
|
|
4
3
|
export interface NitrogenWrapperProps {
|
|
5
4
|
/**
|
|
@@ -21,7 +20,7 @@ export interface NitrogenWrapperProps {
|
|
|
21
20
|
/**
|
|
22
21
|
* The Payload config promise. Import from '@payload-config' in your app and pass it here.
|
|
23
22
|
*/
|
|
24
|
-
config: Promise<
|
|
23
|
+
config: Promise<any>;
|
|
25
24
|
/**
|
|
26
25
|
* Regular page content to render when not in Nitrogen mode.
|
|
27
26
|
*/
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const NitrogenComponents = {
|
|
2
|
+
slug: 'nitrogen-components',
|
|
3
|
+
label: 'Nitrogen Components',
|
|
4
|
+
admin: {
|
|
5
|
+
group: 'Nitrogen',
|
|
6
|
+
},
|
|
7
|
+
access: {
|
|
8
|
+
read: ({ req }) => !!req.user,
|
|
9
|
+
update: ({ req }) => !!req.user,
|
|
10
|
+
},
|
|
11
|
+
fields: [
|
|
12
|
+
{
|
|
13
|
+
name: 'inventory',
|
|
14
|
+
type: 'ui',
|
|
15
|
+
admin: {
|
|
16
|
+
components: {
|
|
17
|
+
Field: '@nitrogenbuilder/connector-payload/components/NitrogenComponentInventoryField',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { NitrogenComponentManifestInput } from './inventory/manifest';
|
|
2
2
|
export interface NitrogenConnectorPluginOptions {
|
|
3
3
|
/** Disable the plugin without removing it from config */
|
|
4
4
|
disabled?: boolean;
|
|
@@ -18,8 +18,18 @@ export interface NitrogenConnectorPluginOptions {
|
|
|
18
18
|
* `collectionRoutes: { posts: '/blog/[slug]', patent: '/patents/[slug]' }`
|
|
19
19
|
*/
|
|
20
20
|
collectionRoutes?: Record<string, string>;
|
|
21
|
+
/**
|
|
22
|
+
* A static manifest or async loader describing the project's registered
|
|
23
|
+
* Nitrogen components and their prop schemas.
|
|
24
|
+
*/
|
|
25
|
+
componentManifest?: NitrogenComponentManifestInput;
|
|
26
|
+
/**
|
|
27
|
+
* Collections whose saved `nitrogenData` should be indexed for the component
|
|
28
|
+
* inventory. These do not need to be editor-enabled.
|
|
29
|
+
*/
|
|
30
|
+
indexCollections?: string[];
|
|
21
31
|
}
|
|
22
|
-
export declare const nitrogenConnectorPlugin: (options?: NitrogenConnectorPluginOptions) =>
|
|
32
|
+
export declare const nitrogenConnectorPlugin: (options?: NitrogenConnectorPluginOptions) => any;
|
|
23
33
|
export { NitrogenTemplates } from "./collections/NitrogenTemplates";
|
|
24
34
|
export { NitrogenSettings } from "./globals/NitrogenSettings";
|
|
25
35
|
export { NitrogenEditButton } from "./components/NitrogenEditButton";
|