Compare commits

..
1 Commits
Author SHA1 Message Date
Ivor StrelarandClaude Opus 5 b0952e0fb3 Revert "fix: drop the HTTP endpoint that left 1.0.8 pending registry review"
Removing the route did not clear the Pending status: 1.0.9 shipped without
it and sits Pending alongside 1.0.8, so the endpoint was never the cause.
Pending appears to be the normal post-upload state before a scan promotes a
version to Active.

Restores the Refresh button and its preview endpoint.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 13:40:42 +02:00
4 changed files with 107 additions and 2 deletions
+2
View File
@@ -179,6 +179,8 @@ and skips row 2. Each prompt triggers a separate pass through the downstream gra
- **Scanning stops at the first empty prompt cell**, so anything below a gap is ignored.
- **The sheet is re-read on every run**, so edits you make in the browser are picked up
automatically. Add rows or clear status cells and just hit Run again.
- **Refresh sheet** is optional — it reports how many prompts are pending without running
the graph.
---
+29 -1
View File
@@ -157,7 +157,8 @@ all. Write `done` next to a prompt in the sheet and the next run skips it; clear
the cell and it gets queued again. Scanning stops at the first empty prompt cell.
The sheet is re-read fresh on every run, so edits you make in the browser are
picked up automatically — there is nothing to refresh by hand.
always picked up. **Refresh sheet** is optional — it reports how many prompts
are pending without having to run the graph.
"""
@classmethod
@@ -197,3 +198,30 @@ picked up automatically — there is nothing to refresh by hand.
NODE_CLASS_MAPPINGS = {"SFGoogleSheetPromptQueue": SFGoogleSheetPromptQueue}
NODE_DISPLAY_NAME_MAPPINGS = {"SFGoogleSheetPromptQueue": "SF Google Sheet Prompt Queue"}
# --- Server route backing the node's Refresh button ---------------------------
try:
from aiohttp import web
from server import PromptServer
@PromptServer.instance.routes.post("/sf_gsheet/preview")
async def _preview(request):
body = await request.json()
try:
rows = fetch_rows(body.get("url", ""), body.get("sheet_gid", "0"))
pending, total = scan_rows(
rows,
col_letter_to_index(body.get("prompt_col", "A")),
col_letter_to_index(body.get("status_col", "B")),
bool(body.get("skip_first_row", True)),
)
return web.json_response(
{"ok": True, "total": total, "pending": len(pending)}
)
except Exception as e:
return web.json_response({"ok": False, "error": str(e)})
except ImportError:
pass
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui-sf-nodes"
description = "Custom nodes for ComfyUI including LLM Chat with support for Claude, Gemini, and OpenAI models, WaveSpeed AI image/video generation, VertexAI integration, and workflow utilities"
version = "1.0.9"
version = "1.0.10"
license = { file = "LICENSE" }
dependencies = [
"requests>=2.31.0",
+75
View File
@@ -0,0 +1,75 @@
/**
* SF Google Sheet Prompt Queue — adds a Refresh button that re-reads the sheet
* and reports how many prompts are still waiting to run.
*/
import { app } from "../../../scripts/app.js";
import { api } from "../../../scripts/api.js";
const NODE_NAME = "SFGoogleSheetPromptQueue";
function widgetValue(node, name, fallback) {
const widget = node.widgets?.find((w) => w.name === name);
return widget ? widget.value : fallback;
}
app.registerExtension({
name: "Stillfront.GoogleSheetPromptQueue",
async beforeRegisterNodeDef(nodeType, nodeData) {
if (nodeData.name !== NODE_NAME) {
return;
}
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const result = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;
const node = this;
const status = node.addWidget("text", "", "Press Refresh to read the sheet", () => {});
status.disabled = true;
status.serialize = false;
const setStatus = (text) => {
status.value = text;
node.setDirtyCanvas(true, false);
};
const refreshButton = node.addWidget("button", "Refresh sheet", null, async () => {
setStatus("Reading sheet…");
try {
const response = await api.fetchApi("/sf_gsheet/preview", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
url: widgetValue(node, "url", ""),
sheet_gid: widgetValue(node, "sheet_gid", "0"),
prompt_col: widgetValue(node, "prompt_col", "A"),
status_col: widgetValue(node, "status_col", "B"),
skip_first_row: widgetValue(node, "skip_first_row", true),
}),
});
const data = await response.json();
if (!data.ok) {
setStatus(`Error: ${data.error}`);
return;
}
const cap = widgetValue(node, "max_rows", 10);
const willSend = Math.min(data.pending, cap);
setStatus(
data.pending === 0
? `Nothing pending — all ${data.total} prompt(s) marked`
: `${data.pending} pending of ${data.total} — next run sends ${willSend}`
);
} catch (e) {
setStatus("Could not reach ComfyUI server");
}
});
refreshButton.serialize = false;
return result;
};
},
});