diff options
| author | salmonik <salmonik@tuta.io> | 2026-07-29 12:21:32 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-07-29 12:21:32 +0200 |
| commit | bc0d3d2f324ee613424ee31103207222b4b19640 (patch) | |
| tree | 483f699f303c44af6ec27b8f357e220b4d683e0c /templates/instances/edit.html | |
| parent | Enable/disable mods, batch toggle & delete (diff) | |
| download | minecraft-ui-bc0d3d2f324ee613424ee31103207222b4b19640.tar.gz minecraft-ui-bc0d3d2f324ee613424ee31103207222b4b19640.zip | |
Config editor, host networking, whitelist RCON
- Config file editor at /instances/{id}/config (browse & edit config/ files)
- Host networking for Docker container (fixes WireGuard MTU DNS issues)
- Whitelist changes applied live via RCON instead of stopping the server
- Config edit handler detects which fields changed: whitelist → RCON,
other settings → restart container
- walk_dir simplified (removed unused root param)
- import_world uses if-let instead of never-looping while-let
- docker-compose.yml updated as reference template
Diffstat (limited to '')
| -rw-r--r-- | templates/instances/edit.html | 226 |
1 files changed, 34 insertions, 192 deletions
diff --git a/templates/instances/edit.html b/templates/instances/edit.html index 77dfca6..ef7d53e 100644 --- a/templates/instances/edit.html +++ b/templates/instances/edit.html | |||
| @@ -19,125 +19,41 @@ | |||
| 19 | <legend>Server Properties</legend> | 19 | <legend>Server Properties</legend> |
| 20 | <label> | 20 | <label> |
| 21 | Memory (MB) | 21 | Memory (MB) |
| 22 | <input | 22 | <input type="number" name="memory_mb" value="{{ instance.memory_mb }}" min="512" max="{{ max_memory_mb }}" required /> |
| 23 | type="number" | ||
| 24 | name="memory_mb" | ||
| 25 | value="{{ instance.memory_mb }}" | ||
| 26 | min="512" | ||
| 27 | max="{{ max_memory_mb }}" | ||
| 28 | required | ||
| 29 | /> | ||
| 30 | </label> | 23 | </label> |
| 31 | <label> | 24 | <label> |
| 32 | Difficulty | 25 | Difficulty |
| 33 | <select name="difficulty"> | 26 | <select name="difficulty"> |
| 34 | <option | 27 | <option value="0"{% if instance.difficulty == 0 %} selected{% endif %}>Peaceful</option> |
| 35 | value="0" | 28 | <option value="1"{% if instance.difficulty == 1 %} selected{% endif %}>Easy</option> |
| 36 | {% | 29 | <option value="2"{% if instance.difficulty == 2 %} selected{% endif %}>Normal</option> |
| 37 | if | 30 | <option value="3"{% if instance.difficulty == 3 %} selected{% endif %}>Hard</option> |
| 38 | instance.difficulty == 0 | ||
| 39 | %}selected{% | ||
| 40 | endif | ||
| 41 | %} | ||
| 42 | > | ||
| 43 | Peaceful | ||
| 44 | </option> | ||
| 45 | <option | ||
| 46 | value="1" | ||
| 47 | {% | ||
| 48 | if | ||
| 49 | instance.difficulty == 1 | ||
| 50 | %}selected{% | ||
| 51 | endif | ||
| 52 | %} | ||
| 53 | > | ||
| 54 | Easy | ||
| 55 | </option> | ||
| 56 | <option | ||
| 57 | value="2" | ||
| 58 | {% | ||
| 59 | if | ||
| 60 | instance.difficulty == 2 | ||
| 61 | %}selected{% | ||
| 62 | endif | ||
| 63 | %} | ||
| 64 | > | ||
| 65 | Normal | ||
| 66 | </option> | ||
| 67 | <option | ||
| 68 | value="3" | ||
| 69 | {% | ||
| 70 | if | ||
| 71 | instance.difficulty == 3 | ||
| 72 | %}selected{% | ||
| 73 | endif | ||
| 74 | %} | ||
| 75 | > | ||
| 76 | Hard | ||
| 77 | </option> | ||
| 78 | </select> | 31 | </select> |
| 79 | </label> | 32 | </label> |
| 80 | <label> | 33 | <label> |
| 81 | Gamemode | 34 | Gamemode |
| 82 | <select name="gamemode"> | 35 | <select name="gamemode"> |
| 83 | <option value="0" {% if instance.gamemode == 0 %}selected{% endif %}> | 36 | <option value="0"{% if instance.gamemode == 0 %} selected{% endif %}>Survival</option> |
| 84 | Survival | 37 | <option value="1"{% if instance.gamemode == 1 %} selected{% endif %}>Creative</option> |
| 85 | </option> | 38 | <option value="2"{% if instance.gamemode == 2 %} selected{% endif %}>Adventure</option> |
| 86 | <option value="1" {% if instance.gamemode == 1 %}selected{% endif %}> | 39 | <option value="3"{% if instance.gamemode == 3 %} selected{% endif %}>Spectator</option> |
| 87 | Creative | ||
| 88 | </option> | ||
| 89 | <option value="2" {% if instance.gamemode == 2 %}selected{% endif %}> | ||
| 90 | Adventure | ||
| 91 | </option> | ||
| 92 | <option value="3" {% if instance.gamemode == 3 %}selected{% endif %}> | ||
| 93 | Spectator | ||
| 94 | </option> | ||
| 95 | </select> | 40 | </select> |
| 96 | </label> | 41 | </label> |
| 97 | <label> | 42 | <label> |
| 98 | Max Players | 43 | Max Players |
| 99 | <input | 44 | <input type="number" name="max_players" value="{{ instance.max_players }}" min="1" max="100" /> |
| 100 | type="number" | ||
| 101 | name="max_players" | ||
| 102 | value="{{ instance.max_players }}" | ||
| 103 | min="1" | ||
| 104 | max="100" | ||
| 105 | /> | ||
| 106 | </label> | 45 | </label> |
| 107 | <label> | 46 | <label> |
| 108 | <input | 47 | <input type="checkbox" name="pvp"{% if instance.pvp %} checked{% endif %} /> |
| 109 | type="checkbox" | ||
| 110 | name="pvp" | ||
| 111 | {% | ||
| 112 | if | ||
| 113 | instance.pvp | ||
| 114 | %}checked{% | ||
| 115 | endif | ||
| 116 | %} | ||
| 117 | /> | ||
| 118 | PvP enabled | 48 | PvP enabled |
| 119 | </label> | 49 | </label> |
| 120 | <label> | 50 | <label> |
| 121 | <input | 51 | <input type="checkbox" name="whitelist_enabled"{% if instance.whitelist_enabled %} checked{% endif %} /> |
| 122 | type="checkbox" | ||
| 123 | name="whitelist_enabled" | ||
| 124 | {% | ||
| 125 | if | ||
| 126 | instance.whitelist_enabled | ||
| 127 | %}checked{% | ||
| 128 | endif | ||
| 129 | %} | ||
| 130 | /> | ||
| 131 | Whitelist enabled | 52 | Whitelist enabled |
| 132 | </label> | 53 | </label> |
| 133 | <label> | 54 | <label> |
| 134 | MOTD | 55 | MOTD |
| 135 | <input | 56 | <input type="text" name="motd" value="{{ instance.motd }}" maxlength="59" /> |
| 136 | type="text" | ||
| 137 | name="motd" | ||
| 138 | value="{{ instance.motd }}" | ||
| 139 | maxlength="59" | ||
| 140 | /> | ||
| 141 | </label> | 57 | </label> |
| 142 | </fieldset> | 58 | </fieldset> |
| 143 | 59 | ||
| @@ -147,12 +63,8 @@ | |||
| 147 | </div> | 63 | </div> |
| 148 | </form> | 64 | </form> |
| 149 | 65 | ||
| 150 | <div | 66 | <div class="card{% if instance.is_active %} card-muted{% endif %}" style="margin-top: 1.5rem"> |
| 151 | class="card{% if instance.is_active %} card-muted{% endif %}" | ||
| 152 | style="margin-top: 1.5rem" | ||
| 153 | > | ||
| 154 | <h3>World Management</h3> | 67 | <h3>World Management</h3> |
| 155 | |||
| 156 | {% if instance.is_active %} | 68 | {% if instance.is_active %} |
| 157 | <div class="flash flash-warn">Stop the server before managing the world.</div> | 69 | <div class="flash flash-warn">Stop the server before managing the world.</div> |
| 158 | {% endif %} | 70 | {% endif %} |
| @@ -166,109 +78,39 @@ | |||
| 166 | </span> | 78 | </span> |
| 167 | </div> | 79 | </div> |
| 168 | 80 | ||
| 169 | <div | 81 | <div class="actions" style="flex-wrap:wrap; gap:1rem;{% if instance.is_active %} pointer-events:none; opacity:0.5{% endif %}"> |
| 170 | class="actions" | 82 | <a href="/instances/{{ instance.id }}/world/export" class="btn" hx-boost="false"{% if instance.is_active %} tabindex="-1"{% endif %}>Export World</a> |
| 171 | style="flex-wrap:wrap; gap:1rem; {% if instance.is_active %}pointer-events:none; opacity:0.5{% endif %}" | ||
| 172 | > | ||
| 173 | <a | ||
| 174 | href="/instances/{{ instance.id }}/world/export" | ||
| 175 | class="btn" | ||
| 176 | hx-boost="false" | ||
| 177 | {% | ||
| 178 | if | ||
| 179 | instance.is_active | ||
| 180 | %}tabindex="-1" | ||
| 181 | {% | ||
| 182 | endif | ||
| 183 | %} | ||
| 184 | >Export World</a | ||
| 185 | > | ||
| 186 | 83 | ||
| 187 | <form | 84 | <form action="/instances/{{ instance.id }}/world/import" method="post" enctype="multipart/form-data" style="display: flex; align-items: center; gap: 0.5rem" hx-boost="false"> |
| 188 | action="/instances/{{ instance.id }}/world/import" | 85 | <input type="file" name="world_zip" accept=".zip" required style="font-size: 0.85rem"{% if instance.is_active %} disabled{% endif %} /> |
| 189 | method="post" | 86 | <button type="submit" class="btn" onclick="return confirm('This will replace the current world. Continue?');"{% if instance.is_active %} disabled{% endif %}>Import</button> |
| 190 | enctype="multipart/form-data" | ||
| 191 | style="display: flex; align-items: center; gap: 0.5rem" | ||
| 192 | hx-boost="false" | ||
| 193 | > | ||
| 194 | <input | ||
| 195 | type="file" | ||
| 196 | name="world_zip" | ||
| 197 | accept=".zip" | ||
| 198 | required | ||
| 199 | style="font-size: 0.85rem" | ||
| 200 | {% | ||
| 201 | if | ||
| 202 | instance.is_active | ||
| 203 | %}disabled{% | ||
| 204 | endif | ||
| 205 | %} | ||
| 206 | /> | ||
| 207 | <button | ||
| 208 | type="submit" | ||
| 209 | class="btn" | ||
| 210 | onclick=" | ||
| 211 | return confirm('This will replace the current world. Continue?'); | ||
| 212 | " | ||
| 213 | {% | ||
| 214 | if | ||
| 215 | instance.is_active | ||
| 216 | %}disabled{% | ||
| 217 | endif | ||
| 218 | %} | ||
| 219 | > | ||
| 220 | Import | ||
| 221 | </button> | ||
| 222 | </form> | 87 | </form> |
| 223 | 88 | ||
| 224 | <form | 89 | <form action="/instances/{{ instance.id }}/world/regenerate" method="post" class="form-row" onsubmit="return confirm('This will DELETE the current world and generate a new one. Continue?');"> |
| 225 | action="/instances/{{ instance.id }}/world/regenerate" | 90 | <input type="text" name="seed" placeholder="Seed (empty = random)" style="width: 180px"{% if instance.is_active %} disabled{% endif %} /> |
| 226 | method="post" | 91 | <button type="submit" class="btn-danger"{% if instance.is_active %} disabled{% endif %}>Regenerate</button> |
| 227 | class="form-row" | ||
| 228 | onsubmit=" | ||
| 229 | return confirm( | ||
| 230 | 'This will DELETE the current world and generate a new one. Continue?', | ||
| 231 | ); | ||
| 232 | " | ||
| 233 | > | ||
| 234 | <input | ||
| 235 | type="text" | ||
| 236 | name="seed" | ||
| 237 | placeholder="Seed (empty = random)" | ||
| 238 | style="width: 180px" | ||
| 239 | {% | ||
| 240 | if | ||
| 241 | instance.is_active | ||
| 242 | %}disabled{% | ||
| 243 | endif | ||
| 244 | %} | ||
| 245 | /> | ||
| 246 | <button | ||
| 247 | type="submit" | ||
| 248 | class="btn-danger" | ||
| 249 | {% | ||
| 250 | if | ||
| 251 | instance.is_active | ||
| 252 | %}disabled{% | ||
| 253 | endif | ||
| 254 | %} | ||
| 255 | > | ||
| 256 | Regenerate | ||
| 257 | </button> | ||
| 258 | </form> | 92 | </form> |
| 259 | </div> | 93 | </div> |
| 260 | </div> | 94 | </div> |
| 261 | 95 | ||
| 262 | <div class="card" style="margin-top: 1.5rem"> | 96 | <div class="card" style="margin-top: 1.5rem"> |
| 97 | <h3>Configuration Files</h3> | ||
| 98 | <div class="meta" style="margin-bottom: 0.5rem"> | ||
| 99 | <span>Edit mod/plugin config files inside <code>config/</code></span> | ||
| 100 | </div> | ||
| 101 | <div class="actions"> | ||
| 102 | <a href="/instances/{{ instance.id }}/config" class="btn">Open Config Editor</a> | ||
| 103 | </div> | ||
| 104 | </div> | ||
| 105 | |||
| 106 | <div class="card" style="margin-top: 1.5rem"> | ||
| 263 | <h3>Mods</h3> | 107 | <h3>Mods</h3> |
| 264 | <div class="meta" style="margin-bottom: 0.5rem"> | 108 | <div class="meta" style="margin-bottom: 0.5rem"> |
| 265 | <span> | 109 | <span> |
| 266 | {% if instance.has_modpack %} | 110 | {% if instance.has_modpack %} |
| 267 | <strong>{{ mod_count }}</strong> mod{% if mod_count != 1 %}s{% endif %} | 111 | <strong>{{ mod_count }}</strong> mod{% if mod_count != 1 %}s{% endif %} |
| 268 | installed {% if rejected_count > 0 %} (<strong | 112 | installed{% if rejected_count > 0 %} (<strong>{{ rejected_count }}</strong> rejected){% endif %} |
| 269 | >{{ rejected_count }}</strong | 113 | {% else %} No mods installed {% endif %} |
| 270 | > | ||
| 271 | rejected) {% endif %} {% else %} No mods installed {% endif %} | ||
| 272 | </span> | 114 | </span> |
| 273 | </div> | 115 | </div> |
| 274 | <div class="actions"> | 116 | <div class="actions"> |
