MVF (functionality) of Git and Login security.
This commit is contained in:
@@ -2,21 +2,38 @@ from git import Repo, InvalidGitRepositoryError
|
||||
import os
|
||||
import copy
|
||||
import re
|
||||
from custom_nodes.EternalKernelLiteGraphNodes.shared import ETK_PATH
|
||||
from custom_nodes.EternalKernelLiteGraphNodes.shared import ETK_PATH, GDE_PATH
|
||||
|
||||
NODE_CLASS_MAPPINGS = {}
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {}
|
||||
|
||||
|
||||
def check_for_js_extension():
|
||||
# here we check to see that the js extension is installed at ../../web/extensions/etk/ui_modifications.js
|
||||
# here we check to see that the js extension is installed at {GDE_PATH}/web/extensions/etk/ui_modifications.js
|
||||
# if it is not, we will copy it there from the ETK_PATH
|
||||
# check if the file exists
|
||||
|
||||
import shutil
|
||||
check_full_path = os.path.normpath(os.path.join(ETK_PATH, "../../web/extensions/etk/ui_modifications.js"))
|
||||
if not os.path.exists(check_full_path):
|
||||
# copy the file
|
||||
shutil.copy(os.path.join(ETK_PATH, "ui_modifications.js"), check_full_path)
|
||||
for fn in ["ui_modifications.js", "ui_helpers.js"]:
|
||||
check_full_path = os.path.normpath(os.path.join(ETK_PATH, f"{GDE_PATH}/web/extensions/etk/{fn}"))
|
||||
# now lets check the modified date of the file
|
||||
|
||||
if os.path.exists(check_full_path):
|
||||
if os.path.getmtime(check_full_path) < os.path.getmtime(os.path.join(ETK_PATH, fn)):
|
||||
# check_target_newer = True
|
||||
should_copy_this_file = True
|
||||
else:
|
||||
# check_target_newer = False
|
||||
should_copy_this_file = False
|
||||
|
||||
else:
|
||||
should_copy_this_file = True
|
||||
|
||||
if should_copy_this_file:
|
||||
print(f"Copying {fn} to {check_full_path}")
|
||||
shutil.copy(os.path.join(ETK_PATH, fn), check_full_path)
|
||||
else:
|
||||
print(f"Skipping {fn} as it is already up to date")
|
||||
|
||||
|
||||
check_for_js_extension()
|
||||
|
||||
+374
-7
@@ -5,24 +5,391 @@ from importlib import reload
|
||||
import logging
|
||||
import os
|
||||
from folder_paths import output_directory, input_directory, temp_directory
|
||||
from custom_nodes.EternalKernelLiteGraphNodes.shared import GDE_PATH
|
||||
import custom_nodes.EternalKernelLiteGraphNodes.shared as shared
|
||||
|
||||
fake_git = None
|
||||
real_git_url = "https://github.com/story-squad/GDE_Graph_IO.git" # is this actually an uri?
|
||||
|
||||
|
||||
class GitIO:
|
||||
def __init__(self, i_real_git_url: str, i_gde_path: str):
|
||||
self.gde_path = i_gde_path
|
||||
self.real_git_io_path = self.setup_git_io(i_real_git_url)
|
||||
|
||||
def setup_git_io(self, l_real_git_url: str):
|
||||
real_git_path = os.path.join(self.gde_path, "data")
|
||||
real_git_path = os.path.join(real_git_path, "GDE_Graph_IO")
|
||||
|
||||
# check to see if it exists and is a git repo, if not then clone it
|
||||
if os.path.exists(real_git_path):
|
||||
# check to see if it is a git repo
|
||||
if os.path.exists(os.path.join(real_git_path, ".git")):
|
||||
print("git io found")
|
||||
else:
|
||||
# not a git repo, delete it and clone it
|
||||
print("git io error, not a git repo")
|
||||
else:
|
||||
# clone it
|
||||
print("git io not found")
|
||||
print("cloning git io repo")
|
||||
os.system("git clone " + l_real_git_url + " " + real_git_path)
|
||||
|
||||
return real_git_path
|
||||
|
||||
def ensure_git_state(self, user: str):
|
||||
"""works in windows or linux, ensures that the git repo is in the correct state"""
|
||||
if not os.path.exists(self.real_git_io_path):
|
||||
raise Exception("git io path not found")
|
||||
if not os.path.exists(os.path.join(self.real_git_io_path, ".git")):
|
||||
raise Exception("git io error, not a git repo")
|
||||
# get the current branch
|
||||
current_branch = os.popen("git branch --show-current").read()
|
||||
# if the current branch is not the user's branch, then switch to it
|
||||
if current_branch != user:
|
||||
# also check if the branch exists, if not then create it
|
||||
branches = os.popen("git branch").read()
|
||||
if user not in branches:
|
||||
os.system("git branch " + user)
|
||||
os.system("git push --set-upstream origin " + user)
|
||||
# switch to the user's branch
|
||||
os.system("git checkout " + user)
|
||||
|
||||
# pull the latest from the user's branch
|
||||
os.system("git pull")
|
||||
|
||||
def git_save_version_1(self, user: str, file_name: str, file_data: str):
|
||||
"""
|
||||
for git save version 1 each user will have their own branch,
|
||||
and the data will be saved to a file in the user's branch
|
||||
version > 1 may include other strategies
|
||||
"""
|
||||
self.ensure_git_state(user)
|
||||
# change to correct directory
|
||||
os.chdir(self.real_git_io_path)
|
||||
# switch to the users branch
|
||||
os.system("git checkout " + user)
|
||||
# save the file data as the file to the disk
|
||||
with open(os.path.join(self.real_git_io_path, file_name), "w", encoding="utf-8") as f:
|
||||
f.write(file_data)
|
||||
# add the file to the git repo
|
||||
os.system("git add " + file_name)
|
||||
# commit the file to the git repo
|
||||
os.system("git commit -m \"saving file " + file_name + "\"")
|
||||
# push the file to the git repo
|
||||
os.system("git push")
|
||||
|
||||
def git_load_version_1(self, user_name, file_name):
|
||||
"""
|
||||
for git load version 1 each user will have their own branch,
|
||||
and the data will be loaded from a file in the user's branch
|
||||
version > 1 may include other strategies
|
||||
"""
|
||||
self.ensure_git_state(user_name)
|
||||
# change to correct directory
|
||||
os.chdir(self.real_git_io_path)
|
||||
# switch to the users branch
|
||||
os.system("git checkout " + user_name)
|
||||
# pull the latest from the user's branch
|
||||
os.system("git pull")
|
||||
# read the file from the disk
|
||||
with open(os.path.join(self.real_git_io_path, file_name), "r", encoding="utf-8") as f:
|
||||
file_data = f.read()
|
||||
return file_data
|
||||
|
||||
|
||||
git_io = GitIO(real_git_url, GDE_PATH)
|
||||
|
||||
user_data = {
|
||||
"user1": {"password": "pass1",
|
||||
"security": None,
|
||||
"client_id": None},
|
||||
"user2": {"password": "pass2",
|
||||
"security": None,
|
||||
"client_id": None},
|
||||
|
||||
}
|
||||
|
||||
|
||||
def get_user_by_client_id(client_id):
|
||||
for user in user_data:
|
||||
if user_data[user]["client_id"] == client_id:
|
||||
return user
|
||||
return None
|
||||
|
||||
|
||||
def get_user_by_security(security):
|
||||
for user in user_data:
|
||||
if user_data[user]["security"] == security:
|
||||
return user
|
||||
return None
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/gde/logout")
|
||||
async def logout(request):
|
||||
"""
|
||||
This function is called when the user logs out
|
||||
"""
|
||||
print("logout request")
|
||||
|
||||
# get the user and pass from the json
|
||||
data = await request.json()
|
||||
client_id = data["client_id"]
|
||||
|
||||
# find the user with the client id
|
||||
user = get_user_by_client_id(client_id)
|
||||
|
||||
if user is None:
|
||||
# use json to send the data back
|
||||
return web.json_response({"error": "invalid client_id"}, status=401)
|
||||
|
||||
# clear the security and client id
|
||||
user_data[user]["security"] = None
|
||||
user_data[user]["client_id"] = None
|
||||
|
||||
# use json to send the data back
|
||||
return web.json_response({"success": True})
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/gde/login")
|
||||
async def login(request):
|
||||
"""
|
||||
This function is called when the attemnpts to log in:
|
||||
- validates login
|
||||
- sets up security
|
||||
- user and pass are in the json
|
||||
"""
|
||||
print("login request")
|
||||
|
||||
# get the user and pass from the json
|
||||
data = await request.json()
|
||||
try:
|
||||
client_id = data["client_id"]
|
||||
except:
|
||||
# this means the client id is not set yet so return logged_in False
|
||||
# use json to send the data back
|
||||
return web.json_response({"logged_in": False})
|
||||
try:
|
||||
user = data["username"]
|
||||
password = data["password"]
|
||||
except:
|
||||
# this means the client is just checking to see if it is already logged into the server
|
||||
# so check
|
||||
user = get_user_by_client_id(client_id)
|
||||
if user is None:
|
||||
# use json to send the data back
|
||||
print("user is none")
|
||||
return web.json_response({"logged_in": False})
|
||||
else:
|
||||
# use json to send the data back
|
||||
print("user is not none")
|
||||
return web.json_response({"logged_in": True})
|
||||
|
||||
# validate the user and pass
|
||||
# for now the users and passes are right here in the code
|
||||
|
||||
if user not in user_data:
|
||||
# use json to send the data back
|
||||
return web.json_response({"error": "invalid user"}, status=401)
|
||||
|
||||
if password != user_data[user]["password"]:
|
||||
# use json to send the data back
|
||||
return web.json_response({"error": "invalid password"}, status=401)
|
||||
|
||||
# if the user and pass are valid, then set up security
|
||||
# for now the security is just a random string that will be sent back to the user
|
||||
# in the future this will be a token that will be used to authenticate the user
|
||||
import uuid
|
||||
security = str(uuid.uuid4())
|
||||
|
||||
# there is no middleware installed
|
||||
# so we will just store the security in memory
|
||||
# this is not secure, but it is good enough for now
|
||||
# store the security in memory
|
||||
user_data[user]["security"] = security
|
||||
user_data[user]["client_id"] = client_id
|
||||
|
||||
# return json with the security
|
||||
return web.json_response({"security": security})
|
||||
|
||||
|
||||
def hijack_prompt_server():
|
||||
"""
|
||||
This function is called by the GDE when it starts up, it hijacks the prompt server
|
||||
for added security.
|
||||
"""
|
||||
# remove the existing prompt route
|
||||
q = [i for i, s in enumerate(PromptServer.instance.routes) if ("/prompt" in str(s))]
|
||||
print(f"found {len(q)} routes to remove: {q}")
|
||||
for adj, i in enumerate(q):
|
||||
route = PromptServer.instance.routes._items.pop(i - adj)
|
||||
|
||||
method = route.method
|
||||
path = route.path
|
||||
kwargs = route.kwargs
|
||||
|
||||
if method == "GET":
|
||||
print(f"removing route {method} {path} {kwargs}")
|
||||
get_handler = route.handler
|
||||
|
||||
@PromptServer.instance.routes.get(path)
|
||||
async def get_prompt(request):
|
||||
print("hijacked prompt get /prompt")
|
||||
print("headers:", request.headers)
|
||||
modified_func_response = await get_handler(request)
|
||||
return modified_func_response
|
||||
|
||||
elif method == "POST":
|
||||
print(f"removing route {method} {path} {kwargs}")
|
||||
post_handler = route.handler
|
||||
|
||||
@PromptServer.instance.routes.post(path)
|
||||
async def post_prompt(request: web.Request):
|
||||
# print("hijacked prompt post /prompt")
|
||||
# print("headers:", request.headers)
|
||||
|
||||
json_data = await request.json()
|
||||
client_id = json_data.get("client_id", None)
|
||||
if client_id is None:
|
||||
print("client_id is None")
|
||||
return web.Response(text="client_id is None", status=400)
|
||||
else:
|
||||
print("client_id:", client_id)
|
||||
# find in users by client_id
|
||||
try:
|
||||
user = get_user_by_client_id(client_id)
|
||||
except KeyError:
|
||||
user = None
|
||||
|
||||
if user is None:
|
||||
print("user not found")
|
||||
return web.json_response({"error": "user not found"}, status=401)
|
||||
else:
|
||||
print(f"minimal security check passed for user {user}")
|
||||
|
||||
modified_func_response: web.Response = await post_handler(request)
|
||||
|
||||
print(modified_func_response.headers)
|
||||
|
||||
return modified_func_response
|
||||
|
||||
# return await post_handler(request)
|
||||
# return post_handler(request)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/gde/git/user_graphs")
|
||||
async def get_user_graphs(request):
|
||||
"""
|
||||
Returns a list of available user graphs (dropdown options).
|
||||
"""
|
||||
import os
|
||||
import subprocess
|
||||
data = await request.json()
|
||||
user = data.get("user", None)
|
||||
|
||||
print("getting user graphs for user:", user)
|
||||
|
||||
# Ensure that the git repo is in the correct state
|
||||
|
||||
# Directory where the user graphs are stored
|
||||
user_graphs_dir = git_io.real_git_io_path
|
||||
|
||||
# Ensure that the git repo is in the correct state
|
||||
git_io.ensure_git_state(user)
|
||||
|
||||
# Check if the branch exists
|
||||
branch_exists = subprocess.call(["git", "rev-parse", "--verify", "--quiet", user])
|
||||
|
||||
# If the branch does not exist, create it
|
||||
if branch_exists != 0:
|
||||
subprocess.call(["git", "checkout", "-b", user])
|
||||
|
||||
# Pull the latest from the user's branch
|
||||
subprocess.call(["git", "pull"])
|
||||
|
||||
# Get the list of user graph files
|
||||
user_graph_files = [f for f in os.listdir(user_graphs_dir) if os.path.isfile(os.path.join(user_graphs_dir, f))]
|
||||
|
||||
# Convert the list of files to the desired format
|
||||
options_data = [{"value": f, "label": f} for f in user_graph_files if f != ""]
|
||||
|
||||
return web.json_response(options_data)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/gde/git/users")
|
||||
async def get_users(request):
|
||||
""" the list of users is just the list of branches in the git repo"""
|
||||
import subprocess
|
||||
print("getting users")
|
||||
|
||||
# Ensure that the git repo is in the correct state
|
||||
git_io.ensure_git_state("main")
|
||||
|
||||
# Change to correct directory
|
||||
os.chdir(git_io.real_git_io_path)
|
||||
|
||||
# Fetch updates from the remote
|
||||
subprocess.call(["git", "fetch", "--prune"])
|
||||
|
||||
# List all remote branches
|
||||
remote_branches_raw = subprocess.check_output(["git", "branch", "-r"]).decode("utf-8").split("\n")
|
||||
remote_branches = [b.replace("origin/", "").strip() for b in remote_branches_raw]
|
||||
|
||||
# List all local branches
|
||||
local_branches_raw = subprocess.check_output(["git", "branch"]).decode("utf-8").split("\n")
|
||||
local_branches = [b.replace("*", "").strip() for b in local_branches_raw]
|
||||
|
||||
# Identify local branches not present in the remote branches
|
||||
branches_to_delete = [b for b in local_branches if b not in remote_branches]
|
||||
|
||||
# Delete these local branches
|
||||
for branch in branches_to_delete:
|
||||
subprocess.call(["git", "branch", "-D", branch])
|
||||
|
||||
# Now, get the updated list of local branches
|
||||
branches = subprocess.check_output(["git", "branch"]).decode("utf-8").split("\n")
|
||||
branches = [b.replace("*", "").strip() for b in branches]
|
||||
|
||||
# Convert the list of branches to the desired format
|
||||
options_data = [{"value": b, "label": b} for b in branches if b != ""]
|
||||
|
||||
return web.json_response(options_data)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/gde/git/save")
|
||||
async def save_to_git(request):
|
||||
"""
|
||||
for git save version 1 each user will have their own branch,
|
||||
and the data will be saved to a file in the user's branch
|
||||
version > 1 may include other strategies
|
||||
"""
|
||||
|
||||
git_save_version = 1
|
||||
req_json = await request.json()
|
||||
print("saving to git")
|
||||
global fake_git
|
||||
fake_git = await request.json()
|
||||
print(fake_git)
|
||||
req_json = await request.json()
|
||||
data = req_json.get("data", None)
|
||||
user_name = req_json.get("user_name", None)
|
||||
file_name = req_json.get("file_name", None)
|
||||
|
||||
git_io.git_save_version_1(user_name, file_name, data)
|
||||
# Implement your actual Git saving logic here
|
||||
return web.Response(text="Saved to Git successfully.")
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/gde/git/load")
|
||||
async def load_from_git(request):
|
||||
"""use git_io to load the file from git"""
|
||||
print("loading from git")
|
||||
global fake_git
|
||||
req_json = await request.json()
|
||||
user_name = req_json.get("user_name", None)
|
||||
file_name = req_json.get("file_name", None)
|
||||
|
||||
# Implement your actual Git loading logic here
|
||||
if fake_git is not None:
|
||||
return web.json_response(fake_git)
|
||||
else:
|
||||
return web.Response(text="No data found.", status=404)
|
||||
file_data = git_io.git_load_version_1(user_name, file_name)
|
||||
return web.json_response({"data": file_data})
|
||||
|
||||
|
||||
if __name__ != 'EternalKernelLiteGraphNodes.server_endpoints':
|
||||
hijack_prompt_server()
|
||||
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
import {app} from "../../../scripts/app.js";
|
||||
import {api} from "../../../scripts/api.js";
|
||||
|
||||
export function setupButtons(menu, app, api) {
|
||||
// Save To Git Button
|
||||
const saveButton = document.createElement("button");
|
||||
saveButton.textContent = "Save To Git";
|
||||
saveButton.onclick = async () => {
|
||||
try {
|
||||
const json = JSON.stringify(app.graph.serialize(), null, 2);
|
||||
const userNameValue = menu.querySelector("#branch-name-field").value;
|
||||
const dropDownSelected = menu.querySelector("#graph-name-field").value;
|
||||
|
||||
await api.fetchApi("/gde/git/save", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
data: json,
|
||||
file_name: dropDownSelected,
|
||||
user_name: userNameValue
|
||||
}),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
menu.append(saveButton);
|
||||
|
||||
// Load From Git Button
|
||||
const loadButton = document.createElement("button");
|
||||
loadButton.textContent = "Load From Git";
|
||||
loadButton.onclick = async () => {
|
||||
try {
|
||||
const response = await api.fetchApi("/gde/git/load", {
|
||||
// needs user_name file_name
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
user_name: menu.querySelector("#branch-name-field").value,
|
||||
file_name: menu.querySelector("#graph-name-field").value
|
||||
}
|
||||
),
|
||||
|
||||
});
|
||||
const data = await response.json();
|
||||
app.loadGraphData(JSON.parse(data.data));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
menu.append(loadButton);
|
||||
}
|
||||
|
||||
|
||||
export function setupModal() {
|
||||
// Modal
|
||||
const modal = document.createElement("div");
|
||||
modal.style.display = "none"; // Initially hidden
|
||||
modal.style.position = "fixed";
|
||||
modal.style.top = "50%";
|
||||
modal.style.left = "50%";
|
||||
modal.style.transform = "translate(-50%, -50%)";
|
||||
modal.style.padding = "20px";
|
||||
modal.style.backgroundColor = "#fff";
|
||||
modal.style.border = "1px solid #000";
|
||||
modal.style.zIndex = "1000"; // Ensure it's on top of other elements
|
||||
document.body.append(modal);
|
||||
|
||||
// Input field inside the modal
|
||||
const modalInput = document.createElement("input");
|
||||
modalInput.type = "text";
|
||||
modalInput.placeholder = "Enter graph name";
|
||||
modal.append(modalInput);
|
||||
|
||||
// Submit button inside the modal
|
||||
const submitButton = document.createElement("button");
|
||||
submitButton.textContent = "Submit";
|
||||
let targetDropdownId = ''; // This will store the ID of the dropdown we're targeting
|
||||
submitButton.onclick = () => {
|
||||
const dropdown = document.querySelector(`#${targetDropdownId}`);
|
||||
const newOption = document.createElement("option");
|
||||
newOption.value = modalInput.value;
|
||||
newOption.textContent = modalInput.value;
|
||||
dropdown.append(newOption);
|
||||
dropdown.value = modalInput.value;
|
||||
console.log("Submitted value:", modalInput.value);
|
||||
modal.style.display = "none"; // Hide the modal
|
||||
};
|
||||
modal.append(submitButton);
|
||||
|
||||
// Function to show the modal (this can be used outside as well)
|
||||
window.showModal = function (dropdownId) {
|
||||
targetDropdownId = dropdownId; // Store the passed dropdown ID
|
||||
modal.style.display = "block";
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function setupDropdown(menu, api, placeholder, apiEndpoint, dropdownId, user = null, graph_name = null, onCreateNew = null) {
|
||||
let dropdown = document.getElementById(dropdownId);
|
||||
|
||||
// If dropdown already exists, clear its options first
|
||||
if (dropdown) {
|
||||
dropdown.innerHTML = '';
|
||||
} else {
|
||||
// Create new dropdown if it doesn't exist
|
||||
dropdown = document.createElement("select");
|
||||
dropdown.style.marginTop = "2px";
|
||||
dropdown.style.width = "100%";
|
||||
dropdown.style.borderRadius = "8px";
|
||||
dropdown.style.fontSize = "18px";
|
||||
dropdown.style.backgroundColor = "#222222";
|
||||
dropdown.style.color = "#EEEEEE";
|
||||
|
||||
dropdown.id = dropdownId;
|
||||
//use comfy-list style
|
||||
|
||||
menu.append(dropdown);
|
||||
}
|
||||
|
||||
// Add default option
|
||||
const defaultOption = document.createElement("option");
|
||||
defaultOption.value = "";
|
||||
defaultOption.textContent = placeholder;
|
||||
dropdown.append(defaultOption);
|
||||
|
||||
// Add "Create New" option
|
||||
const createNewOption = document.createElement("option");
|
||||
createNewOption.value = "create_new";
|
||||
createNewOption.textContent = "Create New";
|
||||
dropdown.append(createNewOption);
|
||||
|
||||
dropdown.addEventListener("change", (event) => {
|
||||
// Check if "Create New" option was selected
|
||||
if (event.target.value === "create_new" && onCreateNew) {
|
||||
onCreateNew(event, dropdown);
|
||||
}
|
||||
|
||||
// Check if branch dropdown is the one being changed
|
||||
if (dropdownId === 'branch-name-field') {
|
||||
while (dropdown.options.length > 2) {
|
||||
dropdown.remove(2);
|
||||
}
|
||||
setTimeout(async () => {
|
||||
await someFunction(dropdownId, api, apiEndpoint, placeholder, user, graph_name)
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(async () => {
|
||||
await someFunction(dropdownId, api, apiEndpoint, placeholder, user, graph_name)
|
||||
})
|
||||
}
|
||||
|
||||
export async function someFunction(dropdownId, api, apiEndpoint, placeholder, user = null, graph_name = null) {
|
||||
try {
|
||||
const dropdown = document.getElementById(dropdownId);
|
||||
dropdown.disabled = true; // Disable the file dropdown
|
||||
|
||||
const queryParams = {
|
||||
user: user || ""
|
||||
};
|
||||
if (graph_name) {
|
||||
queryParams.graph_name = graph_name;
|
||||
}
|
||||
|
||||
const response = await api.fetchApi(apiEndpoint, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(queryParams)
|
||||
});
|
||||
const optionsData = await response.json();
|
||||
optionsData.forEach(optionItem => {
|
||||
const optionElement = document.createElement("option");
|
||||
optionElement.value = optionItem.value;
|
||||
optionElement.textContent = optionItem.label;
|
||||
dropdown.append(optionElement);
|
||||
});
|
||||
|
||||
dropdown.disabled = false; // Enable the file dropdown
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error fetching options for ${placeholder}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
+212
-52
@@ -1,60 +1,220 @@
|
||||
import { app } from "../../../scripts/app.js";
|
||||
import { api } from "../../../scripts/api.js";
|
||||
import {app} from "../../../scripts/app.js";
|
||||
import {api} from "../../../scripts/api.js";
|
||||
import {setupButtons, setupModal, setupDropdown} from './ui_helpers.js';
|
||||
|
||||
// create a place to store some variables, including security_token
|
||||
const gde = {
|
||||
security_token: null,
|
||||
}
|
||||
gde.login_div = document.createElement("div");
|
||||
gde.login_div.id = "gde-login";
|
||||
|
||||
gde.usernameField = document.createElement("input");
|
||||
gde.usernameField.id = "username-field";
|
||||
gde.usernameField.placeholder = "Username";
|
||||
//add a logout button
|
||||
gde.logoutButton = document.createElement("button");
|
||||
gde.logoutButton.id = "logout-button";
|
||||
gde.logoutButton.innerText = "Logout";
|
||||
gde.logoutButton.addEventListener("click", async () => {
|
||||
//clear the token
|
||||
gde.security_token = null;
|
||||
//remove the logout button
|
||||
gde.logoutButton.remove();
|
||||
//add the login button and fields
|
||||
gde.login_div.append(gde.usernameField);
|
||||
gde.login_div.append(gde.passwordField);
|
||||
gde.login_div.append(gde.loginButton);
|
||||
// clear the graph dropdown
|
||||
const graphDropdown = document.getElementById("graph-name-field");
|
||||
if (graphDropdown) {
|
||||
// remove all options without removing the first two
|
||||
while (graphDropdown.options.length > 2) {
|
||||
graphDropdown.remove(2);
|
||||
}
|
||||
}
|
||||
// clear the branch dropdown
|
||||
const branchDropdown = document.getElementById("branch-name-field");
|
||||
if (branchDropdown) {
|
||||
// remove all options without removing the first two
|
||||
while (branchDropdown.options.length > 2) {
|
||||
branchDropdown.remove(2);
|
||||
}
|
||||
}
|
||||
|
||||
// tell the server we logged out
|
||||
await api.fetchApi("/gde/logout", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
client_id: api.clientId,
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
gde.passwordField = document.createElement("input");
|
||||
gde.passwordField.id = "password-field";
|
||||
gde.passwordField.placeholder = "Password";
|
||||
gde.passwordField.type = "password";
|
||||
gde.loginButton = document.createElement("button");
|
||||
gde.loginButton.id = "login-button";
|
||||
gde.loginButton.style.color = "var(--input-text)";
|
||||
gde.loginButton.style.backgroundColor = "var(--comfy-input-bg)";
|
||||
gde.loginButton.style.borderRadius = "8px";
|
||||
gde.loginButton.style.borderColor = "var(--border-color)";
|
||||
gde.loginButton.style.borderStyle = "solid";
|
||||
gde.loginButton.style.marginTop = "2px";
|
||||
gde.loginButton.style.width = "100%";
|
||||
gde.loginButton.innerText = "Login";
|
||||
gde.loginButton.addEventListener("click", async () => {
|
||||
const username = document.getElementById("username-field").value;
|
||||
const password = document.getElementById("password-field").value;
|
||||
const res = await api.fetchApi("/gde/login", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
username: username,
|
||||
password: password,
|
||||
client_id: api.clientId,
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
;
|
||||
if (res.status !== 200) {
|
||||
alert("Login failed");
|
||||
} else {
|
||||
//read the json response, token will be under security
|
||||
const json = await res.json();
|
||||
|
||||
//set the token it is somewhere in the json under security
|
||||
gde.security_token = json.security;
|
||||
|
||||
//now that we are logged in remove the login button and fields
|
||||
gde.usernameField.remove();
|
||||
gde.passwordField.remove();
|
||||
gde.loginButton.remove();
|
||||
|
||||
|
||||
gde.login_div.append(gde.logoutButton);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
gde.get_server_state = async (client_id) => {
|
||||
// check with the server to see if we have a valid client_id
|
||||
const response = await api.fetchApi("/gde/login", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
client_id: client_id,
|
||||
}),
|
||||
});
|
||||
const data = await response.json();
|
||||
return data;
|
||||
}
|
||||
|
||||
// create a dummy function
|
||||
gde.setup_login_form = async () => {
|
||||
const menu = document.querySelector(".comfy-menu");
|
||||
// create a div in the menu for this extension
|
||||
|
||||
|
||||
//need to check with server for the status of our current api.clientId
|
||||
const cid = api.clientId || api.socket.url.split("=")[1];
|
||||
const server_state = await gde.get_server_state(cid).then((server_state) => {
|
||||
const logged_in = server_state.logged_in;
|
||||
|
||||
const separator = document.createElement("hr");
|
||||
separator.style.margin = "20px 0";
|
||||
separator.style.width = "100%";
|
||||
menu.append(separator);
|
||||
menu.append(gde.login_div);
|
||||
|
||||
if (logged_in) {
|
||||
gde.login_div.append(gde.logoutButton);
|
||||
|
||||
} else {
|
||||
gde.login_div.append(gde.usernameField);
|
||||
gde.login_div.append(gde.passwordField);
|
||||
gde.login_div.append(gde.loginButton);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
gde.hijack_queueprompt = async () => {
|
||||
// is this actually needed?
|
||||
}
|
||||
app.registerExtension({
|
||||
name: "GDE.UI.RemoveDefaultButtons",
|
||||
async setup(app) {
|
||||
document.getElementById("comfy-load-default-button").remove();
|
||||
document.getElementById("comfy-clipspace-button").remove();
|
||||
},
|
||||
name: "GDE.UI.RemoveDefaultButtons",
|
||||
async setup(app) {
|
||||
document.getElementById("comfy-load-default-button").remove();
|
||||
document.getElementById("comfy-clipspace-button").remove();
|
||||
},
|
||||
});
|
||||
|
||||
app.registerExtension({
|
||||
name: "GDE.UI",
|
||||
async setup() {
|
||||
const menu = document.querySelector(".comfy-menu");
|
||||
const separator = document.createElement("hr");
|
||||
name: "GDE.UI.Login",
|
||||
async setup() {
|
||||
setTimeout(async () => {
|
||||
await gde.setup_login_form();
|
||||
await gde.hijack_queueprompt();
|
||||
}, 10);
|
||||
}
|
||||
|
||||
separator.style.margin = "20px 0";
|
||||
separator.style.width = "100%";
|
||||
menu.append(separator);
|
||||
|
||||
// Save To Git Button
|
||||
const saveButton = document.createElement("button");
|
||||
saveButton.textContent = "Save To Git";
|
||||
saveButton.onclick = async () => {
|
||||
try {
|
||||
const json = JSON.stringify(app.graph.serialize(), null, 2);
|
||||
await api.fetchApi("/gde/git/save", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ data: json }),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
menu.append(saveButton);
|
||||
});
|
||||
|
||||
// Load From Git Button
|
||||
const loadButton = document.createElement("button");
|
||||
loadButton.textContent = "Load From Git";
|
||||
loadButton.onclick = async () => {
|
||||
try {
|
||||
const response = await api.fetchApi("/gde/git/load", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
});
|
||||
const data = await response.json();
|
||||
app.loadGraphData(JSON.parse(data.data));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
menu.append(loadButton);
|
||||
}
|
||||
});
|
||||
app.registerExtension({
|
||||
name: "GDE.UI.Git",
|
||||
async setup() {
|
||||
setupModal();
|
||||
const separator = document.createElement("hr");
|
||||
const menu = document.querySelector(".comfy-menu");
|
||||
separator.style.margin = "20px 0";
|
||||
separator.style.width = "100%";
|
||||
menu.append(separator);
|
||||
setupButtons(menu, app, api);
|
||||
const handleBranchCreateNew = (event, dropdown) => {
|
||||
// Custom logic for when "Create New" is selected in the branch dropdown
|
||||
showModal('branch-name-field'); // Show the modal for creating a new branch
|
||||
dropdown.value = ""; // Reset the dropdown value
|
||||
// Clear the file dropdown
|
||||
const fileDropdown = document.getElementById("graph-name-field");
|
||||
if (fileDropdown) {
|
||||
// remove all options without removing the first two
|
||||
while (fileDropdown.options.length > 2) {
|
||||
fileDropdown.remove(2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleGraphCreateNew = (event, dropdown) => {
|
||||
// Custom logic for when "Create New" is selected in the branch dropdown
|
||||
showModal('graph-name-field'); // Show the modal for creating a new branch
|
||||
dropdown.value = ""; // Reset the dropdown value
|
||||
// Clear the file dropdown
|
||||
const fileDropdown = document.getElementById("graph-name-field");
|
||||
};
|
||||
|
||||
setupDropdown(menu, api, "Select Branch", "/gde/git/users", "branch-name-field", null, null, handleBranchCreateNew);
|
||||
const branchDropdown = document.getElementById("branch-name-field");
|
||||
|
||||
branchDropdown.addEventListener("change", (event) => {
|
||||
const selectedBranch = event.target.value;
|
||||
if (selectedBranch && selectedBranch !== "Create New") {
|
||||
// Repopulate the file/graph dropdown based on the selected branch
|
||||
setupDropdown(menu, api, "Select Graph", "/gde/git/user_graphs", "graph-name-field", selectedBranch, null, handleGraphCreateNew);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
setupDropdown(menu, api, "Select Graph", "/gde/git/user_graphs", "graph-name-field", null, null, handleGraphCreateNew);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user