update readme and add icons

This commit is contained in:
2026-03-29 23:40:07 -07:00
parent 52da360804
commit 79b89da023
25 changed files with 865 additions and 198 deletions

View File

@@ -2130,6 +2130,24 @@ function Flow() {
input.click();
}, [applyWorkflowData]);
const uploadPlugin = useCallback(() => {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.py';
input.onchange = async (e) => {
const file = e.target.files[0];
if (!file) return;
setStatus({ text: 'Uploading plugin…', level: 'info' });
try {
await api.uploadPlugin(file);
// Node list refresh is handled by the nodes_updated WebSocket message.
} catch (err) {
setStatus({ text: err.message, level: 'error' });
}
};
input.click();
}, []);
// ── Drag-and-drop workflow image loading ───────────────────────────
const onDropFile = useCallback(async (event) => {
@@ -2820,6 +2838,9 @@ function Flow() {
<button className="btn" onClick={copySnapshot} title="Copy workflow screenshot to clipboard">
Snapshot
</button>
<button className="btn" onClick={uploadPlugin} title="Upload a plugin (.py)">
Plugin
</button>
</div>
<div className={`status-bar ${status.level}`}>{status.text}</div>

View File

@@ -90,6 +90,20 @@ export async function uploadFile(file, { relativePath = '' } = {}) {
return r.json();
}
export async function uploadPlugin(file) {
const fd = new FormData();
fd.append('file', file);
const r = await fetch('/upload-plugin', { method: 'POST', body: fd });
if (r.status === 404) {
throw new Error('Plugin upload is not available in this build.');
}
if (!r.ok) {
const text = await r.text();
throw new Error(text || `Upload failed (${r.status})`);
}
return r.json();
}
export async function getChannels(filepath) {
const r = await sessionFetch(`/channels?file=${encodeURIComponent(filepath)}`);
if (!r.ok) return [{ name: 'field', type: 'DATA_FIELD' }];