Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add folder selection functionality for model directories. #74

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion server.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from flask import Response, stream_with_context
from waitress import serve
import webbrowser
from tkinter import filedialog, Tk
import tkinter as tk

import torch

Expand Down Expand Up @@ -272,6 +274,20 @@ def api_delete_session():
if verbose: print("->", result)
return json.dumps(result) + "\n"

@app.route("/api/select_folder")
def api_select_folder():
global api_lock, verbose
if verbose: print("/api/select_folder")
with api_lock:
root = Tk()
root.withdraw() # Hide the main window
root.attributes('-topmost', True) # Make sure dialog appears on top
folder = filedialog.askdirectory()
root.destroy()
result = {"result": "ok", "path": folder if folder else ""}
if verbose: print("->", result)
return json.dumps(result) + "\n"

@app.route("/api/remove_model", methods=['POST'])
def api_remove_model():
global api_lock, verbose
Expand Down Expand Up @@ -467,4 +483,3 @@ def api_cancel_notepad_generate():
print(f" -- Opening UI in default web browser")

serve(app, host = host, port = port, threads = 8)

2 changes: 1 addition & 1 deletion static/controls.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

.vflex_line {
height-min: 32px;
min-height: 32px;
}

.checkbox {
Expand Down
35 changes: 35 additions & 0 deletions static/controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,28 @@ export class LabelTextbox {
if (placeholder) this.tb.placeholder = placeholder;
this.tb.spellcheck = false;
this.tb.value = this.data[this.data_id] ? this.data[this.data_id] : "";

// Create hidden span to measure text width
this.measureSpan = document.createElement("span");
this.measureSpan.style.visibility = "hidden";
this.measureSpan.style.position = "absolute";
this.measureSpan.style.whiteSpace = "pre";
// Copy font styles from input to span for accurate measurement
this.measureSpan.style.font = window.getComputedStyle(this.tb).font;
document.body.appendChild(this.measureSpan);

// Function to update input width based on content
const updateWidth = () => {
this.measureSpan.textContent = this.tb.value || this.tb.placeholder;
const width = this.measureSpan.offsetWidth;
this.tb.style.width = (width + 20) + 'px'; // Add padding
};

// Update width on input
this.tb.addEventListener("input", updateWidth);

// Initial width update
updateWidth();

this.tb.addEventListener("focus", () => {
//console.log(this.data[this.data_id]);
Expand Down Expand Up @@ -98,6 +120,10 @@ export class LabelTextbox {
refresh() {
let v = this.data[this.data_id] ? this.data[this.data_id] : null;
this.tb.value = v;
// Update width when refreshing
this.measureSpan.textContent = this.tb.value || this.tb.placeholder;
const width = this.measureSpan.offsetWidth;
this.tb.style.width = (width + 20) + 'px';
this.refreshCB();
}

Expand Down Expand Up @@ -249,6 +275,10 @@ export class LabelNumbox extends LabelTextbox {
this.min = min;
this.max = max;
this.decimals = decimals;

// Override dynamic width calculation for numeric inputs
this.measureSpan = null; // Remove the span used for width measurement
this.tb.style.width = null; // Remove any inline width style
}

interpret(value) {
Expand All @@ -263,6 +293,11 @@ export class LabelNumbox extends LabelTextbox {
refresh() {
this.tb.value = this.data[this.data_id].toFixed(this.decimals);
this.refreshCB();
// Override parent's refresh method to prevent dynamic width calculation
if (this.measureSpan) {
document.body.removeChild(this.measureSpan);
this.measureSpan = null;
}
}
}

Expand Down
40 changes: 35 additions & 5 deletions static/models.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
padding: 20px;
height: calc(100vh - 40px);
overflow-y: auto;
flex-grow: 1;
}

.model-view-text {
Expand Down Expand Up @@ -138,8 +137,42 @@
color: var(--textcolor-dim);
}

.model-view-item-textbox.wide {
.folder-button {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
padding: 4px;
margin-right: 8px;
border-radius: 4px;
}

.folder-button:hover {
background-color: var(--background-color-active);
}

.folder-button:hover svg {
filter: brightness(1.3);
}

.folder-button svg {
width: 24px;
height: 24px;
fill: var(--textcolor-head);
}

.model-directory-container {
display: flex;
align-items: center;
flex-grow: 1;
min-width: 0; /* Allow container to shrink below content size */
overflow: hidden; /* Prevent overflow */
}

.model-view-item-textbox.wide {
flex: 0 1 auto; /* Allow textbox to shrink */
min-width: 100px; /* Minimum width */
max-width: calc(100% - 40px); /* Maximum width accounting for folder icon */
}

.model-view-item-textbox.shortright {
Expand Down Expand Up @@ -181,6 +214,3 @@
flex-grow: 1;
justify-content: end;
}



77 changes: 74 additions & 3 deletions static/models.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,48 @@ export class ModelView {
this.element.appendChild(util.newDiv(null, "model-view-text divider", ""));
this.element.appendChild(util.newDiv(null, "model-view-text spacer", ""));

this.tb_model_directory = new controls.LabelTextbox("model-view-item-left", "Model directory", "model-view-item-textbox wide", "~/models/my_model/", this.modelInfo, "model_directory", null, () => { this.send() } );
this.element.appendChild(this.tb_model_directory.element);
// Create container for model directory input and folder button
let modelDirContainer = util.newDiv(null, "model-directory-container");
this.element.appendChild(modelDirContainer);

// Function to normalize path separators based on platform
const normalizePath = (path) => {
const isWindows = navigator.platform.toLowerCase().includes('win');
if (isWindows) {
return path.replace(/\//g, '\\');
}
return path;
};

// Create a function to handle folder selection
const selectFolder = async () => {
try {
const response = await fetch("/api/select_folder");
const data = await response.json();
if (data.result === "ok" && data.path) {
// Update the model directory textbox with the selected path
this.modelInfo.model_directory = normalizePath(data.path);
this.tb_model_directory.refresh();
this.send();
}
} catch (err) {
console.log('Folder selection error:', err);
}
};

// Create model directory textbox
this.tb_model_directory = new controls.LabelTextbox("model-view-item-left", "Model directory", "model-view-item-textbox wide", "~/models/my_model/", this.modelInfo, "model_directory", null, () => { this.send() } );
modelDirContainer.appendChild(this.tb_model_directory.label);

// Create folder button
let folderButton = util.newDiv(null, "folder-button");
folderButton.appendChild(util.newIcon("folder-icon"));
folderButton.addEventListener("click", () => {
selectFolder();
});
modelDirContainer.appendChild(folderButton);

modelDirContainer.appendChild(this.tb_model_directory.tb);

this.element_model = util.newHFlex();
this.element_model_error = util.newHFlex();
Expand Down Expand Up @@ -380,8 +420,39 @@ export class ModelView {
//this.element_model.appendChild(util.newDiv(null, "model-view-text spacer", ""));
this.element_draft_model.appendChild(util.newDiv(null, "model-view-text spacer", ""));

// Create container for draft model directory input and folder button
let draftModelDirContainer = util.newDiv(null, "model-directory-container");
this.element_draft_model.appendChild(draftModelDirContainer);

// Create a function to handle draft folder selection
const selectDraftFolder = async () => {
try {
const response = await fetch("/api/select_folder");
const data = await response.json();
if (data.result === "ok" && data.path) {
// Update the draft model directory textbox with the selected path
this.modelInfo.draft_model_directory = normalizePath(data.path);
this.tb_draft_model_directory.refresh();
this.send();
}
} catch (err) {
console.log('Folder selection error:', err);
}
};

// Create draft model directory textbox
this.tb_draft_model_directory = new controls.LabelTextbox("model-view-item-left", "Draft model directory", "model-view-item-textbox wide", "~/models/my_draft_model/", this.modelInfo, "draft_model_directory", null, () => { this.send() } );
this.element_draft_model.appendChild(this.tb_draft_model_directory.element);
draftModelDirContainer.appendChild(this.tb_draft_model_directory.label);

// Create folder button
let draftFolderButton = util.newDiv(null, "folder-button");
draftFolderButton.appendChild(util.newIcon("folder-icon"));
draftFolderButton.addEventListener("click", () => {
selectDraftFolder();
});
draftModelDirContainer.appendChild(draftFolderButton);

draftModelDirContainer.appendChild(this.tb_draft_model_directory.tb);

this.element_draft_model_s = util.newHFlex();
this.element_draft_model_error = util.newHFlex();
Expand Down
8 changes: 8 additions & 0 deletions templates/svg_icons.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@
</defs>
</svg>

<svg style="display: none;">
<defs>
<symbol id="folder-icon" viewBox="0 0 24 24">
<path d="M20 5h-8.5L9.8 3.3c-.1-.1-.3-.3-.5-.3H4c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 14H4V7h16v12z"/>
</symbol>
</defs>
</svg>

<svg style="display: none;">
<defs>
<symbol id="notepad-icon" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24">
Expand Down