@gogitcms/editor 0.38.0 → 0.40.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/app/src/App.tsx
CHANGED
|
@@ -2346,7 +2346,7 @@ function CmsView({
|
|
|
2346
2346
|
const doc = loaded[draft.id];
|
|
2347
2347
|
if (!tab || !doc) return;
|
|
2348
2348
|
const col = collections.find((c) => c.name === tab.collection);
|
|
2349
|
-
|
|
2349
|
+
const published = {
|
|
2350
2350
|
id: draft.id,
|
|
2351
2351
|
collection: tab.collection,
|
|
2352
2352
|
path: doc.path,
|
|
@@ -2356,6 +2356,16 @@ function CmsView({
|
|
|
2356
2356
|
fields: { ...(doc.fields ?? {}), ...draft.fields },
|
|
2357
2357
|
body: draft.body ?? undefined,
|
|
2358
2358
|
bodyField: col?.fields.find((f) => f.source === "body")?.name,
|
|
2359
|
+
};
|
|
2360
|
+
// Two audiences: the plugin tabs open on this document, and the
|
|
2361
|
+
// plugins themselves — which is how a preview popped out into its
|
|
2362
|
+
// own window keeps receiving edits after its tab is closed.
|
|
2363
|
+
draftBus.publish(published);
|
|
2364
|
+
pluginRegistry.notifyDraft(published, {
|
|
2365
|
+
workspaceId: params.workspaceId,
|
|
2366
|
+
repositoryId: repo.id,
|
|
2367
|
+
branchId: branch.id,
|
|
2368
|
+
ref: branch.name,
|
|
2359
2369
|
});
|
|
2360
2370
|
}
|
|
2361
2371
|
}
|
|
@@ -146,3 +146,40 @@ describe("host capabilities", () => {
|
|
|
146
146
|
await expect(registry.api("@acme/preview").getPreviewToken("")).rejects.toThrow(/repositoryId is required/);
|
|
147
147
|
});
|
|
148
148
|
});
|
|
149
|
+
|
|
150
|
+
describe("onDocumentDraft", () => {
|
|
151
|
+
it("hands every in-flight edit to the plugins that asked, for the life of the plugin", () => {
|
|
152
|
+
const registry = new PluginRegistry();
|
|
153
|
+
const seen: string[] = [];
|
|
154
|
+
registry.api("@acme/preview").onDocumentDraft((doc, ctx) => seen.push(`${ctx.repositoryId}:${doc.id}:${doc.fields.title}`));
|
|
155
|
+
registry.api("@acme/other").onDocumentDraft(() => {
|
|
156
|
+
throw new Error("boom");
|
|
157
|
+
});
|
|
158
|
+
const errors: string[] = [];
|
|
159
|
+
jest.spyOn(console, "error").mockImplementation((m: unknown) => void errors.push(String(m)));
|
|
160
|
+
|
|
161
|
+
registry.notifyDraft(
|
|
162
|
+
{ id: "d1", collection: "posts", path: "content/a.md", fields: { title: "Hello" } },
|
|
163
|
+
{ workspaceId: "ws", repositoryId: "repo-1", ref: "main" },
|
|
164
|
+
);
|
|
165
|
+
registry.notifyDraft(
|
|
166
|
+
{ id: "d1", collection: "posts", path: "content/a.md", fields: { title: "Hello again" } },
|
|
167
|
+
{ workspaceId: "ws", repositoryId: "repo-1", ref: "main" },
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
expect(seen).toEqual(["repo-1:d1:Hello", "repo-1:d1:Hello again"]);
|
|
171
|
+
// A listener that throws is reported and does not stop the others, nor
|
|
172
|
+
// the editor's typing path that called in.
|
|
173
|
+
expect(errors.some((e) => e.includes("@acme/other") && e.includes("boom"))).toBe(true);
|
|
174
|
+
jest.restoreAllMocks();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("refuses a listener that is not a function", () => {
|
|
178
|
+
const registry = new PluginRegistry();
|
|
179
|
+
const errors: string[] = [];
|
|
180
|
+
jest.spyOn(console, "error").mockImplementation((m: unknown) => void errors.push(String(m)));
|
|
181
|
+
(registry.api("@acme/preview") as any).onDocumentDraft("nope");
|
|
182
|
+
expect(errors.some((e) => e.includes("must be a function"))).toBe(true);
|
|
183
|
+
jest.restoreAllMocks();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
@@ -15,6 +15,8 @@ import type {
|
|
|
15
15
|
PluginSidebarLink,
|
|
16
16
|
PluginStatus,
|
|
17
17
|
PluginUserMenuLink,
|
|
18
|
+
PluginDraftContext,
|
|
19
|
+
PluginDraftListener,
|
|
18
20
|
} from "./types";
|
|
19
21
|
|
|
20
22
|
// The schema prefix under which plugin field components are addressed
|
|
@@ -85,6 +87,7 @@ export class PluginRegistry {
|
|
|
85
87
|
private userMenuLinks: PluginUserMenuLinkRecord[] = [];
|
|
86
88
|
private fieldComponents = new Map<string, PluginFieldComponentRecord>();
|
|
87
89
|
private documentActions: PluginDocumentActionRecord[] = [];
|
|
90
|
+
private draftListeners: { pluginId: string; listener: PluginDraftListener }[] = [];
|
|
88
91
|
private statuses = new Map<string, { status: PluginStatus; error?: string }>();
|
|
89
92
|
private listeners = new Set<() => void>();
|
|
90
93
|
private version = 0;
|
|
@@ -255,9 +258,31 @@ export class PluginRegistry {
|
|
|
255
258
|
});
|
|
256
259
|
registry.bump();
|
|
257
260
|
},
|
|
261
|
+
onDocumentDraft(listener: PluginDraftListener) {
|
|
262
|
+
if (typeof listener !== "function") {
|
|
263
|
+
console.error(`[plugin ${pluginId}] onDocumentDraft: listener must be a function`);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
registry.draftListeners.push({ pluginId, listener });
|
|
267
|
+
},
|
|
258
268
|
};
|
|
259
269
|
}
|
|
260
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Hand an in-flight edit to every plugin that asked for them. Called by the
|
|
273
|
+
* host from its typing path, so a listener that throws is reported and
|
|
274
|
+
* skipped rather than allowed to break the editor.
|
|
275
|
+
*/
|
|
276
|
+
notifyDraft(doc: PluginDocument, ctx: PluginDraftContext): void {
|
|
277
|
+
for (const { pluginId, listener } of this.draftListeners) {
|
|
278
|
+
try {
|
|
279
|
+
listener(doc, ctx);
|
|
280
|
+
} catch (err) {
|
|
281
|
+
console.error(`[plugin ${pluginId}] draft listener threw: ${String(err)}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
261
286
|
// --- queries the hosts render from ----------------------------------------
|
|
262
287
|
|
|
263
288
|
/** Field component for a schema `display.component` key ("plugin:<name>"). */
|
|
@@ -212,8 +212,30 @@ export interface CmsPluginApi {
|
|
|
212
212
|
* pane is built without the CMS knowing anything about previews.
|
|
213
213
|
*/
|
|
214
214
|
addDocumentAction(action: PluginDocumentAction): void;
|
|
215
|
+
/**
|
|
216
|
+
* Subscribe to every open document's in-flight edits, for the life of the
|
|
217
|
+
* plugin rather than of a tab.
|
|
218
|
+
*
|
|
219
|
+
* A tab's `onDraft` (PluginTabContext) ends with the tab. This one does not,
|
|
220
|
+
* which is what lets a preview keep receiving edits after its pane has been
|
|
221
|
+
* popped out into a window and the tab closed. The host debounces before
|
|
222
|
+
* calling (~150 ms), same as the tab form. Listeners are called for every
|
|
223
|
+
* document being edited; the plugin decides which ones it cares about.
|
|
224
|
+
*/
|
|
225
|
+
onDocumentDraft(listener: PluginDraftListener): void;
|
|
215
226
|
}
|
|
216
227
|
|
|
228
|
+
/** Where a draft came from: the repository and branch being edited. */
|
|
229
|
+
export type PluginDraftContext = {
|
|
230
|
+
workspaceId: string;
|
|
231
|
+
repositoryId: string;
|
|
232
|
+
branchId?: string;
|
|
233
|
+
/** Git ref name of the branch, when the host knows it. */
|
|
234
|
+
ref?: string;
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
export type PluginDraftListener = (doc: PluginDocument, ctx: PluginDraftContext) => void;
|
|
238
|
+
|
|
217
239
|
/** A plugin's setup function — the package entrypoint's default export. */
|
|
218
240
|
export type PluginSetup = (cms: CmsPluginApi, options?: unknown) => void | Promise<void>;
|
|
219
241
|
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gogitcms/editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@gogitcms/editor",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.40.0",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@apollo/client": "^3.11.8",
|
|
12
12
|
"@handlewithcare/react-prosemirror": "^3.2.7",
|
|
@@ -47,11 +47,11 @@
|
|
|
47
47
|
"node": ">=20"
|
|
48
48
|
},
|
|
49
49
|
"optionalDependencies": {
|
|
50
|
-
"@gogitcms/gitcms-local-darwin-arm64": "0.
|
|
51
|
-
"@gogitcms/gitcms-local-darwin-x64": "0.
|
|
52
|
-
"@gogitcms/gitcms-local-linux-arm64": "0.
|
|
53
|
-
"@gogitcms/gitcms-local-linux-x64": "0.
|
|
54
|
-
"@gogitcms/gitcms-local-win32-x64": "0.
|
|
50
|
+
"@gogitcms/gitcms-local-darwin-arm64": "0.40.0",
|
|
51
|
+
"@gogitcms/gitcms-local-darwin-x64": "0.40.0",
|
|
52
|
+
"@gogitcms/gitcms-local-linux-arm64": "0.40.0",
|
|
53
|
+
"@gogitcms/gitcms-local-linux-x64": "0.40.0",
|
|
54
|
+
"@gogitcms/gitcms-local-win32-x64": "0.40.0"
|
|
55
55
|
}
|
|
56
56
|
},
|
|
57
57
|
"node_modules/@apollo/client": {
|
|
@@ -751,9 +751,9 @@
|
|
|
751
751
|
}
|
|
752
752
|
},
|
|
753
753
|
"node_modules/@gogitcms/gitcms-local-darwin-arm64": {
|
|
754
|
-
"version": "0.
|
|
755
|
-
"resolved": "https://registry.npmjs.org/@gogitcms/gitcms-local-darwin-arm64/-/gitcms-local-darwin-arm64-0.
|
|
756
|
-
"integrity": "sha512-
|
|
754
|
+
"version": "0.40.0",
|
|
755
|
+
"resolved": "https://registry.npmjs.org/@gogitcms/gitcms-local-darwin-arm64/-/gitcms-local-darwin-arm64-0.40.0.tgz",
|
|
756
|
+
"integrity": "sha512-YSXToG2tsBQgjcvnQUrukaejCPUfkEHTeaOephZd4cOXQ2ZqG9/ZlHUrL7f7EByfqL3Haq0+kFIf8n6gr8UQgQ==",
|
|
757
757
|
"cpu": [
|
|
758
758
|
"arm64"
|
|
759
759
|
],
|
|
@@ -764,9 +764,9 @@
|
|
|
764
764
|
]
|
|
765
765
|
},
|
|
766
766
|
"node_modules/@gogitcms/gitcms-local-darwin-x64": {
|
|
767
|
-
"version": "0.
|
|
768
|
-
"resolved": "https://registry.npmjs.org/@gogitcms/gitcms-local-darwin-x64/-/gitcms-local-darwin-x64-0.
|
|
769
|
-
"integrity": "sha512-
|
|
767
|
+
"version": "0.40.0",
|
|
768
|
+
"resolved": "https://registry.npmjs.org/@gogitcms/gitcms-local-darwin-x64/-/gitcms-local-darwin-x64-0.40.0.tgz",
|
|
769
|
+
"integrity": "sha512-TgOawXMxI9VbFIsqV6fewAn/TK0I6B/nZp+2kfchV/uTTdvdwRhis5AP3xgg9Pm3oGeQRiS3U7CzYsmVbsSxkw==",
|
|
770
770
|
"cpu": [
|
|
771
771
|
"x64"
|
|
772
772
|
],
|
|
@@ -777,9 +777,9 @@
|
|
|
777
777
|
]
|
|
778
778
|
},
|
|
779
779
|
"node_modules/@gogitcms/gitcms-local-linux-x64": {
|
|
780
|
-
"version": "0.
|
|
781
|
-
"resolved": "https://registry.npmjs.org/@gogitcms/gitcms-local-linux-x64/-/gitcms-local-linux-x64-0.
|
|
782
|
-
"integrity": "sha512-
|
|
780
|
+
"version": "0.40.0",
|
|
781
|
+
"resolved": "https://registry.npmjs.org/@gogitcms/gitcms-local-linux-x64/-/gitcms-local-linux-x64-0.40.0.tgz",
|
|
782
|
+
"integrity": "sha512-w7HITMMDfoYTkY7d3wUyHt5rcdF6Ku8f0Ej8GTYXa4TO72QtVDxh9TcKOdICxih7lvQNBUhj7sZ88ZtabYsOtg==",
|
|
783
783
|
"cpu": [
|
|
784
784
|
"x64"
|
|
785
785
|
],
|
|
@@ -789,6 +789,19 @@
|
|
|
789
789
|
"linux"
|
|
790
790
|
]
|
|
791
791
|
},
|
|
792
|
+
"node_modules/@gogitcms/gitcms-local-win32-x64": {
|
|
793
|
+
"version": "0.40.0",
|
|
794
|
+
"resolved": "https://registry.npmjs.org/@gogitcms/gitcms-local-win32-x64/-/gitcms-local-win32-x64-0.40.0.tgz",
|
|
795
|
+
"integrity": "sha512-qszCKrAqqddACYF+ZrtAep2wIGSLW/SWAAS2+M5MS6WiZT6bJVlYTQiw64U+/hMk4XfscFP4hUwOSeV37c9ocA==",
|
|
796
|
+
"cpu": [
|
|
797
|
+
"x64"
|
|
798
|
+
],
|
|
799
|
+
"license": "UNLICENSED",
|
|
800
|
+
"optional": true,
|
|
801
|
+
"os": [
|
|
802
|
+
"win32"
|
|
803
|
+
]
|
|
804
|
+
},
|
|
792
805
|
"node_modules/@graphql-typed-document-node/core": {
|
|
793
806
|
"version": "3.2.0",
|
|
794
807
|
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gogitcms/editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"description": "Terminal UI for setting up and running the Go·Git CMS content editor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -65,10 +65,10 @@
|
|
|
65
65
|
"@gogitcms/frontend": "workspace:*"
|
|
66
66
|
},
|
|
67
67
|
"optionalDependencies": {
|
|
68
|
-
"@gogitcms/gitcms-local-darwin-arm64": "0.
|
|
69
|
-
"@gogitcms/gitcms-local-darwin-x64": "0.
|
|
70
|
-
"@gogitcms/gitcms-local-linux-arm64": "0.
|
|
71
|
-
"@gogitcms/gitcms-local-linux-x64": "0.
|
|
72
|
-
"@gogitcms/gitcms-local-win32-x64": "0.
|
|
68
|
+
"@gogitcms/gitcms-local-darwin-arm64": "0.40.0",
|
|
69
|
+
"@gogitcms/gitcms-local-darwin-x64": "0.40.0",
|
|
70
|
+
"@gogitcms/gitcms-local-linux-arm64": "0.40.0",
|
|
71
|
+
"@gogitcms/gitcms-local-linux-x64": "0.40.0",
|
|
72
|
+
"@gogitcms/gitcms-local-win32-x64": "0.40.0"
|
|
73
73
|
}
|
|
74
74
|
}
|