From f6de1f0abad3de6a968c1dc679f59744b6377cf0 Mon Sep 17 00:00:00 2001 From: CMonk Date: Sun, 12 May 2024 21:14:59 +0800 Subject: [PATCH 1/5] Add multi-client(multi-user) support. client-server-ps match logic is: Under most cases, client-server-ps matching will be automatic, and the experience will be the same for single user, but for some special cases, user name needs to be set. In detail: If there is only one ps instance per IP address, all the client with the same ip address will use the one PS instance. So in most cases, which will be: local server, private remote server, even on public server, people with different public ip addresses are ok. Problem will be when multiple ps instances are under the same public ip address (VPN, behind NAT, etc). User will have to input matching user name in ComfyUI Settings-> SD-PPP User Name, and in PS plugin, so the server knows which PS instance to use. --- comfy/nodes.py | 67 +++++----- comfy/photoshop_instance.py | 11 +- comfy/photoshop_manager.py | 116 ++++++++++++++++++ comfy/sdppp.py | 45 +++++-- comfy/static/js/sd-ppp.js | 43 ++++++- photoshop/dist/index.js | 80 ++++++++---- photoshop/dist/manifest.json | 8 +- photoshop/plugin/manifest.json | 8 +- photoshop/src/controllers/PanelController.jsx | 2 +- photoshop/src/panels/Main.jsx | 22 +++- photoshop/src/styles.css | 3 + photoshop/src/system/ComfyConnection.js | 16 ++- photoshop/src/system/events/get_image.js | 7 +- photoshop/src/system/events/send_images.js | 11 +- photoshop/src/system/util.js | 13 +- 15 files changed, 354 insertions(+), 98 deletions(-) create mode 100644 comfy/photoshop_manager.py diff --git a/comfy/nodes.py b/comfy/nodes.py index 77d65da..e4093b7 100644 --- a/comfy/nodes.py +++ b/comfy/nodes.py @@ -2,13 +2,11 @@ import numpy as np import time from nodes import LoadImage from .apis import cache_images +from .photoshop_manager import PhotoshopManager +from server import PromptServer +prompt_server = PromptServer.instance def define_comfyui_nodes(sdppp): - def validate_sdppp(): - if not sdppp.has_ps_instance(): - return 'Photoshop is not connected' - return True - def call_async_func_in_server_thread(coro, dontwait = False): handle = { 'done': False, @@ -29,36 +27,32 @@ def define_comfyui_nodes(sdppp): class GetImageFromPhotoshopLayerNode: - @classmethod - def VALIDATE_INPUTS(s, layer): - return validate_sdppp() + # !!!!do not validate because there's no client_id when validating, so we validate manually before execution!!!! + # @classmethod + # def VALIDATE_INPUTS(): + # pass @classmethod def IS_CHANGED(self, layer, use_layer_bounds): - if not sdppp.has_ps_instance(): + photoshopInstance = PhotoshopManager.instance().instance_from_client_id(prompt_server.client_id) + if not photoshopInstance: return np.random.rand() else: - photoshopInstance = sdppp.get_ps_instance() id = photoshopInstance.layer_name_to_id(layer) bounds_id = photoshopInstance.layer_name_to_id(use_layer_bounds, id) start = time.time() is_changed, history_state_id = call_async_func_in_server_thread(photoshopInstance.check_layer_bounds_combo_changed(id, bounds_id)) if is_changed and history_state_id is None: - return np.random.rand() - photoshopInstance.update_comfyui_last_value(id, bounds_id, history_state_id) - return history_state_id + return photoshopInstance.update_comfyui_last_value(id, bounds_id, np.random.rand()) + return photoshopInstance.update_comfyui_last_value(id, bounds_id, history_state_id) @classmethod def INPUT_TYPES(cls): - if validate_sdppp() is not True: - layer_strs = [] - bounds_strs = [] - else: - layer_strs = sdppp.get_ps_instance().get_base_layers() - bounds_strs = sdppp.get_ps_instance().get_bounds_layers() - + layer_strs = [] + bounds_strs = [] return { - "required": { + "required": {}, + "optional": { "layer": (layer_strs, {"default": layer_strs[0] if len(layer_strs) > 0 else None}), "use_layer_bounds": (bounds_strs, {"default": bounds_strs[0] if len(bounds_strs) > 0 else None}), } @@ -70,10 +64,16 @@ def define_comfyui_nodes(sdppp): CATEGORY = "Photoshop" def get_image(self, layer, use_layer_bounds): - if validate_sdppp() is not True: + photoshopInstance = PhotoshopManager.instance().instance_from_client_id(prompt_server.client_id) + if not photoshopInstance: raise ValueError('Photoshop is not connected') - photoshopInstance = sdppp.get_ps_instance() - + layer_strs = photoshopInstance.get_base_layers() + if layer not in layer_strs: + raise ValueError(f"Layer {layer} not found in Photoshop") + bounds_strs = photoshopInstance.get_bounds_layers() + if use_layer_bounds not in bounds_strs: + raise ValueError(f"Layer {use_layer_bounds} not found in Photoshop") + id = photoshopInstance.layer_name_to_id(layer) bounds_id = photoshopInstance.layer_name_to_id(use_layer_bounds, id) @@ -86,19 +86,18 @@ def define_comfyui_nodes(sdppp): class SendImageToPhotoshopLayerNode: - @classmethod - def VALIDATE_INPUTS(s, images): - return validate_sdppp() + # !!!!do not validate because there's no client_id when validating, so we validate manually before execution!!!! + # @classmethod + # def VALIDATE_INPUTS(): + # pass @classmethod def INPUT_TYPES(cls): - if validate_sdppp() is not True: - layer_strs = [] - else: - layer_strs = sdppp.get_ps_instance().get_set_layers() + layer_strs = [] return { - "required": { + "required": {}, + "optional": { "images": ("IMAGE", ), "layer": (layer_strs, {"default": layer_strs[0] if len(layer_strs) > 0 else None}), } @@ -110,9 +109,9 @@ def define_comfyui_nodes(sdppp): OUTPUT_NODE = True def send_image(self, images, layer): - if validate_sdppp() is not True: + photoshopInstance = PhotoshopManager.instance().instance_from_client_id(prompt_server.client_id) + if not photoshopInstance: raise ValueError('Photoshop is not connected') - photoshopInstance = sdppp.get_ps_instance() ret = cache_images(images) layer_id = photoshopInstance.layer_name_to_id(layer) diff --git a/comfy/photoshop_instance.py b/comfy/photoshop_instance.py index c70cb16..b56e411 100644 --- a/comfy/photoshop_instance.py +++ b/comfy/photoshop_instance.py @@ -13,11 +13,17 @@ class PhotoshopInstance: SPECIAL_LAYER_SAME_AS_LAYER: -3 } - def __init__(self, sdppp, sid): + def __init__(self, sdppp, sid, uid): self.sdppp = sdppp self.sid = sid + self.uid = uid self.layers = [] + self.on_destroy = None self.reset_change_tracker() + + def destroy(self): + if self.on_destroy: + self.on_destroy(self) def get_layers(self): return list(map(lambda layer: f"{layer['name']} (id:{layer['id']})", self.layers)) @@ -83,6 +89,8 @@ class PhotoshopInstance: # for apis calls async def is_ps_history_changed(self): current_id = await self.get_active_history_state_id() + if self.get_img_state_id is None or current_id is None: + return False return self.get_img_state_id != current_id and self.get_img_state_id < current_id async def check_layer_bounds_combo_changed(self, layer, use_layer_bounds): @@ -102,6 +110,7 @@ class PhotoshopInstance: def update_comfyui_last_value(self, layer, use_layer_bounds, value): layer_bounds_combo = f"{layer}{use_layer_bounds}" self.comfyui_last_value_tracker[layer_bounds_combo] = value + return value # need to update history id after internal operation otherwise it might cause infinite change loop async def _update_history_state_id_after_internal_change(self, history_state_id=None): diff --git a/comfy/photoshop_manager.py b/comfy/photoshop_manager.py new file mode 100644 index 0000000..e4b0bcc --- /dev/null +++ b/comfy/photoshop_manager.py @@ -0,0 +1,116 @@ +import asyncio +from .photoshop_instance import PhotoshopInstance +DEFAULT_ID = 0 + +class PhotoshopManager: + _instance = None + + @classmethod + def instance(cls) -> 'PhotoshopManager': + if cls._instance is None: + cls._instance = PhotoshopManager() + return cls._instance + + def __init__(self): + # client id info + self.ip_to_client_id_list = {} + self.client_id_to_userid = {} + # ps instance info + self.ip_to_ps_instance_list = {} + # final match + self.client_id_to_ps_instance = {} + + # get instance from client information, match new instance if not exist + def instance_from_client_info(self, ip, client_id, user_id) -> PhotoshopInstance: + if not ip: return None + if not client_id: user_id = 0 + if not user_id: user_id = 0 + instance = self.instance_from_client_id(client_id) + if instance is not None: + return instance + self._add_new_client(ip, client_id, user_id) + self._client_match_ps(ip, client_id, user_id) + return self.instance_from_client_id(client_id) + + # get instance from client id + def instance_from_client_id(self, client_id) -> PhotoshopInstance: + return self.client_id_to_ps_instance.get(client_id, None) + + # create new instance and record + async def new_ps_instance(self, sdppp, sid, ip, user_id) -> PhotoshopInstance: + if not ip: return None + if not user_id: user_id = 0 + # create new instance + instance = PhotoshopInstance(sdppp, sid, user_id) + instance.on_destroy = self._on_instance_destroy + # record new instance + await self._add_new_ps_instance(ip, instance) + return instance + + #------------------------------------------------------------------------------------------------------------------------------------------------ + # callback when instance is destroyed and remove from record + def _on_instance_destroy(self, instance): + self._remove_instance(instance) + + # record new ps instance for matching + async def _add_new_ps_instance(self, ip, instance): + # find old one and destroy + same_ip_list = self.ip_to_ps_instance_list.get(ip, []) + for check_instance in same_ip_list: + if check_instance.uid == instance.uid: + await check_instance.destroy() + # record ip to instance + ps_instance_list = self.ip_to_ps_instance_list.get(ip, []) + if instance not in ps_instance_list: + ps_instance_list.append(instance) + self.ip_to_ps_instance_list[ip] = ps_instance_list + + # record new client id + def _add_new_client(self, ip, client_id, user_id): + # record client id, if exist, do nothing + client_id_list = self.ip_to_client_id_list.get(ip, []) + if client_id in client_id_list: + return + client_id_list.append(client_id) + self.ip_to_client_id_list[ip] = client_id_list + # record user_id + self.client_id_to_userid[client_id] = user_id + + # match client id to ps instance for prompt use + # there are several ways to match: + # 1. one to one match(local network most likely): same ip client and ps instance, assign to it + # 2. multiple ps instance under the same ip(remote service most likely), check user id + def _client_match_ps(self, ip, client_id, user_id): + # check existing pair + instance = self.client_id_to_ps_instance.get(client_id, None) + if instance is not None: + return + # check same ip ps instance + ps_instance_list = self.ip_to_ps_instance_list.get(ip, []) + count = len(ps_instance_list) + if count <= 0: + return + # if only one same ip ps instance, assign client id + if count == 1: + self.client_id_to_ps_instance[client_id] = ps_instance_list[0] + return + # if more than one same ip ps instance, check same user_id, same ip + same user id = same ps instance + ps_user_id_list = [instance.uid for instance in ps_instance_list] + try: + check_index = ps_user_id_list.index(user_id) + except: + check_index = None + if check_index is None: + return + self.client_id_to_ps_instance[client_id] = ps_instance_list[check_index] + + def _remove_instance(self, instance): + # remove id from ip to instance list + for ip, ps_instance_list in self.ip_to_ps_instance_list.items(): + if instance in ps_instance_list: + ps_instance_list.remove(instance) + # remove instance from client id to instance + for client_id in list(self.client_id_to_ps_instance.keys()): + check_instance = self.client_id_to_ps_instance.get(client_id, None) + if check_instance == instance: + self.client_id_to_ps_instance.pop(client_id, None) \ No newline at end of file diff --git a/comfy/sdppp.py b/comfy/sdppp.py index 31a2b56..54bfd76 100644 --- a/comfy/sdppp.py +++ b/comfy/sdppp.py @@ -2,13 +2,13 @@ import socketio import json import asyncio from socketio import exceptions -from .photoshop_instance import PhotoshopInstance -empty_queue = [] +from .photoshop_manager import PhotoshopManager class SDPPP: def __init__(self, PromptServer): self.photoshop_instances = dict() self.comfyui_instances = dict() + self.sid_to_ip = dict() self.sio = socketio.AsyncServer(async_mode='aiohttp', cors_allowed_origins="*") self.sio.attach(PromptServer.instance.app, socketio_path='/sd-ppp/') @@ -25,12 +25,25 @@ class SDPPP: if sid is None: sid = list(self.photoshop_instances.keys())[0] return self.photoshop_instances[sid] + + def get_client_info_from_event(self, sid, data): + ip = self.sid_to_ip[sid] + if not ip: + return + client_id = data.get('client_id', None) + if not client_id: + client_id = 0 + user_id = data.get('user_id', None) + if not user_id: + user_id = 0 + return ip, client_id, user_id def registerSocketListeners(self): sio = self.sio @sio.event async def connect(sid, environ): + ip = self.sid_to_ip[sid] = environ['REMOTE_ADDR'] qs = environ['QUERY_STRING'] qsobj = dict(x.split('=') for x in qs.split('&')) @@ -38,12 +51,20 @@ class SDPPP: raise exceptions.ConnectionRefusedError('instance type missed in query') elif qsobj['type'] == 'photoshop': - if len(self.photoshop_instances) > 0: - raise exceptions.ConnectionRefusedError('only 1 instance is allowed now') - self.photoshop_instances[sid] = PhotoshopInstance(self, sid) + user_id = qsobj.get('user_id', None) + if not user_id: + user_id = 0 + self.photoshop_instances[sid] = await PhotoshopManager.instance().new_ps_instance(self, sid, ip, user_id) elif qsobj['type'] == 'comfyui': self.comfyui_instances[sid] = True + client_id = qsobj.get('client_id', None) + if not client_id: + client_id = 0 + user_id = qsobj.get('user_id', None) + if not user_id: + user_id = 0 + PhotoshopManager.instance().instance_from_client_info(ip, client_id, user_id) else: raise exceptions.ConnectionRefusedError('unknown instance type ' + qsobj['type']) @@ -53,9 +74,11 @@ class SDPPP: @sio.event async def disconnect(sid): if sid in self.photoshop_instances: - self.photoshop_instances.pop(sid, None) + instance = self.photoshop_instances.pop(sid, None) + instance.destroy() elif sid in self.comfyui_instances: self.comfyui_instances.pop(sid, None) + self.sid_to_ip.pop(sid, None) # only emit by photoshop instance @sio.event @@ -76,8 +99,9 @@ class SDPPP: }, to=sid) @sio.event - async def check_changes(sid): - instance = self.get_ps_instance() + async def check_changes(sid, data): + ip, client_id, user_id = self.get_client_info_from_event(sid, data) + instance = PhotoshopManager.instance().instance_from_client_info(ip, client_id, user_id) if instance is None: return if not await instance.is_ps_history_changed(): @@ -85,8 +109,9 @@ class SDPPP: await sio.emit('trigger_graph_change', to=sid) @sio.event - async def reset_changes(sid): - instance = self.get_ps_instance() + async def init(sid, data): + ip, client_id, user_id = self.get_client_info_from_event(sid, data) + instance = PhotoshopManager.instance().instance_from_client_info(ip, client_id, user_id) if instance is None: return instance.reset_change_tracker() diff --git a/comfy/static/js/sd-ppp.js b/comfy/static/js/sd-ppp.js index a1e6eb9..9149264 100644 --- a/comfy/static/js/sd-ppp.js +++ b/comfy/static/js/sd-ppp.js @@ -8,12 +8,44 @@ let setLayerStrs = []; let socket = null; console.log("[sd-ppp]", "Loading js extension"); + +const DEFAULT_USER_ID = "Change if sharing remote server" + +function getUserId() { + let userId = app.ui.settings.getSettingValue("SD-PPP.userId"); + if (!userId || userId == DEFAULT_USER_ID) { + userId = ""; + } + return userId; +} + app.registerExtension({ name: "Comfy.SD-PPP", init() { }, async setup() { + // set change query loop setInterval(checkChanges, 1000); + // add setting for using remote server + const userName = localStorage["Comfy.userName"]; + const emptyValue = app.multiUserServer ? userName : DEFAULT_USER_ID + app.ui.settings.addSetting({ + id: "SD-PPP.userId", + name: "SD-PPP: User ID", + defaultValue: emptyValue, + onChange: async (value, oldValue) => { + if (!value) { + setTimeout(() => { + app.ui.settings.setSettingValue("SD-PPP.userId", emptyValue); + if (!app.multiUserServer) return; + // Change empty text box to user name immediately when in multi-user mode, it's recommanded in multi-user environment + const input = document.querySelector("#SD-PPP-userId") + if (input) input.value = emptyValue; + }, 0.01);; + } + }, + type: "text", + }); socket = socketio(location.origin, { transports: ["websocket"], @@ -25,7 +57,10 @@ app.registerExtension({ }); socket.on('connect', () => { - socket.emit('reset_changes'); + socket.emit('init', { + client_id: api.clientId, + user_id: getUserId(), + }); }); socket.on('disconnect', () => { }); @@ -71,7 +106,6 @@ app.registerExtension({ if(onMouseEnter) await onMouseEnter.call(this, ...args); this_handler.call(this); } - } } }); @@ -90,7 +124,10 @@ async function checkHistoryChanges() { const mode0NodeTypes = currentState.nodes.filter(node => node.mode == 0).map(node => node.type); const containsSDPPPNodes = mode0NodeTypes.some(nodeType => SDPPPNodes.includes(nodeType)); if (!containsSDPPPNodes) return; - socket.emit('check_changes') + socket.emit('check_changes', { + client_id: api.clientId, + user_id: getUserId(), + }) } catch (e) { console.error("[sd-ppp]", "Failed to check changes", e); } diff --git a/photoshop/dist/index.js b/photoshop/dist/index.js index 1bb5e46..03f2d6a 100644 --- a/photoshop/dist/index.js +++ b/photoshop/dist/index.js @@ -42,7 +42,7 @@ class PanelController { } create() { this[_root] = document.createElement("div"); - this[_root].style.height = "100vh"; + this[_root].style.height = "130vh"; this[_root].style.overflow = "auto"; this[_root].style.padding = "8px"; react_dom__WEBPACK_IMPORTED_MODULE_0__.render(this[_Component]({ @@ -107,6 +107,15 @@ class Main extends react__WEBPACK_IMPORTED_MODULE_0__.Component { comfyURL: instance ? instance.comfyURL : '' }); }); + uxp__WEBPACK_IMPORTED_MODULE_2__.storage.secureStorage.getItem('userId').then(value => { + if (!value) return; + this.setState({ + userId: Buffer.from(value).toString() + }); + if (this.state.userId) { + console.log('userId:', this.state.userId); + } + }); uxp__WEBPACK_IMPORTED_MODULE_2__.storage.secureStorage.getItem('comfyURL').then(value => { if (!value) return; this.setState({ @@ -119,7 +128,7 @@ class Main extends react__WEBPACK_IMPORTED_MODULE_0__.Component { }); } doConnectOrDisconnect() { - if (!_system_ComfyConnection__WEBPACK_IMPORTED_MODULE_1__["default"].instance?.isConnected) _system_ComfyConnection__WEBPACK_IMPORTED_MODULE_1__["default"].createInstance(this.state.comfyURL);else _system_ComfyConnection__WEBPACK_IMPORTED_MODULE_1__["default"].instance.disconnect(); + if (!_system_ComfyConnection__WEBPACK_IMPORTED_MODULE_1__["default"].instance?.isConnected) _system_ComfyConnection__WEBPACK_IMPORTED_MODULE_1__["default"].createInstance(this.state.comfyURL, this.state.userId);else _system_ComfyConnection__WEBPACK_IMPORTED_MODULE_1__["default"].instance.disconnect(); } render() { return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-textfield", { @@ -130,6 +139,15 @@ class Main extends react__WEBPACK_IMPORTED_MODULE_0__.Component { }, value: this.state.comfyURL, placeholder: "http://127.0.0.1:8188" + }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-textfield", { + id: "user-id-bar", + label: "USER ID", + onInput: ev => { + this.state.userId = ev.currentTarget.value; + if (!this.state.userId) uxp__WEBPACK_IMPORTED_MODULE_2__.storage.secureStorage.removeItem('userId');else uxp__WEBPACK_IMPORTED_MODULE_2__.storage.secureStorage.setItem('userId', this.state.userId); + }, + value: this.state.userId, + placeholder: "User Name: Change if sharing remote server" }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "button-box" }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-button", { @@ -187,20 +205,27 @@ class ComfyConnection { } }); } - static createInstance(comfyURL) { + static createInstance(comfyURL, userId) { if (ComfyConnection.instance && ComfyConnection.instance.isConnected) { ComfyConnection.instance.disconnect(); } - ComfyConnection.instance = new ComfyConnection(comfyURL); + ComfyConnection.instance = new ComfyConnection(comfyURL, userId); } get isConnected() { return this.socket != null && this.socket.connected === true; } comfyURL = ''; interval = null; - constructor(comfyURL) { + constructor(comfyURL, userId) { ComfyConnection.instance = this; + if (!comfyURL) { + comfyURL = 'http://127.0.0.1:8188'; + } this.comfyURL = comfyURL.replace(/\/*$/, ''); + if (!userId) { + userId = ''; + } + this.userId = userId; this.connect(); } connect() { @@ -223,7 +248,8 @@ class ComfyConnection { path: '/sd-ppp/', query: { version: 1, - type: 'photoshop' + type: 'photoshop', + user_id: this.userId } }); this.interval = setInterval(() => { @@ -335,12 +361,13 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ }); /* harmony import */ var photoshop__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! photoshop */ "photoshop"); /* harmony import */ var photoshop__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(photoshop__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../util.js */ "./src/system/util.js"); +/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../util */ "./src/system/util.js"); /* harmony import */ var _library_jimp_min__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../library/jimp.min */ "./src/system/library/jimp.min.js"); /* harmony import */ var _library_jimp_min__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_library_jimp_min__WEBPACK_IMPORTED_MODULE_2__); + function isLayerFolder(layer) { return layer.layers && layer.layers.length > 0; } @@ -412,8 +439,8 @@ function getDesiredBounds(boundsLayerID) { width: photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument.width, height: photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument.height }; - // if boundsLayerID == -1, use selection bounds - if (boundsLayerID == -1) { + // use selection bounds + if (boundsLayerID == _util_js__WEBPACK_IMPORTED_MODULE_1__.SPECIAL_LAYER_NAME_TO_ID[_util_js__WEBPACK_IMPORTED_MODULE_1__.SPECIAL_LAYER_USE_SELECTION]) { // if no selection use document bounds const selectionBounds = photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument.selection?.bounds; if (!selectionBounds) return docBounds; @@ -459,7 +486,7 @@ async function getImage(comfyURL, params) { const startTime = Date.now(); let layer; let isFolder = false; - const activeLayers = photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument.activeLayers; + const activeLayers = photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument?.activeLayers; try { hostControl = executionContext.hostControl; suspensionID = await hostControl.suspendHistory({ @@ -548,16 +575,7 @@ __webpack_require__.r(__webpack_exports__); -const SPECIAL_LAYER_USE_CANVAS = '### Use Canvas ###'; -const SPECIAL_LAYER_USE_SELECTION = '### Use Selection ###'; -const SPECIAL_LAYER_NEW_LAYER = '### New Layer ###'; -const SPECIAL_LAYER_SAME_AS_LAYER = '### Same as Layer ###'; -const SPECIAL_LAYER_NAME_TO_ID = { - SPECIAL_LAYER_USE_CANVAS: 0, - SPECIAL_LAYER_USE_SELECTION: -1, - SPECIAL_LAYER_NEW_LAYER: -2, - SPECIAL_LAYER_SAME_AS_LAYER: -3 -}; + function autocrop(jimp) { let minX = jimp.bitmap.width - 1; let minY = jimp.bitmap.height - 1; @@ -586,7 +604,7 @@ async function sendImages(comfyURL, params) { let newLayerName; await (0,_util_js__WEBPACK_IMPORTED_MODULE_1__.executeAsModalUntilSuccess)(async () => { try { - if (layerId && layerId != SPECIAL_LAYER_NAME_TO_ID[SPECIAL_LAYER_NEW_LAYER]) { + if (layerId && layerId != _util_js__WEBPACK_IMPORTED_MODULE_1__.SPECIAL_LAYER_NAME_TO_ID[_util_js__WEBPACK_IMPORTED_MODULE_1__.SPECIAL_LAYER_NEW_LAYER]) { layer = await photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument.layers.find(l => l.id == layerId); // deal with multiple images let imageIndexSuffix = ""; @@ -5045,6 +5063,11 @@ function ownKeys(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ SPECIAL_LAYER_NAME_TO_ID: () => (/* binding */ SPECIAL_LAYER_NAME_TO_ID), +/* harmony export */ SPECIAL_LAYER_NEW_LAYER: () => (/* binding */ SPECIAL_LAYER_NEW_LAYER), +/* harmony export */ SPECIAL_LAYER_SAME_AS_LAYER: () => (/* binding */ SPECIAL_LAYER_SAME_AS_LAYER), +/* harmony export */ SPECIAL_LAYER_USE_CANVAS: () => (/* binding */ SPECIAL_LAYER_USE_CANVAS), +/* harmony export */ SPECIAL_LAYER_USE_SELECTION: () => (/* binding */ SPECIAL_LAYER_USE_SELECTION), /* harmony export */ executeAsModalUntilSuccess: () => (/* binding */ executeAsModalUntilSuccess), /* harmony export */ findInAllSubLayer: () => (/* binding */ findInAllSubLayer), /* harmony export */ getAllSubLayer: () => (/* binding */ getAllSubLayer), @@ -5053,6 +5076,16 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var photoshop__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! photoshop */ "photoshop"); /* harmony import */ var photoshop__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(photoshop__WEBPACK_IMPORTED_MODULE_0__); +const SPECIAL_LAYER_USE_CANVAS = '### Use Canvas ###'; +const SPECIAL_LAYER_USE_SELECTION = '### Use Selection ###'; +const SPECIAL_LAYER_NEW_LAYER = '### New Layer ###'; +const SPECIAL_LAYER_SAME_AS_LAYER = '### Same as Layer ###'; +const SPECIAL_LAYER_NAME_TO_ID = { + SPECIAL_LAYER_USE_CANVAS: 0, + SPECIAL_LAYER_USE_SELECTION: -1, + SPECIAL_LAYER_NEW_LAYER: -2, + SPECIAL_LAYER_SAME_AS_LAYER: -3 +}; function unTrimImageData(intersectImageDataArray, toImageDataArray, fromImageBounds, toImageBounds) { const fromLeft = fromImageBounds.left; const fromTop = fromImageBounds.top; @@ -5105,7 +5138,7 @@ function getAllSubLayer(layer, level = 0) { }, []); } function findInAllSubLayer(layer, layerid) { - if (!layer.layers) return null; + if (!layer?.layers) return null; for (let i = 0; i < layer.layers.length; i++) { if (layer.layers[i].id === layerid) return layer.layers[i]; const result = findInAllSubLayer(layer.layers[i], layerid); @@ -5179,6 +5212,9 @@ ___CSS_LOADER_EXPORT___.push([module.id, `.tabbar { #url-bar { width: 100%; } +#user-id-bar { + width: 100%; +} .button-box { width: 100%; display: flex; diff --git a/photoshop/dist/manifest.json b/photoshop/dist/manifest.json index 1fa5114..3025af0 100644 --- a/photoshop/dist/manifest.json +++ b/photoshop/dist/manifest.json @@ -41,19 +41,19 @@ }, "minimumSize": { "width": 300, - "height": 100 + "height": 130 }, "maximumSize": { "width": 400, - "height": 100 + "height": 130 }, "preferredDockedSize": { "width": 300, - "height": 100 + "height": 130 }, "preferredFloatingSize": { "width": 300, - "height": 100 + "height": 130 }, "icons": [ { diff --git a/photoshop/plugin/manifest.json b/photoshop/plugin/manifest.json index 1fa5114..3025af0 100644 --- a/photoshop/plugin/manifest.json +++ b/photoshop/plugin/manifest.json @@ -41,19 +41,19 @@ }, "minimumSize": { "width": 300, - "height": 100 + "height": 130 }, "maximumSize": { "width": 400, - "height": 100 + "height": 130 }, "preferredDockedSize": { "width": 300, - "height": 100 + "height": 130 }, "preferredFloatingSize": { "width": 300, - "height": 100 + "height": 130 }, "icons": [ { diff --git a/photoshop/src/controllers/PanelController.jsx b/photoshop/src/controllers/PanelController.jsx index 0f6adf4..e7e1fcf 100644 --- a/photoshop/src/controllers/PanelController.jsx +++ b/photoshop/src/controllers/PanelController.jsx @@ -30,7 +30,7 @@ export class PanelController { create() { this[_root] = document.createElement("div"); - this[_root].style.height = "100vh"; + this[_root].style.height = "130vh"; this[_root].style.overflow = "auto"; this[_root].style.padding = "8px"; diff --git a/photoshop/src/panels/Main.jsx b/photoshop/src/panels/Main.jsx index c521bcb..2085291 100644 --- a/photoshop/src/panels/Main.jsx +++ b/photoshop/src/panels/Main.jsx @@ -17,6 +17,13 @@ export default class Main extends React.Component { comfyURL: instance ? instance.comfyURL : '' }) }); + storage.secureStorage.getItem('userId').then((value) => { + if (!value) return + this.setState({ userId: Buffer.from(value).toString() }) + if (this.state.userId) { + console.log('userId:', this.state.userId) + } + }) storage.secureStorage.getItem('comfyURL').then((value) => { if (!value) return this.setState({ comfyURL: Buffer.from(value).toString() }) @@ -29,7 +36,7 @@ export default class Main extends React.Component { doConnectOrDisconnect() { if (!ComfyConnection.instance?.isConnected) - ComfyConnection.createInstance(this.state.comfyURL); + ComfyConnection.createInstance(this.state.comfyURL, this.state.userId); else ComfyConnection.instance.disconnect(); } @@ -45,6 +52,19 @@ export default class Main extends React.Component { value={this.state.comfyURL} placeholder="http://127.0.0.1:8188" > + { + this.state.userId = ev.currentTarget.value; + if (!this.state.userId) + storage.secureStorage.removeItem('userId'); + else + storage.secureStorage.setItem('userId', this.state.userId); + }} + value={this.state.userId} + placeholder="User Name: Change if sharing remote server" + >
{ diff --git a/photoshop/src/system/events/get_image.js b/photoshop/src/system/events/get_image.js index 1236546..c19b51f 100644 --- a/photoshop/src/system/events/get_image.js +++ b/photoshop/src/system/events/get_image.js @@ -1,6 +1,7 @@ import { app, imaging } from "photoshop"; import { executeAsModalUntilSuccess, findInAllSubLayer, unTrimImageData } from '../util.js'; import Jimp from "../library/jimp.min"; +import { SPECIAL_LAYER_NAME_TO_ID, SPECIAL_LAYER_USE_SELECTION } from "../util"; function isLayerFolder(layer){ return layer.layers && layer.layers.length > 0; @@ -81,8 +82,8 @@ function getDesiredBounds(boundsLayerID) { width: app.activeDocument.width, height: app.activeDocument.height }; - // if boundsLayerID == -1, use selection bounds - if (boundsLayerID == -1) { + // use selection bounds + if (boundsLayerID == SPECIAL_LAYER_NAME_TO_ID[SPECIAL_LAYER_USE_SELECTION]) { // if no selection use document bounds const selectionBounds = app.activeDocument.selection?.bounds; if (!selectionBounds) return docBounds; @@ -130,7 +131,7 @@ export default async function getImage(comfyURL, params) { const startTime = Date.now(); let layer; let isFolder = false; - const activeLayers = app.activeDocument.activeLayers; + const activeLayers = app.activeDocument?.activeLayers; try { hostControl = executionContext.hostControl; suspensionID = await hostControl.suspendHistory({ diff --git a/photoshop/src/system/events/send_images.js b/photoshop/src/system/events/send_images.js index ad865bb..25901d0 100644 --- a/photoshop/src/system/events/send_images.js +++ b/photoshop/src/system/events/send_images.js @@ -2,16 +2,7 @@ import { app, imaging } from "photoshop"; import { executeAsModalUntilSuccess} from '../util.js'; import Jimp from "../library/jimp.min"; -const SPECIAL_LAYER_USE_CANVAS = '### Use Canvas ###' -const SPECIAL_LAYER_USE_SELECTION = '### Use Selection ###' -const SPECIAL_LAYER_NEW_LAYER = '### New Layer ###' -const SPECIAL_LAYER_SAME_AS_LAYER = '### Same as Layer ###' -const SPECIAL_LAYER_NAME_TO_ID = { - SPECIAL_LAYER_USE_CANVAS: 0, - SPECIAL_LAYER_USE_SELECTION: -1, - SPECIAL_LAYER_NEW_LAYER: -2, - SPECIAL_LAYER_SAME_AS_LAYER: -3 -} +import { SPECIAL_LAYER_NAME_TO_ID, SPECIAL_LAYER_NEW_LAYER } from '../util.js'; function autocrop(jimp) { let minX = jimp.bitmap.width - 1; diff --git a/photoshop/src/system/util.js b/photoshop/src/system/util.js index 7851850..0040a5b 100644 --- a/photoshop/src/system/util.js +++ b/photoshop/src/system/util.js @@ -1,5 +1,16 @@ import { core } from "photoshop"; +export const SPECIAL_LAYER_USE_CANVAS = '### Use Canvas ###' +export const SPECIAL_LAYER_USE_SELECTION = '### Use Selection ###' +export const SPECIAL_LAYER_NEW_LAYER = '### New Layer ###' +export const SPECIAL_LAYER_SAME_AS_LAYER = '### Same as Layer ###' +export const SPECIAL_LAYER_NAME_TO_ID = { + SPECIAL_LAYER_USE_CANVAS: 0, + SPECIAL_LAYER_USE_SELECTION: -1, + SPECIAL_LAYER_NEW_LAYER: -2, + SPECIAL_LAYER_SAME_AS_LAYER: -3 +} + export function unTrimImageData( intersectImageDataArray, toImageDataArray, @@ -68,7 +79,7 @@ export function getAllSubLayer(layer, level = 0) { } export function findInAllSubLayer(layer, layerid) { - if (!layer.layers) return null; + if (!layer?.layers) return null; for (let i = 0; i < layer.layers.length; i++) { if (layer.layers[i].id === layerid) return layer.layers[i]; From 6dc7f1d401a6a671937105dc23f2eb0620a7138b Mon Sep 17 00:00:00 2001 From: CMonk Date: Sun, 12 May 2024 23:43:30 +0800 Subject: [PATCH 2/5] Fix missing info --- comfy/sdppp.py | 7 +++++-- comfy/static/js/sd-ppp.js | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/comfy/sdppp.py b/comfy/sdppp.py index 54bfd76..3edaf9a 100644 --- a/comfy/sdppp.py +++ b/comfy/sdppp.py @@ -57,13 +57,13 @@ class SDPPP: self.photoshop_instances[sid] = await PhotoshopManager.instance().new_ps_instance(self, sid, ip, user_id) elif qsobj['type'] == 'comfyui': - self.comfyui_instances[sid] = True client_id = qsobj.get('client_id', None) if not client_id: client_id = 0 user_id = qsobj.get('user_id', None) if not user_id: user_id = 0 + self.comfyui_instances[sid] = client_id PhotoshopManager.instance().instance_from_client_info(ip, client_id, user_id) else: @@ -91,7 +91,10 @@ class SDPPP: layer_strs = instance.get_base_layers() bounds_strs = instance.get_bounds_layers() set_layer_strs = instance.get_set_layers() - for sid, instance in self.comfyui_instances.items(): + for sid, client_id in self.comfyui_instances.items(): + check_instance = PhotoshopManager.instance().instance_from_client_id(client_id) + if check_instance != instance: + continue await sio.emit('sync_layers', { 'layer_strs': layer_strs, 'bound_strs': bounds_strs, diff --git a/comfy/static/js/sd-ppp.js b/comfy/static/js/sd-ppp.js index 9149264..d1a0aba 100644 --- a/comfy/static/js/sd-ppp.js +++ b/comfy/static/js/sd-ppp.js @@ -52,7 +52,9 @@ app.registerExtension({ path: '/sd-ppp/', query: { version: 1, - type: 'comfyui' + type: 'comfyui', + client_id: api.clientId, + user_id: getUserId(), } }); From d977d59843d118a58e2e748643806100e1c9f515 Mon Sep 17 00:00:00 2001 From: CMonk Date: Mon, 13 May 2024 23:42:40 +0800 Subject: [PATCH 3/5] Fix copy paste error --- photoshop/dist/index.js | 8 ++++---- photoshop/src/system/util.js | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/photoshop/dist/index.js b/photoshop/dist/index.js index 03f2d6a..fffd9b6 100644 --- a/photoshop/dist/index.js +++ b/photoshop/dist/index.js @@ -5081,10 +5081,10 @@ const SPECIAL_LAYER_USE_SELECTION = '### Use Selection ###'; const SPECIAL_LAYER_NEW_LAYER = '### New Layer ###'; const SPECIAL_LAYER_SAME_AS_LAYER = '### Same as Layer ###'; const SPECIAL_LAYER_NAME_TO_ID = { - SPECIAL_LAYER_USE_CANVAS: 0, - SPECIAL_LAYER_USE_SELECTION: -1, - SPECIAL_LAYER_NEW_LAYER: -2, - SPECIAL_LAYER_SAME_AS_LAYER: -3 + [SPECIAL_LAYER_USE_CANVAS]: 0, + [SPECIAL_LAYER_USE_SELECTION]: -1, + [SPECIAL_LAYER_NEW_LAYER]: -2, + [SPECIAL_LAYER_SAME_AS_LAYER]: -3 }; function unTrimImageData(intersectImageDataArray, toImageDataArray, fromImageBounds, toImageBounds) { const fromLeft = fromImageBounds.left; diff --git a/photoshop/src/system/util.js b/photoshop/src/system/util.js index 0040a5b..af13065 100644 --- a/photoshop/src/system/util.js +++ b/photoshop/src/system/util.js @@ -5,10 +5,10 @@ export const SPECIAL_LAYER_USE_SELECTION = '### Use Selection ###' export const SPECIAL_LAYER_NEW_LAYER = '### New Layer ###' export const SPECIAL_LAYER_SAME_AS_LAYER = '### Same as Layer ###' export const SPECIAL_LAYER_NAME_TO_ID = { - SPECIAL_LAYER_USE_CANVAS: 0, - SPECIAL_LAYER_USE_SELECTION: -1, - SPECIAL_LAYER_NEW_LAYER: -2, - SPECIAL_LAYER_SAME_AS_LAYER: -3 + [SPECIAL_LAYER_USE_CANVAS]: 0, + [SPECIAL_LAYER_USE_SELECTION]: -1, + [SPECIAL_LAYER_NEW_LAYER]: -2, + [SPECIAL_LAYER_SAME_AS_LAYER]: -3 } export function unTrimImageData( From ffc4e7e1cd408ccd5a845b9aaa01b9f513bf49b0 Mon Sep 17 00:00:00 2001 From: zombieyang Date: Thu, 16 May 2024 09:43:57 +0800 Subject: [PATCH 4/5] move user-id input into collapse menu --- photoshop/dist/index.js | 93 +++++++++++++++++++++++++++++++--- photoshop/dist/manifest.json | 9 ++-- photoshop/plugin/manifest.json | 9 ++-- photoshop/src/index.jsx | 2 +- photoshop/src/panels/Main.jsx | 54 ++++++++++++++------ photoshop/src/styles.css | 55 ++++++++++++++++++++ 6 files changed, 191 insertions(+), 31 deletions(-) diff --git a/photoshop/dist/index.js b/photoshop/dist/index.js index fffd9b6..ce9813a 100644 --- a/photoshop/dist/index.js +++ b/photoshop/dist/index.js @@ -96,7 +96,9 @@ __webpack_require__.r(__webpack_exports__); class Main extends react__WEBPACK_IMPORTED_MODULE_0__.Component { state = { comfyURL: '', - isConnected: false + isConnected: false, + userId: uxp__WEBPACK_IMPORTED_MODULE_2__.userInfo.userId().slice(0, 10), + ui_ExpandMore: false }; componentDidMount() { _system_ComfyConnection__WEBPACK_IMPORTED_MODULE_1__["default"].onConnectStateChange(() => { @@ -131,6 +133,7 @@ class Main extends react__WEBPACK_IMPORTED_MODULE_0__.Component { if (!_system_ComfyConnection__WEBPACK_IMPORTED_MODULE_1__["default"].instance?.isConnected) _system_ComfyConnection__WEBPACK_IMPORTED_MODULE_1__["default"].createInstance(this.state.comfyURL, this.state.userId);else _system_ComfyConnection__WEBPACK_IMPORTED_MODULE_1__["default"].instance.disconnect(); } render() { + const expandMore = this.state.ui_ExpandMore; return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-textfield", { id: "url-bar", label: "ComfyURL", @@ -139,16 +142,39 @@ class Main extends react__WEBPACK_IMPORTED_MODULE_0__.Component { }, value: this.state.comfyURL, placeholder: "http://127.0.0.1:8188" - }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-textfield", { - id: "user-id-bar", + }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-divider", null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { + id: "connection-more", + className: expandMore ? "expand-menu expand" : "expand-menu collapse" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { + class: "expand-menu-title", + onClick: () => { + this.setState({ + ui_ExpandMore: !expandMore + }); + } + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-label", { + class: "expand-menu-arrow" + }, expandMore ? "▼" : "▶️"), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-label", null, "more")), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { + class: "content" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { + class: "input-row" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-label", null, "user-id:"), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { + class: "input-label", + id: "user-id-bar" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-label", null, this.state.userId), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-textfield", { label: "USER ID", onInput: ev => { - this.state.userId = ev.currentTarget.value; - if (!this.state.userId) uxp__WEBPACK_IMPORTED_MODULE_2__.storage.secureStorage.removeItem('userId');else uxp__WEBPACK_IMPORTED_MODULE_2__.storage.secureStorage.setItem('userId', this.state.userId); + const userID = ev.currentTarget.value; + if (!userID) uxp__WEBPACK_IMPORTED_MODULE_2__.storage.secureStorage.removeItem('userId');else { + uxp__WEBPACK_IMPORTED_MODULE_2__.storage.secureStorage.setItem('userId', this.state.userId); + this.setState({ + userId: userID + }); + } }, value: this.state.userId, placeholder: "User Name: Change if sharing remote server" - }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { + }))))), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "button-box" }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-button", { id: "connect-btn", @@ -5224,6 +5250,61 @@ ___CSS_LOADER_EXPORT___.push([module.id, `.tabbar { } #connect-btn { text-align: center; +} +.input-row { + display: flex; + flex-direction: row; + align-items: center; + height: 30px; +} + +.input-label { + position: relative; +} +.input-label sp-label { + width: calc(100% - 15px); + height: 100%; + margin-left: 15px; +} +.input-label sp-textfield { + position: absolute; + width: 100%; + top: -5px; + left: 0; + visibility: hidden; + z-index: 5; +} +.input-label sp-textfield:focus { + visibility: visible; +} +.input-label:hover sp-textfield{ + visibility: visible; +} +.expand-menu .expand-menu-title { + display: flex; + flex-direction: row; + align-items: center; + height: 20px; + padding: 5px; + background-color: rgba(0, 0, 0, 0.3); +} +.expand-menu .expand-menu-arrow { + font-weight: bold; + width: 15px; +} +.expand-menu .expand-menu-title sp-icon { + height: 15px; + width: 20px; + color: #ccc; +} +.expand-menu .content { + margin-left: 15px +} +.expand-menu.collapse .content { + display: none; +} +.expand-menu.expand .content { + display: flex; }`, ""]); // Exports /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___); diff --git a/photoshop/dist/manifest.json b/photoshop/dist/manifest.json index 3025af0..7e243b8 100644 --- a/photoshop/dist/manifest.json +++ b/photoshop/dist/manifest.json @@ -11,6 +11,7 @@ } ], "requiredPermissions": { + "enableUserInfo": true, "network": { "domains": "all" }, @@ -41,19 +42,19 @@ }, "minimumSize": { "width": 300, - "height": 130 + "height": 160 }, "maximumSize": { "width": 400, - "height": 130 + "height": 160 }, "preferredDockedSize": { "width": 300, - "height": 130 + "height": 160 }, "preferredFloatingSize": { "width": 300, - "height": 130 + "height": 160 }, "icons": [ { diff --git a/photoshop/plugin/manifest.json b/photoshop/plugin/manifest.json index 3025af0..7e243b8 100644 --- a/photoshop/plugin/manifest.json +++ b/photoshop/plugin/manifest.json @@ -11,6 +11,7 @@ } ], "requiredPermissions": { + "enableUserInfo": true, "network": { "domains": "all" }, @@ -41,19 +42,19 @@ }, "minimumSize": { "width": 300, - "height": 130 + "height": 160 }, "maximumSize": { "width": 400, - "height": 130 + "height": 160 }, "preferredDockedSize": { "width": 300, - "height": 130 + "height": 160 }, "preferredFloatingSize": { "width": 300, - "height": 130 + "height": 160 }, "icons": [ { diff --git a/photoshop/src/index.jsx b/photoshop/src/index.jsx index 5582f7a..ac3329e 100644 --- a/photoshop/src/index.jsx +++ b/photoshop/src/index.jsx @@ -6,7 +6,7 @@ import Main from "./panels/Main.jsx"; import { entrypoints } from "uxp"; -const demosController = new PanelController(() =>
, {id: "comfy-connect", menuItems: [ +const demosController = new PanelController(() =>
, {id: "comfy-connect", menuItems: [ // { id: "reload1", label: "Reload Plugin", enabled: true, checked: false, oninvoke: () => location.reload() }, // { id: "dialog1", label: "About this Plugin", enabled: true, checked: false, oninvoke: () => aboutController.run() }, ] }); diff --git a/photoshop/src/panels/Main.jsx b/photoshop/src/panels/Main.jsx index 2085291..9d5cd20 100644 --- a/photoshop/src/panels/Main.jsx +++ b/photoshop/src/panels/Main.jsx @@ -1,11 +1,14 @@ import React from "react"; import ComfyConnection from "../system/ComfyConnection"; -import { storage } from "uxp"; +import { storage, userInfo } from "uxp"; export default class Main extends React.Component { state = { comfyURL: '', - isConnected: false + isConnected: false, + userId: userInfo.userId().slice(0, 10), + + ui_ExpandMore: false, } componentDidMount() { @@ -42,9 +45,9 @@ export default class Main extends React.Component { } render() { + const expandMore = this.state.ui_ExpandMore; return ( <> - - { - this.state.userId = ev.currentTarget.value; - if (!this.state.userId) - storage.secureStorage.removeItem('userId'); - else - storage.secureStorage.setItem('userId', this.state.userId); - }} - value={this.state.userId} - placeholder="User Name: Change if sharing remote server" - > + +
+
{ this.setState({ui_ExpandMore: !expandMore}) }}> + {expandMore ? "▼" : "▶️"} + {/* */} + more +
+
+
+ user-id: +
+ {this.state.userId} + { + const userID = ev.currentTarget.value; + if (!userID) + storage.secureStorage.removeItem('userId'); + else { + storage.secureStorage.setItem('userId', this.state.userId); + this.setState({ + userId: userID + }) + } + }} + value={this.state.userId} + placeholder="User Name: Change if sharing remote server" + > +
+
+
+
Date: Fri, 17 May 2024 08:06:39 +0800 Subject: [PATCH 5/5] some style optimize --- photoshop/dist/index.js | 17 ++++++++--------- photoshop/src/panels/Main.jsx | 10 ++++------ photoshop/src/styles.css | 7 ++++--- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/photoshop/dist/index.js b/photoshop/dist/index.js index ce9813a..60143bc 100644 --- a/photoshop/dist/index.js +++ b/photoshop/dist/index.js @@ -152,15 +152,13 @@ class Main extends react__WEBPACK_IMPORTED_MODULE_0__.Component { ui_ExpandMore: !expandMore }); } - }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-label", { - class: "expand-menu-arrow" - }, expandMore ? "▼" : "▶️"), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-label", null, "more")), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-label", null, expandMore ? "▼ more" : "▶ more")), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { class: "content" }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { - class: "input-row" - }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-label", null, "user-id:"), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { - class: "input-label", + class: "input-row", id: "user-id-bar" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-label", null, "user-name:"), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { + class: "input-label" }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-label", null, this.state.userId), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("sp-textfield", { label: "USER ID", onInput: ev => { @@ -5256,10 +5254,12 @@ ___CSS_LOADER_EXPORT___.push([module.id, `.tabbar { flex-direction: row; align-items: center; height: 30px; + width: 100%; } .input-label { position: relative; + flex: 1; } .input-label sp-label { width: calc(100% - 15px); @@ -5284,13 +5284,12 @@ ___CSS_LOADER_EXPORT___.push([module.id, `.tabbar { display: flex; flex-direction: row; align-items: center; - height: 20px; + height: 15px; padding: 5px; - background-color: rgba(0, 0, 0, 0.3); } .expand-menu .expand-menu-arrow { font-weight: bold; - width: 15px; + text-align: center; } .expand-menu .expand-menu-title sp-icon { height: 15px; diff --git a/photoshop/src/panels/Main.jsx b/photoshop/src/panels/Main.jsx index 9d5cd20..3ba6251 100644 --- a/photoshop/src/panels/Main.jsx +++ b/photoshop/src/panels/Main.jsx @@ -58,14 +58,12 @@ export default class Main extends React.Component {
{ this.setState({ui_ExpandMore: !expandMore}) }}> - {expandMore ? "▼" : "▶️"} - {/* */} - more + {expandMore ? "▼ more" : "▶ more"}
-
- user-id: -
+
+ user-name: +
{this.state.userId}