merge
This commit is contained in:
		
						commit
						06805e310d
					
				@ -39,14 +39,34 @@ class ComfyUIDeployExternalImageBatch:
 | 
			
		||||
 | 
			
		||||
    CATEGORY = "image"
 | 
			
		||||
    
 | 
			
		||||
    def process_image(self, image):
 | 
			
		||||
        image = ImageOps.exif_transpose(image)
 | 
			
		||||
        image = image.convert("RGB")
 | 
			
		||||
        image = np.array(image).astype(np.float32) / 255.0
 | 
			
		||||
        image_tensor = torch.from_numpy(image)[None,]
 | 
			
		||||
        return image_tensor
 | 
			
		||||
    
 | 
			
		||||
    def run(self, input_id, images=None, default_value=None, display_name=None, description=None):
 | 
			
		||||
        import requests
 | 
			
		||||
        import zipfile
 | 
			
		||||
        import io
 | 
			
		||||
        
 | 
			
		||||
        processed_images = []
 | 
			
		||||
        try:
 | 
			
		||||
            images_list = json.loads(images)  # Assuming images is a JSON array string
 | 
			
		||||
            print(images_list)
 | 
			
		||||
            for img_input in images_list:
 | 
			
		||||
                if img_input.startswith('http'):
 | 
			
		||||
                    import requests
 | 
			
		||||
                if img_input.startswith('http') and img_input.endswith('.zip'):
 | 
			
		||||
                    print("Fetching zip file from url: ", img_input)
 | 
			
		||||
                    response = requests.get(img_input)
 | 
			
		||||
                    zip_file = zipfile.ZipFile(io.BytesIO(response.content))
 | 
			
		||||
                    for file_name in zip_file.namelist():
 | 
			
		||||
                        if file_name.lower().endswith(('.png', '.jpg', '.jpeg')):
 | 
			
		||||
                            with zip_file.open(file_name) as file:
 | 
			
		||||
                                image = Image.open(file)
 | 
			
		||||
                                image = self.process_image(image)
 | 
			
		||||
                                processed_images.append(image)
 | 
			
		||||
                elif  img_input.startswith('http'):
 | 
			
		||||
                    from io import BytesIO
 | 
			
		||||
                    print("Fetching image from url: ", img_input)
 | 
			
		||||
                    response = requests.get(img_input)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										149
									
								
								custom_routes.py
									
									
									
									
									
								
							
							
						
						
									
										149
									
								
								custom_routes.py
									
									
									
									
									
								
							@ -28,30 +28,28 @@ from aiohttp import web, ClientSession, ClientError, ClientTimeout
 | 
			
		||||
import atexit
 | 
			
		||||
 | 
			
		||||
# Global session
 | 
			
		||||
client_session = None
 | 
			
		||||
# client_session = None
 | 
			
		||||
 | 
			
		||||
# def create_client_session():
 | 
			
		||||
#     global client_session
 | 
			
		||||
#     if client_session is None:
 | 
			
		||||
#         client_session = aiohttp.ClientSession()
 | 
			
		||||
 | 
			
		||||
# async def ensure_client_session():
 | 
			
		||||
#     global client_session
 | 
			
		||||
#     if client_session is None:
 | 
			
		||||
#         client_session = aiohttp.ClientSession()
 | 
			
		||||
 | 
			
		||||
async def ensure_client_session():
 | 
			
		||||
    global client_session
 | 
			
		||||
    if client_session is None:
 | 
			
		||||
        client_session = aiohttp.ClientSession()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def cleanup():
 | 
			
		||||
    global client_session
 | 
			
		||||
    if client_session:
 | 
			
		||||
        await client_session.close()
 | 
			
		||||
# async def cleanup():
 | 
			
		||||
#     global client_session
 | 
			
		||||
#     if client_session:
 | 
			
		||||
#         await client_session.close()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def exit_handler():
 | 
			
		||||
    print("Exiting the application. Initiating cleanup...")
 | 
			
		||||
    loop = asyncio.get_event_loop()
 | 
			
		||||
    loop.run_until_complete(cleanup())
 | 
			
		||||
    # loop = asyncio.get_event_loop()
 | 
			
		||||
    # loop.run_until_complete(cleanup())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
atexit.register(exit_handler)
 | 
			
		||||
@ -67,74 +65,77 @@ import time
 | 
			
		||||
async def async_request_with_retry(
 | 
			
		||||
    method, url, disable_timeout=False, token=None, **kwargs
 | 
			
		||||
):
 | 
			
		||||
    global client_session
 | 
			
		||||
    await ensure_client_session()
 | 
			
		||||
    retry_delay = 1  # Start with 1 second delay
 | 
			
		||||
    initial_timeout = 5  # 5 seconds timeout for the initial connection
 | 
			
		||||
    # global client_session
 | 
			
		||||
    # await ensure_client_session()
 | 
			
		||||
    async with aiohttp.ClientSession() as client_session:
 | 
			
		||||
        retry_delay = 1  # Start with 1 second delay
 | 
			
		||||
        initial_timeout = 5  # 5 seconds timeout for the initial connection
 | 
			
		||||
 | 
			
		||||
    start_time = time.time()
 | 
			
		||||
    for attempt in range(max_retries):
 | 
			
		||||
        try:
 | 
			
		||||
            if not disable_timeout:
 | 
			
		||||
                timeout = ClientTimeout(total=None, connect=initial_timeout)
 | 
			
		||||
                kwargs["timeout"] = timeout
 | 
			
		||||
        start_time = time.time()
 | 
			
		||||
        for attempt in range(max_retries):
 | 
			
		||||
            try:
 | 
			
		||||
                if not disable_timeout:
 | 
			
		||||
                    timeout = ClientTimeout(total=None, connect=initial_timeout)
 | 
			
		||||
                    kwargs["timeout"] = timeout
 | 
			
		||||
 | 
			
		||||
            if token is not None:
 | 
			
		||||
                if "headers" not in kwargs:
 | 
			
		||||
                    kwargs["headers"] = {}
 | 
			
		||||
                kwargs["headers"]["Authorization"] = f"Bearer {token}"
 | 
			
		||||
                if token is not None:
 | 
			
		||||
                    if "headers" not in kwargs:
 | 
			
		||||
                        kwargs["headers"] = {}
 | 
			
		||||
                    kwargs["headers"]["Authorization"] = f"Bearer {token}"
 | 
			
		||||
 | 
			
		||||
            request_start = time.time()
 | 
			
		||||
            async with client_session.request(method, url, **kwargs) as response:
 | 
			
		||||
                request_end = time.time()
 | 
			
		||||
                logger.info(
 | 
			
		||||
                    f"Request attempt {attempt + 1} took {request_end - request_start:.2f} seconds"
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                if response.status != 200:
 | 
			
		||||
                    error_body = await response.text()
 | 
			
		||||
                    logger.error(
 | 
			
		||||
                        f"Request failed with status {response.status} and body {error_body}"
 | 
			
		||||
                request_start = time.time()
 | 
			
		||||
                async with client_session.request(method, url, **kwargs) as response:
 | 
			
		||||
                    request_end = time.time()
 | 
			
		||||
                    logger.info(
 | 
			
		||||
                        f"Request attempt {attempt + 1} took {request_end - request_start:.2f} seconds"
 | 
			
		||||
                    )
 | 
			
		||||
                    # raise Exception(f"Request failed with status {response.status}")
 | 
			
		||||
 | 
			
		||||
                response.raise_for_status()
 | 
			
		||||
                if method.upper() == "GET":
 | 
			
		||||
                    await response.read()
 | 
			
		||||
                    if response.status != 200:
 | 
			
		||||
                        error_body = await response.text()
 | 
			
		||||
                        logger.error(
 | 
			
		||||
                            f"Request failed with status {response.status} and body {error_body}"
 | 
			
		||||
                        )
 | 
			
		||||
                        # raise Exception(f"Request failed with status {response.status}")
 | 
			
		||||
 | 
			
		||||
                total_time = time.time() - start_time
 | 
			
		||||
                logger.info(
 | 
			
		||||
                    f"Request succeeded after {total_time:.2f} seconds (attempt {attempt + 1}/{max_retries})"
 | 
			
		||||
                    response.raise_for_status()
 | 
			
		||||
                    if method.upper() == "GET":
 | 
			
		||||
                        await response.read()
 | 
			
		||||
 | 
			
		||||
                    total_time = time.time() - start_time
 | 
			
		||||
                    logger.info(
 | 
			
		||||
                        f"Request succeeded after {total_time:.2f} seconds (attempt {attempt + 1}/{max_retries})"
 | 
			
		||||
                    )
 | 
			
		||||
                    return response
 | 
			
		||||
            except asyncio.TimeoutError:
 | 
			
		||||
                logger.warning(
 | 
			
		||||
                    f"Request timed out after {initial_timeout} seconds (attempt {attempt + 1}/{max_retries})"
 | 
			
		||||
                )
 | 
			
		||||
                return response
 | 
			
		||||
        except asyncio.TimeoutError:
 | 
			
		||||
            logger.warning(
 | 
			
		||||
                f"Request timed out after {initial_timeout} seconds (attempt {attempt + 1}/{max_retries})"
 | 
			
		||||
            )
 | 
			
		||||
        except ClientError as e:
 | 
			
		||||
            end_time = time.time()
 | 
			
		||||
            logger.error(f"Request failed (attempt {attempt + 1}/{max_retries}): {e}")
 | 
			
		||||
            logger.error(
 | 
			
		||||
                f"Time taken for failed attempt: {end_time - request_start:.2f} seconds"
 | 
			
		||||
            )
 | 
			
		||||
            logger.error(f"Total time elapsed: {end_time - start_time:.2f} seconds")
 | 
			
		||||
            except ClientError as e:
 | 
			
		||||
                end_time = time.time()
 | 
			
		||||
                logger.error(
 | 
			
		||||
                    f"Request failed (attempt {attempt + 1}/{max_retries}): {e}"
 | 
			
		||||
                )
 | 
			
		||||
                logger.error(
 | 
			
		||||
                    f"Time taken for failed attempt: {end_time - request_start:.2f} seconds"
 | 
			
		||||
                )
 | 
			
		||||
                logger.error(f"Total time elapsed: {end_time - start_time:.2f} seconds")
 | 
			
		||||
 | 
			
		||||
            # Log the response body for ClientError as well
 | 
			
		||||
            if hasattr(e, "response") and e.response is not None:
 | 
			
		||||
                error_body = await e.response.text()
 | 
			
		||||
                logger.error(f"Error response body: {error_body}")
 | 
			
		||||
                # Log the response body for ClientError as well
 | 
			
		||||
                if hasattr(e, "response") and e.response is not None:
 | 
			
		||||
                    error_body = await e.response.text()
 | 
			
		||||
                    logger.error(f"Error response body: {error_body}")
 | 
			
		||||
 | 
			
		||||
            if attempt == max_retries - 1:
 | 
			
		||||
                logger.error(f"Request failed after {max_retries} attempts: {e}")
 | 
			
		||||
                raise
 | 
			
		||||
                if attempt == max_retries - 1:
 | 
			
		||||
                    logger.error(f"Request failed after {max_retries} attempts: {e}")
 | 
			
		||||
                    raise
 | 
			
		||||
 | 
			
		||||
        await asyncio.sleep(retry_delay)
 | 
			
		||||
        retry_delay *= retry_delay_multiplier
 | 
			
		||||
            await asyncio.sleep(retry_delay)
 | 
			
		||||
            retry_delay *= retry_delay_multiplier
 | 
			
		||||
 | 
			
		||||
    total_time = time.time() - start_time
 | 
			
		||||
    raise Exception(
 | 
			
		||||
        f"Request failed after {max_retries} attempts and {total_time:.2f} seconds"
 | 
			
		||||
    )
 | 
			
		||||
        total_time = time.time() - start_time
 | 
			
		||||
        raise Exception(
 | 
			
		||||
            f"Request failed after {max_retries} attempts and {total_time:.2f} seconds"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from logging import basicConfig, getLogger
 | 
			
		||||
@ -1621,9 +1622,11 @@ async def update_run_with_output(
 | 
			
		||||
        "node_meta": node_meta,
 | 
			
		||||
        "gpu_event_id": gpu_event_id,
 | 
			
		||||
    }
 | 
			
		||||
    have_upload_media = (
 | 
			
		||||
        "images" in data or "files" in data or "gifs" in data or "mesh" in data
 | 
			
		||||
    )
 | 
			
		||||
    have_upload_media = False
 | 
			
		||||
    if data is not None:
 | 
			
		||||
        have_upload_media = (
 | 
			
		||||
            "images" in data or "files" in data or "gifs" in data or "mesh" in data
 | 
			
		||||
        )
 | 
			
		||||
    if bypass_upload and have_upload_media:
 | 
			
		||||
        print(
 | 
			
		||||
            "CD_BYPASS_UPLOAD is enabled, skipping the upload of the output:", node_id
 | 
			
		||||
 | 
			
		||||
@ -192,11 +192,13 @@ const ext = {
 | 
			
		||||
 | 
			
		||||
  registerCustomNodes() {
 | 
			
		||||
    /** @type {LGraphNode}*/
 | 
			
		||||
    class ComfyDeploy {
 | 
			
		||||
      color = LGraphCanvas.node_colors.yellow.color;
 | 
			
		||||
      bgcolor = LGraphCanvas.node_colors.yellow.bgcolor;
 | 
			
		||||
      groupcolor = LGraphCanvas.node_colors.yellow.groupcolor;
 | 
			
		||||
    class ComfyDeploy extends LGraphNode {
 | 
			
		||||
      constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
        this.color = LGraphCanvas.node_colors.yellow.color;
 | 
			
		||||
        this.bgcolor = LGraphCanvas.node_colors.yellow.bgcolor;
 | 
			
		||||
        this.groupcolor = LGraphCanvas.node_colors.yellow.groupcolor;
 | 
			
		||||
 | 
			
		||||
        if (!this.properties) {
 | 
			
		||||
          this.properties = {};
 | 
			
		||||
          this.properties.workflow_name = "";
 | 
			
		||||
@ -204,65 +206,75 @@ const ext = {
 | 
			
		||||
          this.properties.version = "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ComfyWidgets.STRING(
 | 
			
		||||
          this,
 | 
			
		||||
        this.addWidget(
 | 
			
		||||
          "text",
 | 
			
		||||
          "workflow_name",
 | 
			
		||||
          [
 | 
			
		||||
            "",
 | 
			
		||||
            {
 | 
			
		||||
              default: this.properties.workflow_name,
 | 
			
		||||
              multiline: false,
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
          app,
 | 
			
		||||
          this.properties.workflow_name,
 | 
			
		||||
          (v) => {
 | 
			
		||||
            this.properties.workflow_name = v;
 | 
			
		||||
          },
 | 
			
		||||
          { multiline: false }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        ComfyWidgets.STRING(
 | 
			
		||||
          this,
 | 
			
		||||
        this.addWidget(
 | 
			
		||||
          "text",
 | 
			
		||||
          "workflow_id",
 | 
			
		||||
          [
 | 
			
		||||
            "",
 | 
			
		||||
            {
 | 
			
		||||
              default: this.properties.workflow_id,
 | 
			
		||||
              multiline: false,
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
          app,
 | 
			
		||||
          this.properties.workflow_id,
 | 
			
		||||
          (v) => {
 | 
			
		||||
            this.properties.workflow_id = v;
 | 
			
		||||
          },
 | 
			
		||||
          { multiline: false }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        ComfyWidgets.STRING(
 | 
			
		||||
          this,
 | 
			
		||||
        this.addWidget(
 | 
			
		||||
          "text",
 | 
			
		||||
          "version",
 | 
			
		||||
          ["", { default: this.properties.version, multiline: false }],
 | 
			
		||||
          app,
 | 
			
		||||
          this.properties.version,
 | 
			
		||||
          (v) => {
 | 
			
		||||
            this.properties.version = v;
 | 
			
		||||
          },
 | 
			
		||||
          { multiline: false }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // this.widgets.forEach((w) => {
 | 
			
		||||
        //   // w.computeSize = () => [200,10]
 | 
			
		||||
        //   w.computedHeight = 2;
 | 
			
		||||
        // })
 | 
			
		||||
 | 
			
		||||
        this.widgets_start_y = 10;
 | 
			
		||||
        this.setSize(this.computeSize());
 | 
			
		||||
 | 
			
		||||
        // const config = {  };
 | 
			
		||||
 | 
			
		||||
        // console.log(this);
 | 
			
		||||
        this.serialize_widgets = true;
 | 
			
		||||
        this.isVirtualNode = true;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      onExecute() {
 | 
			
		||||
        // This method is called when the node is executed
 | 
			
		||||
        // You can add any necessary logic here
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      onSerialize(o) {
 | 
			
		||||
        // This method is called when the node is being serialized
 | 
			
		||||
        // Ensure all necessary data is saved
 | 
			
		||||
        if (!o.properties) {
 | 
			
		||||
          o.properties = {};
 | 
			
		||||
        }
 | 
			
		||||
        o.properties.workflow_name = this.properties.workflow_name;
 | 
			
		||||
        o.properties.workflow_id = this.properties.workflow_id;
 | 
			
		||||
        o.properties.version = this.properties.version;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      onConfigure(o) {
 | 
			
		||||
        // This method is called when the node is being configured (e.g., when loading a saved graph)
 | 
			
		||||
        // Ensure all necessary data is restored
 | 
			
		||||
        if (o.properties) {
 | 
			
		||||
          this.properties = { ...this.properties, ...o.properties };
 | 
			
		||||
          this.widgets[0].value = this.properties.workflow_name || "";
 | 
			
		||||
          this.widgets[1].value = this.properties.workflow_id || "";
 | 
			
		||||
          this.widgets[2].value = this.properties.version || "1";
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Load default visibility
 | 
			
		||||
 | 
			
		||||
    LiteGraph.registerNodeType(
 | 
			
		||||
      "ComfyDeploy",
 | 
			
		||||
      Object.assign(ComfyDeploy, {
 | 
			
		||||
        title_mode: LiteGraph.NORMAL_TITLE,
 | 
			
		||||
        title: "Comfy Deploy",
 | 
			
		||||
        collapsable: true,
 | 
			
		||||
      }),
 | 
			
		||||
    );
 | 
			
		||||
    // Register the node type
 | 
			
		||||
    LiteGraph.registerNodeType("ComfyDeploy", Object.assign(ComfyDeploy, {
 | 
			
		||||
      title: "Comfy Deploy",
 | 
			
		||||
      title_mode: LiteGraph.NORMAL_TITLE,
 | 
			
		||||
      collapsable: true,
 | 
			
		||||
    }));
 | 
			
		||||
 | 
			
		||||
    ComfyDeploy.category = "deploy";
 | 
			
		||||
  },
 | 
			
		||||
@ -431,10 +443,10 @@ function createDynamicUIHtml(data) {
 | 
			
		||||
          <h3 style="font-size: 14px; font-weight: semibold; margin-bottom: 8px;">Missing Nodes</h3>
 | 
			
		||||
          <p style="font-size: 12px;">These nodes are not found with any matching custom_nodes in the ComfyUI Manager Database</p>
 | 
			
		||||
          ${data.missing_nodes
 | 
			
		||||
            .map((node) => {
 | 
			
		||||
              return `<p style="font-size: 14px; color: #d69e2e;">${node}</p>`;
 | 
			
		||||
            })
 | 
			
		||||
            .join("")}
 | 
			
		||||
        .map((node) => {
 | 
			
		||||
          return `<p style="font-size: 14px; color: #d69e2e;">${node}</p>`;
 | 
			
		||||
        })
 | 
			
		||||
        .join("")}
 | 
			
		||||
      </div>
 | 
			
		||||
  `;
 | 
			
		||||
  }
 | 
			
		||||
@ -442,17 +454,14 @@ function createDynamicUIHtml(data) {
 | 
			
		||||
  Object.values(data.custom_nodes).forEach((node) => {
 | 
			
		||||
    html += `
 | 
			
		||||
          <div style="border-bottom: 1px solid #e2e8f0; padding-top: 16px;">
 | 
			
		||||
              <a href="${
 | 
			
		||||
                node.url
 | 
			
		||||
              }" target="_blank" style="font-size: 18px; font-weight: semibold; color: white; text-decoration: none;">${
 | 
			
		||||
                node.name
 | 
			
		||||
              }</a>
 | 
			
		||||
              <a href="${node.url
 | 
			
		||||
      }" target="_blank" style="font-size: 18px; font-weight: semibold; color: white; text-decoration: none;">${node.name
 | 
			
		||||
      }</a>
 | 
			
		||||
              <p style="font-size: 14px; color: #4b5563;">${node.hash}</p>
 | 
			
		||||
              ${
 | 
			
		||||
                node.warning
 | 
			
		||||
                  ? `<p style="font-size: 14px; color: #d69e2e;">${node.warning}</p>`
 | 
			
		||||
                  : ""
 | 
			
		||||
              }
 | 
			
		||||
              ${node.warning
 | 
			
		||||
        ? `<p style="font-size: 14px; color: #d69e2e;">${node.warning}</p>`
 | 
			
		||||
        : ""
 | 
			
		||||
      }
 | 
			
		||||
          </div>
 | 
			
		||||
      `;
 | 
			
		||||
  });
 | 
			
		||||
@ -466,9 +475,8 @@ function createDynamicUIHtml(data) {
 | 
			
		||||
  Object.entries(data.models).forEach(([section, items]) => {
 | 
			
		||||
    html += `
 | 
			
		||||
    <div style="border-bottom: 1px solid #e2e8f0; padding-top: 8px; padding-bottom: 8px;">
 | 
			
		||||
        <h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${
 | 
			
		||||
          section.charAt(0).toUpperCase() + section.slice(1)
 | 
			
		||||
        }</h3>`;
 | 
			
		||||
        <h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${section.charAt(0).toUpperCase() + section.slice(1)
 | 
			
		||||
      }</h3>`;
 | 
			
		||||
    items.forEach((item) => {
 | 
			
		||||
      html += `<p style="font-size: 14px; color: ${textColor};">${item.name}</p>`;
 | 
			
		||||
    });
 | 
			
		||||
@ -484,9 +492,8 @@ function createDynamicUIHtml(data) {
 | 
			
		||||
  Object.entries(data.files).forEach(([section, items]) => {
 | 
			
		||||
    html += `
 | 
			
		||||
    <div style="border-bottom: 1px solid #e2e8f0; padding-top: 8px; padding-bottom: 8px;">
 | 
			
		||||
        <h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${
 | 
			
		||||
          section.charAt(0).toUpperCase() + section.slice(1)
 | 
			
		||||
        }</h3>`;
 | 
			
		||||
        <h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${section.charAt(0).toUpperCase() + section.slice(1)
 | 
			
		||||
      }</h3>`;
 | 
			
		||||
    items.forEach((item) => {
 | 
			
		||||
      html += `<p style="font-size: 14px; color: ${textColor};">${item.name}</p>`;
 | 
			
		||||
    });
 | 
			
		||||
@ -1006,14 +1013,12 @@ export class LoadingDialog extends ComfyDialog {
 | 
			
		||||
  showLoading(title, message) {
 | 
			
		||||
    this.show(`
 | 
			
		||||
      <div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
 | 
			
		||||
        <h3 style="margin: 0px; display: flex; align-items: center; justify-content: center; gap: 12px;">${title} ${
 | 
			
		||||
          this.loadingIcon
 | 
			
		||||
        }</h3>
 | 
			
		||||
          ${
 | 
			
		||||
            message
 | 
			
		||||
              ? `<label style="max-width: 100%; white-space: pre-wrap; word-wrap: break-word;">${message}</label>`
 | 
			
		||||
              : ""
 | 
			
		||||
          }
 | 
			
		||||
        <h3 style="margin: 0px; display: flex; align-items: center; justify-content: center; gap: 12px;">${title} ${this.loadingIcon
 | 
			
		||||
      }</h3>
 | 
			
		||||
          ${message
 | 
			
		||||
        ? `<label style="max-width: 100%; white-space: pre-wrap; word-wrap: break-word;">${message}</label>`
 | 
			
		||||
        : ""
 | 
			
		||||
      }
 | 
			
		||||
        </div>
 | 
			
		||||
      `);
 | 
			
		||||
  }
 | 
			
		||||
@ -1279,21 +1284,17 @@ export class ConfigDialog extends ComfyDialog {
 | 
			
		||||
    </label>
 | 
			
		||||
      <label style="color: white; width: 100%;">
 | 
			
		||||
        Endpoint:
 | 
			
		||||
        <input id="endpoint" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="text" value="${
 | 
			
		||||
          data.endpoint
 | 
			
		||||
        }">
 | 
			
		||||
        <input id="endpoint" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="text" value="${data.endpoint
 | 
			
		||||
      }">
 | 
			
		||||
      </label>
 | 
			
		||||
      <div style="color: white;">
 | 
			
		||||
        API Key: User / Org <button style="font-size: 18px;">${
 | 
			
		||||
          data.displayName ?? ""
 | 
			
		||||
        }</button>
 | 
			
		||||
        <input id="apiKey" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="password" value="${
 | 
			
		||||
          data.apiKey
 | 
			
		||||
        }">
 | 
			
		||||
        API Key: User / Org <button style="font-size: 18px;">${data.displayName ?? ""
 | 
			
		||||
      }</button>
 | 
			
		||||
        <input id="apiKey" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="password" value="${data.apiKey
 | 
			
		||||
      }">
 | 
			
		||||
        <button id="loginButton" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;">
 | 
			
		||||
          ${
 | 
			
		||||
            data.apiKey ? "Re-login with ComfyDeploy" : "Login with ComfyDeploy"
 | 
			
		||||
          }
 | 
			
		||||
          ${data.apiKey ? "Re-login with ComfyDeploy" : "Login with ComfyDeploy"
 | 
			
		||||
      }
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user