|
1 |
| -from .utils import here, run_command, comfy_mode |
| 1 | +from .utils import ( |
| 2 | + here, |
| 3 | + import_install, |
| 4 | + styles_dir, |
| 5 | + backup_file, |
| 6 | +) |
2 | 7 | from aiohttp import web
|
3 | 8 | from .log import mklog
|
4 |
| -import sys |
| 9 | +import csv |
| 10 | + |
5 | 11 |
|
6 | 12 | endlog = mklog("mtb endpoint")
|
7 | 13 |
|
8 | 14 | # - ACTIONS
|
9 |
| -import requirements |
| 15 | +import platform |
10 | 16 |
|
| 17 | +import_install("requirements") |
11 | 18 |
|
12 | 19 |
|
13 | 20 | def ACTIONS_installDependency(dependency_names=None):
|
14 | 21 | if dependency_names is None:
|
15 | 22 | return {"error": "No dependency name provided"}
|
16 | 23 | endlog.debug(f"Received Install Dependency request for {dependency_names}")
|
17 | 24 | reqs = []
|
18 |
| - if comfy_mode == "embeded": |
19 |
| - reqs = list(requirements.parse((here / "reqs_portable.txt").read_text())) |
| 25 | + if platform.system() == "Windows": |
| 26 | + reqs = list(requirements.parse((here / "reqs_windows.txt").read_text())) |
20 | 27 | else:
|
21 | 28 | reqs = list(requirements.parse((here / "reqs.txt").read_text()))
|
22 | 29 | print([x.specs for x in reqs])
|
@@ -48,6 +55,32 @@ def ACTIONS_getStyles(style_name=None):
|
48 | 55 | return {"error": "No styles found"}
|
49 | 56 |
|
50 | 57 |
|
| 58 | +def ACTIONS_saveStyle(data): |
| 59 | + # endlog.debug(f"Received Save Styles for {data.keys()}") |
| 60 | + # endlog.debug(data) |
| 61 | + |
| 62 | + styles = [f.name for f in styles_dir.iterdir() if f.suffix == ".csv"] |
| 63 | + target = None |
| 64 | + rows = [] |
| 65 | + for fp, content in data.items(): |
| 66 | + if fp in styles: |
| 67 | + endlog.debug(f"Overwriting {fp}") |
| 68 | + target = styles_dir / fp |
| 69 | + rows = content |
| 70 | + break |
| 71 | + |
| 72 | + if not target: |
| 73 | + endlog.warning(f"Could not determine the target file for {data.keys()}") |
| 74 | + return {"error": "Could not determine the target file for the style"} |
| 75 | + |
| 76 | + backup_file(target) |
| 77 | + |
| 78 | + with target.open("w", newline="", encoding="utf-8") as file: |
| 79 | + csv_writer = csv.writer(file, quoting=csv.QUOTE_ALL) |
| 80 | + for row in rows: |
| 81 | + csv_writer.writerow(row) |
| 82 | + |
| 83 | + |
51 | 84 | async def do_action(request) -> web.Response:
|
52 | 85 | endlog.debug("Init action request")
|
53 | 86 | request_data = await request.json()
|
@@ -83,6 +116,129 @@ def dependencies_button(name, dependencies):
|
83 | 116 | """
|
84 | 117 |
|
85 | 118 |
|
| 119 | +def csv_editor(): |
| 120 | + inputs = [f for f in styles_dir.iterdir() if f.suffix == ".csv"] |
| 121 | + # rows = {f.stem: list(csv.reader(f.read_text("utf8"))) for f in styles} |
| 122 | + |
| 123 | + style_files = {} |
| 124 | + for file in inputs: |
| 125 | + with open(file, "r", encoding="utf8") as f: |
| 126 | + parsed = csv.reader(f) |
| 127 | + style_files[file.name] = [] |
| 128 | + for row in parsed: |
| 129 | + endlog.debug(f"Adding style {row[0]}") |
| 130 | + style_files[file.name].append((row[0], row[1], row[2])) |
| 131 | + |
| 132 | + html_out = """ |
| 133 | + <div id="style-editor"> |
| 134 | + <h1>Style Editor</h1> |
| 135 | + |
| 136 | + """ |
| 137 | + for current, styles in style_files.items(): |
| 138 | + current_out = f"<h3>{current}</h3>" |
| 139 | + table_rows = [] |
| 140 | + for index, style in enumerate(styles): |
| 141 | + table_rows += ( |
| 142 | + (["<tr>"] + [f"<th>{cell}</th>" for cell in style] + ["</tr>"]) |
| 143 | + if index == 0 |
| 144 | + else ( |
| 145 | + ["<tr>"] |
| 146 | + + [ |
| 147 | + f"<td><input type='text' value='{cell}'></td>" |
| 148 | + if i == 0 |
| 149 | + else f"<td><textarea name='Text1' cols='40' rows='5'>{cell}</textarea></td>" |
| 150 | + for i, cell in enumerate(style) |
| 151 | + ] |
| 152 | + + ["</tr>"] |
| 153 | + ) |
| 154 | + ) |
| 155 | + current_out += ( |
| 156 | + f"<table data-id='{current}' data-filename='{current}'>" |
| 157 | + + "".join(table_rows) |
| 158 | + + "</table>" |
| 159 | + ) |
| 160 | + current_out += f"<button data-id='{current}' onclick='saveTableData(this.getAttribute(\"data-id\"))'>Save {current}</button>" |
| 161 | + |
| 162 | + html_out += add_foldable_region(current, current_out) |
| 163 | + |
| 164 | + html_out += "</div>" |
| 165 | + html_out += """<script src='/mtb-assets/js/saveTableData.js'></script>""" |
| 166 | + |
| 167 | + return html_out |
| 168 | + |
| 169 | + |
| 170 | +def render_tab_view(**kwargs): |
| 171 | + tab_headers = [] |
| 172 | + tab_contents = [] |
| 173 | + |
| 174 | + for idx, (tab_name, content) in enumerate(kwargs.items()): |
| 175 | + active_class = "active" if idx == 0 else "" |
| 176 | + tab_headers.append( |
| 177 | + f"<button class='tablinks {active_class}' onclick=\"openTab(event, '{tab_name}')\">{tab_name}</button>" |
| 178 | + ) |
| 179 | + tab_contents.append( |
| 180 | + f"<div id='{tab_name}' class='tabcontent {active_class}'>{content}</div>" |
| 181 | + ) |
| 182 | + |
| 183 | + headers_str = "\n".join(tab_headers) |
| 184 | + contents_str = "\n".join(tab_contents) |
| 185 | + |
| 186 | + return f""" |
| 187 | +<div class='tab-container'> |
| 188 | + <div class='tab'> |
| 189 | + {headers_str} |
| 190 | + </div> |
| 191 | + {contents_str} |
| 192 | + </div> |
| 193 | + <script src='/mtb-assets/js/tabSwitch.js'></script> |
| 194 | + """ |
| 195 | + |
| 196 | + |
| 197 | +def add_foldable_region(title, content): |
| 198 | + symbol_id = f"{title}-symbol" |
| 199 | + return f""" |
| 200 | + <div class='foldable'> |
| 201 | + <div class='foldable-title' onclick="toggleFoldable('{title}', '{symbol_id}')"> |
| 202 | + <span id='{symbol_id}' class='foldable-symbol'>▷</span> |
| 203 | + {title} |
| 204 | + </div> |
| 205 | + <div id='{title}' class='foldable-content'> |
| 206 | + {content} |
| 207 | + </div> |
| 208 | + </div> |
| 209 | + <script src='/mtb-assets/js/foldable.js'></script> |
| 210 | + """ |
| 211 | + |
| 212 | + |
| 213 | +def add_split_pane(left_content, right_content, vertical=True): |
| 214 | + orientation = "vertical" if vertical else "horizontal" |
| 215 | + return f""" |
| 216 | + <div class="split-pane {orientation}"> |
| 217 | + <div id="leftPane"> |
| 218 | + {left_content} |
| 219 | + </div> |
| 220 | + <div id="resizer"></div> |
| 221 | + <div id="rightPane"> |
| 222 | + {right_content} |
| 223 | + </div> |
| 224 | + </div> |
| 225 | + <script> |
| 226 | + initSplitPane({str(vertical).lower()}); |
| 227 | + </script> |
| 228 | + <script src='/mtb-assets/js/splitPane.js'></script> |
| 229 | + """ |
| 230 | + |
| 231 | + |
| 232 | +def add_dropdown(title, options): |
| 233 | + option_str = "\n".join([f"<option value='{opt}'>{opt}</option>" for opt in options]) |
| 234 | + return f""" |
| 235 | + <select> |
| 236 | + <option disabled selected>{title}</option> |
| 237 | + {option_str} |
| 238 | + </select> |
| 239 | + """ |
| 240 | + |
| 241 | + |
86 | 242 | def render_table(table_dict, sort=True, title=None):
|
87 | 243 | table_dict = sorted(
|
88 | 244 | table_dict.items(), key=lambda item: item[0]
|
@@ -122,21 +278,13 @@ def render_table(table_dict, sort=True, title=None):
|
122 | 278 |
|
123 | 279 |
|
124 | 280 | def render_base_template(title, content):
|
125 |
| - css_content = "" |
126 |
| - css_path = here / "html" / "style.css" |
127 |
| - if css_path: |
128 |
| - with open(css_path, "r") as css_file: |
129 |
| - css_content = css_file.read() |
130 |
| - |
131 | 281 | github_icon_svg = """<svg xmlns="http://www.w3.org/2000/svg" fill="whitesmoke" height="3em" viewBox="0 0 496 512"><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>"""
|
132 | 282 | return f"""
|
133 | 283 | <!DOCTYPE html>
|
134 | 284 | <html>
|
135 | 285 | <head>
|
136 | 286 | <title>{title}</title>
|
137 |
| - <style> |
138 |
| - {css_content} |
139 |
| - </style> |
| 287 | + <link rel="stylesheet" href="/mtb-assets/style.css"/> |
140 | 288 | </head>
|
141 | 289 | <script type="module">
|
142 | 290 | import {{ api }} from '/scripts/api.js'
|
|
0 commit comments