update PainterNode
+ Add workflow name to metdata saved to state. + Updated the visual appearance of asset display.
This commit is contained in:
@@ -61,6 +61,12 @@ async def list_painter_assets(request):
|
||||
try:
|
||||
with open(state_path, "r", encoding="utf-8") as f:
|
||||
state = json.load(f)
|
||||
|
||||
metadata = state.get("metadata")
|
||||
if not metadata:
|
||||
metadata = {}
|
||||
|
||||
workflow_name = metadata.get("workflow_name", "Unsaved Workflow")
|
||||
size = state.get("settings", {}).get("currentCanvasSize", {})
|
||||
width = size.get("width")
|
||||
height = size.get("height")
|
||||
@@ -74,6 +80,7 @@ async def list_painter_assets(request):
|
||||
"updated_at": stat.st_mtime,
|
||||
"width": width,
|
||||
"height": height,
|
||||
"workflow_name": workflow_name
|
||||
}
|
||||
)
|
||||
|
||||
@@ -115,10 +122,16 @@ async def save_painter_asset(request):
|
||||
asset_dir = _asset_dir(asset_id)
|
||||
payload = await request.json()
|
||||
state = payload.get("state")
|
||||
workflow_name = payload.get("workflow_name")
|
||||
|
||||
if not isinstance(state, dict):
|
||||
return _json_response_error("state must be an object", 400)
|
||||
|
||||
if not hasattr(state, "metadata"):
|
||||
state.setdefault("metadata", {})
|
||||
|
||||
state["metadata"]["workflow_name"] = workflow_name
|
||||
|
||||
os.makedirs(asset_dir, exist_ok=True)
|
||||
fd, tmp_path = tempfile.mkstemp(
|
||||
prefix=".state-",
|
||||
|
||||
@@ -513,6 +513,7 @@
|
||||
}
|
||||
|
||||
.alekpet_painter_storage_item_card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
@@ -531,11 +532,58 @@
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.alekpet_painter_storage_item_id_text {
|
||||
.alekpet_painter_storage_button_close {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
transition: all 0.4s;
|
||||
border: 0;
|
||||
border-radius: 0 0 0 50%;
|
||||
background: var(--comfy-menu-bg);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.alekpet_painter_storage_button_close:hover {
|
||||
border-radius: 50% 50% 50% 0;
|
||||
padding: 2px;
|
||||
border: 1px solid rgb(255 151 0);
|
||||
background: rgb(255 151 0 / 80%);
|
||||
}
|
||||
|
||||
.alekpet_painter_storage_item_meta {
|
||||
font-size: 11px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
.alekpet_painter_storage_item_id {
|
||||
font-family: monospace;
|
||||
font-size: 11px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.alekpet_painter_storage_item_skew_box {
|
||||
background: linear-gradient(90deg, #727272, transparent);
|
||||
padding: 3px 0px;
|
||||
flex-direction: column;
|
||||
clip-path: polygon(0px 0%, 100% 0%, calc(100% - 15px) 100%, 0% 100%);
|
||||
}
|
||||
|
||||
.alekpet_painter_storage_item_size {
|
||||
background: linear-gradient(90deg, #14377a, transparent);
|
||||
}
|
||||
.alekpet_painter_storage_item_size > span {
|
||||
color: var(----success-color);
|
||||
}
|
||||
|
||||
.alekpet_painter_storage_item_workflow_name {
|
||||
background: linear-gradient(90deg, #096e00, transparent);
|
||||
}
|
||||
.alekpet_painter_storage_item_workflow_name > span {
|
||||
color: var(--success-color);
|
||||
}
|
||||
/* -- end Settings store managing data */
|
||||
|
||||
@@ -118,27 +118,48 @@ export class PainterAssetDialog {
|
||||
canvasEl.style.maxHeight = "100%";
|
||||
previewWrap.appendChild(canvasEl);
|
||||
|
||||
const meta = document.createElement("div");
|
||||
meta.className = "alekpet_painter_storage_item_meta";
|
||||
|
||||
const id = document.createElement("div");
|
||||
id.textContent = asset.asset_id;
|
||||
id.title = asset.asset_id;
|
||||
id.className = "alekpet_painter_storage_item_id_text";
|
||||
id.className = "alekpet_painter_storage_item_id";
|
||||
|
||||
const meta = document.createElement("div");
|
||||
meta.textContent = `${formatBytes(asset.size)}${asset.width && asset.height ? ` · ${asset.width}×${asset.height}` : ""}`;
|
||||
meta.style.fontSize = "11px";
|
||||
const size = document.createElement("div");
|
||||
size.title = "Data size · Pixel resolution";
|
||||
size.innerHTML = `Size: <span>${formatBytes(asset.size)}</span> · WxH: <span>${asset.width && asset.height ? ` · ${asset.width}×${asset.height}` : ""}</span>`;
|
||||
size.className =
|
||||
"alekpet_painter_storage_item_skew_box alekpet_painter_storage_item_size";
|
||||
|
||||
const workflow_name = document.createElement("div");
|
||||
workflow_name.innerHTML = `Workflow: <span>${asset.workflow_name}</span>`;
|
||||
workflow_name.title = `Last used workflow: ${asset.workflow_name}`;
|
||||
workflow_name.className =
|
||||
"alekpet_painter_storage_item_skew_box alekpet_painter_storage_item_workflow_name";
|
||||
|
||||
const buttons = document.createElement("div");
|
||||
Object.assign(buttons.style, { display: "flex", gap: "6px" });
|
||||
|
||||
const add = document.createElement("button");
|
||||
add.textContent = "➕ Add to scene";
|
||||
add.onclick = () => this.addToScene(asset.asset_id);
|
||||
add.textContent = "➕ Add as copy";
|
||||
add.title = "Add to workflow as copy.";
|
||||
add.onclick = () => this.addToWorkflow(asset.asset_id);
|
||||
|
||||
const addRef = document.createElement("button");
|
||||
addRef.textContent = "🔗 Add as reference";
|
||||
addRef.title =
|
||||
"Add to workflow as reference. Attention: the change will affect all copies in workflows!";
|
||||
addRef.onclick = () => this.addToWorkflow(asset.asset_id, true);
|
||||
|
||||
const remove = document.createElement("button");
|
||||
remove.textContent = "🗑 Delete";
|
||||
remove.textContent = "🗑️";
|
||||
remove.title = "Remove canvas data";
|
||||
remove.className = "alekpet_painter_storage_button_close";
|
||||
remove.onclick = () => this.deleteAsset(asset.asset_id, card);
|
||||
|
||||
buttons.append(add, remove);
|
||||
buttons.append(add, addRef, remove);
|
||||
meta.append(id, workflow_name, size);
|
||||
card.append(previewWrap, id, meta, buttons);
|
||||
this.items.appendChild(card);
|
||||
|
||||
@@ -182,7 +203,7 @@ export class PainterAssetDialog {
|
||||
});
|
||||
}
|
||||
|
||||
async addToScene(assetId) {
|
||||
async addToWorkflow(assetId, persist = false) {
|
||||
const LiteGraph = globalThis.LiteGraph;
|
||||
if (!LiteGraph) {
|
||||
console.error("[PainterAssetDialog] LiteGraph is unavailable");
|
||||
@@ -219,10 +240,13 @@ export class PainterAssetDialog {
|
||||
|
||||
await painter.loadCanvasData(assetRef(assetId), painterIndex, {
|
||||
migrateImage: false,
|
||||
persist,
|
||||
});
|
||||
|
||||
painter.node.painterAsset.asset_id = createPainterAssetId();
|
||||
await painter.persistPainterState();
|
||||
if (!persist) {
|
||||
painter.node.painterAsset.asset_id = createPainterAssetId();
|
||||
await painter.persistPainterState();
|
||||
}
|
||||
|
||||
app.graph.setDirtyCanvas(true, false);
|
||||
}
|
||||
|
||||
@@ -118,6 +118,16 @@ async function getLoadedFonts() {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getActiveWorkflowName() {
|
||||
const workflow = app?.extensionManager?.workflow?.activeWorkflow;
|
||||
|
||||
return (
|
||||
workflow?.filename?.replace(/\.json$/i, "") ||
|
||||
workflow?.key ||
|
||||
"Unsaved Workflow"
|
||||
);
|
||||
}
|
||||
// ================= END FUNCTIONS ================
|
||||
|
||||
// ================= CLASS PAINTER ================
|
||||
@@ -2501,7 +2511,10 @@ class Painter {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ state: nextState }),
|
||||
body: JSON.stringify({
|
||||
state: nextState,
|
||||
workflow_name: getActiveWorkflowName(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
@@ -2874,7 +2887,7 @@ class Painter {
|
||||
// - end
|
||||
}
|
||||
|
||||
async loadCanvasData(data, painter_idx, options = {}) {
|
||||
async loadCanvasData(data, painter_idx, options = { persist: true }) {
|
||||
// New workflows store only {version, asset_id}
|
||||
if (isPainterAssetRef(data)) {
|
||||
this.node.painterAsset = {
|
||||
@@ -2939,7 +2952,10 @@ class Painter {
|
||||
}
|
||||
|
||||
// Migrate legacy workflow data, or repair a missing backend asset
|
||||
await this.persistPainterState(data);
|
||||
if (options.persist !== false) {
|
||||
await this.persistPainterState(data);
|
||||
}
|
||||
|
||||
if (data?.canvas_settings && options.migrateImage !== false) {
|
||||
await this.uploadPaintFile(this.node.name);
|
||||
}
|
||||
@@ -3237,7 +3253,7 @@ app.registerExtension({
|
||||
// Managing data
|
||||
app.ui.settings.addSetting({
|
||||
id: `${extensionName}.ManagingData`,
|
||||
name: "🔸 Managing JSON data storage",
|
||||
name: "🔸 Managing JSON data assets",
|
||||
defaultValue: false,
|
||||
type: (name, sett, val) => {
|
||||
return makeElement("tr", {
|
||||
|
||||
Reference in New Issue
Block a user