From 03456dd483a44fbd8c2da9c82103b46bc00c9ca3 Mon Sep 17 00:00:00 2001
From: Juanfran
Date: Wed, 28 Feb 2024 12:54:37 +0100
Subject: [PATCH] feat: update-file example
---
apps/example-plugin/src/app/app.element.ts | 50 +++++++++++++++++--
apps/example-plugin/src/plugin.ts | 27 ++++++++++-
apps/rpc-api/src/app/routes/root.ts | 56 ++++++++++++++++++++++
docs/plugin-usage.md | 2 +-
libs/plugins-runtime/src/lib/api/index.ts | 27 +++++++----
libs/plugins-runtime/src/lib/index.d.ts | 26 +++++++---
package-lock.json | 13 +++++
package.json | 1 +
8 files changed, 180 insertions(+), 22 deletions(-)
diff --git a/apps/example-plugin/src/app/app.element.ts b/apps/example-plugin/src/app/app.element.ts
index 31e6a2b..c0ab4cd 100644
--- a/apps/example-plugin/src/app/app.element.ts
+++ b/apps/example-plugin/src/app/app.element.ts
@@ -3,9 +3,16 @@ import './app.element.css';
export class AppElement extends HTMLElement {
public static observedAttributes = [];
+ #selection = '';
+ #pageId = '';
+ #fileId = '';
+ #revn = 0;
+
+ refreshPage(pageId: string, name: string) {
+ console.log('refreshPage', pageId, name);
- refreshPageName(name: string) {
const projectName = document.getElementById('project-name');
+ this.#pageId = pageId;
if (projectName) {
projectName.innerText = name;
@@ -13,10 +20,12 @@ export class AppElement extends HTMLElement {
}
refreshSelectionId(selection: string) {
+ this.#selection = selection;
+
const selectionId = document.getElementById('selection-id');
if (selectionId) {
- selectionId.innerText = selection;
+ selectionId.innerText = this.#selection;
}
}
@@ -24,12 +33,17 @@ export class AppElement extends HTMLElement {
window.addEventListener('message', (event) => {
if (event.data.type === 'pingpong') {
console.log('iframe', event.data.content);
+ } else if (event.data.type === 'file') {
+ this.#fileId = event.data.content.id;
+ this.#revn = event.data.content.revn;
} else if (event.data.type === 'page') {
- this.refreshPageName(event.data.content);
+ this.refreshPage(event.data.content.id, event.data.content.name);
} else if (event.data.type === 'selection') {
this.refreshSelectionId(event.data.content);
} else if (event.data.type === 'init') {
- this.refreshPageName(event.data.content.name);
+ this.#fileId = event.data.content.fileId;
+ this.#revn = event.data.content.revn;
+ this.refreshPage(event.data.content.pageId, event.data.content.name);
this.refreshSelectionId(event.data.content.selection);
}
});
@@ -51,6 +65,11 @@ export class AppElement extends HTMLElement {
Need the .env file and run "start:rpc-api"
+
+
+ Need the .env file and run "start:rpc-api"
+
+
@@ -85,6 +104,29 @@ export class AppElement extends HTMLElement {
});
});
+ const removeAction = this.querySelector('.remove-obj');
+
+ removeAction?.addEventListener('click', () => {
+ fetch('http://localhost:3000/delete-object', {
+ method: 'DELETE',
+ body: JSON.stringify({
+ fileId: this.#fileId,
+ revn: this.#revn,
+ pageId: this.#pageId,
+ objectId: this.#selection,
+ }),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ })
+ .then((response) => {
+ return response.json();
+ })
+ .then((data) => {
+ console.log(data);
+ });
+ });
+
parent.postMessage({ content: 'ready' }, '*');
}
}
diff --git a/apps/example-plugin/src/plugin.ts b/apps/example-plugin/src/plugin.ts
index 495fd62..a88600d 100644
--- a/apps/example-plugin/src/plugin.ts
+++ b/apps/example-plugin/src/plugin.ts
@@ -12,10 +12,16 @@ penpot.ui.onMessage<{ content: string }>((message) => {
} else if (message.content === 'close') {
penpot.closePlugin();
} else if (message.content === 'ready') {
+ const pageState = penpot.getPageState();
+ const fileState = penpot.getFileState();
+
penpot.ui.sendMessage({
type: 'init',
content: {
- name: penpot.getPageState().name,
+ name: pageState.name,
+ pageId: pageState.id,
+ fileId: fileState.id,
+ revn: fileState.revn,
selection: penpot.getSelection(),
},
});
@@ -23,7 +29,24 @@ penpot.ui.onMessage<{ content: string }>((message) => {
});
penpot.on('pagechange', (page) => {
- penpot.ui.sendMessage({ type: 'page', content: page.name });
+ penpot.ui.sendMessage({
+ type: 'page',
+ content: {
+ name: page.name,
+ id: page.id,
+ },
+ });
+});
+
+penpot.on('filechange', (file) => {
+ penpot.ui.sendMessage({
+ type: 'file',
+ content: {
+ name: file.name,
+ id: file.id,
+ revn: file.revn,
+ },
+ });
});
penpot.on('selectionchange', (id) => {
diff --git a/apps/rpc-api/src/app/routes/root.ts b/apps/rpc-api/src/app/routes/root.ts
index aa15da3..1a09169 100644
--- a/apps/rpc-api/src/app/routes/root.ts
+++ b/apps/rpc-api/src/app/routes/root.ts
@@ -1,9 +1,11 @@
import { FastifyInstance } from 'fastify';
+import { v4 } from 'uuid';
const token = process.env.ACCESS_TOKEN;
export default async function (fastify: FastifyInstance) {
const apiUrl = process.env.API_URL;
+ const fakeSessionId = v4();
fastify.get('/get-profile', function () {
return fetch(`${apiUrl}/get-profile`, {
@@ -17,4 +19,58 @@ export default async function (fastify: FastifyInstance) {
console.error('Error:', error);
});
});
+
+ fastify.delete<{
+ Body: {
+ fileId: string;
+ revn: number;
+ pageId: string;
+ objectId: string;
+ };
+ }>('/delete-object', function (request, reply) {
+ const payload = {
+ '~:id': `~u${request.body.fileId}`,
+ '~:revn': request.body.revn,
+ '~:session-id': `~u${fakeSessionId}`,
+ '~:changes': [
+ {
+ '~:type': '~:del-obj',
+ '~:page-id': `~u${request.body.pageId}`,
+ '~:ignore-touched': false,
+ '~:id': `~u${request.body.objectId}`,
+ },
+ ],
+ '~:features': {
+ '~#set': [
+ 'layout/grid',
+ 'styles/v2',
+ 'fdata/pointer-map',
+ 'fdata/objects-map',
+ 'fdata/shape-data-type',
+ ],
+ },
+ };
+
+ console.log('Payload:', payload);
+
+ return fetch(
+ `http://localhost:3449/api/rpc/command/update-file?id=${request.body.fileId}`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/transit+json',
+ Authorization: `Token ${token}`,
+ },
+ body: JSON.stringify(payload),
+ }
+ )
+ .then((response) => response.json())
+ .then((data) => {
+ console.log('Success:', data);
+ reply.send(data);
+ })
+ .catch((error) => {
+ console.error('Error:', error);
+ });
+ });
}
diff --git a/docs/plugin-usage.md b/docs/plugin-usage.md
index bc4d892..b9f66db 100644
--- a/docs/plugin-usage.md
+++ b/docs/plugin-usage.md
@@ -14,7 +14,7 @@ Get state:
penpot.ui.getFileState();
// file page state
-penpot.ui.getFileState();
+penpot.ui.getPageState();
// selection id
penpot.ui.getSelection();
diff --git a/libs/plugins-runtime/src/lib/api/index.ts b/libs/plugins-runtime/src/lib/api/index.ts
index 79159c0..9d8b44d 100644
--- a/libs/plugins-runtime/src/lib/api/index.ts
+++ b/libs/plugins-runtime/src/lib/api/index.ts
@@ -25,18 +25,21 @@ window.addEventListener('message', (event) => {
}
});
-export function triggerEvent(type: string, message: T) {
+export function triggerEvent(
+ type: keyof EventsMap,
+ message: EventsMap[keyof EventsMap]
+) {
const listeners = eventListeners.get(type) || [];
listeners.forEach((listener) => listener(message));
}
-export function setPageState(page: unknown) {
+export function setPageState(page: Page) {
pageState = page;
triggerEvent('pagechange', page);
}
-export function setFileState(file: unknown) {
+export function setFileState(file: File) {
fileState = file;
triggerEvent('filechange', file);
@@ -92,25 +95,31 @@ export function createApi() {
setTimeout(callback, time);
}),
closePlugin,
- on: (type: string, fn: Callback) => {
+ on(
+ type: T,
+ callback: (event: EventsMap[T]) => void
+ ): void {
// z.function alter fn, so can't use it here
z.enum(validEvents).parse(type);
- z.function().parse(fn);
+ z.function().parse(callback);
const listeners = eventListeners.get(type) || [];
- listeners.push(fn);
+ listeners.push(callback as Callback);
eventListeners.set(type, listeners);
},
- off: (type: string, fn: () => void) => {
+ off(
+ type: T,
+ callback: (event: EventsMap[T]) => void
+ ): void {
z.enum(validEvents).parse(type);
- z.function().parse(fn);
+ z.function().parse(callback);
const listeners = eventListeners.get(type) || [];
eventListeners.set(
type,
- listeners.filter((listener) => listener !== fn)
+ listeners.filter((listener) => listener !== callback)
);
},
getFileState: () => {
diff --git a/libs/plugins-runtime/src/lib/index.d.ts b/libs/plugins-runtime/src/lib/index.d.ts
index f9dafcc..ec38ba4 100644
--- a/libs/plugins-runtime/src/lib/index.d.ts
+++ b/libs/plugins-runtime/src/lib/index.d.ts
@@ -1,8 +1,19 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
+interface Page {
+ name: string;
+ id: string;
+}
+
+interface File {
+ name: string;
+ id: string;
+ revn: number;
+}
+
interface EventsMap {
- pagechange: { name: string };
- filechange: any;
+ pagechange: Page;
+ filechange: File;
selectionchange: string;
}
@@ -16,16 +27,19 @@ interface Penpot {
sendMessage: (message: unknown) => void;
onMessage: (callback: (message: T) => void) => void;
};
- log: (message: string) => void;
+ log: (...data: any[]) => void;
setTimeout: (callback: () => void, time: number) => void;
closePlugin: () => void;
on: (
type: T,
callback: (event: EventsMap[T]) => void
) => void;
- off: (type: string, callback: () => void) => void;
- getFileState: () => any;
- getPageState: () => any;
+ off: (
+ type: T,
+ callback: (event: EventsMap[T]) => void
+ ) => void;
+ getFileState: () => File;
+ getPageState: () => Page;
getSelection: () => any;
}
diff --git a/package-lock.json b/package-lock.json
index fc66bbb..12f487b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,7 @@
"fastify-plugin": "~4.5.0",
"ses": "^1.1.0",
"tslib": "^2.3.0",
+ "uuid": "^9.0.1",
"zod": "^3.22.4"
},
"devDependencies": {
@@ -11982,6 +11983,18 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
+ "node_modules/uuid": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+ "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
diff --git a/package.json b/package.json
index 7c37cbf..bde2027 100644
--- a/package.json
+++ b/package.json
@@ -62,6 +62,7 @@
"fastify-plugin": "~4.5.0",
"ses": "^1.1.0",
"tslib": "^2.3.0",
+ "uuid": "^9.0.1",
"zod": "^3.22.4"
}
}