blob: cab78bf5bec6d38e1a42059bf1907d64676f1317 [file] [log] [blame]
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +04001{{ define "schema-form" }}
2 {{ $readonly := .ReadOnly }}
3 {{ $networks := .AvailableNetworks }}
4 {{ $data := .Data }}
gio44f621b2024-04-29 09:44:38 +04005 {{ range $f := .Schema.Fields }}
6 {{ $name := $f.Name }}
7 {{ $schema := $f.Schema }}
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +04008 {{ if eq $schema.Kind 0 }}
gio44f621b2024-04-29 09:44:38 +04009 <label {{ if $schema.Advanced }}hidden{{ end }}>
10 <input type="checkbox" role="swtich" name="{{ $name }}" oninput="valueChanged({{ $name }}, this.checked)" {{ if $readonly }}disabled{{ end }} {{ if index $data $name }}checked{{ end }} />
11 {{ $schema.Name }}
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040012 </label>
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +040013 {{ else if eq $schema.Kind 7 }}
gio44f621b2024-04-29 09:44:38 +040014 <label {{ if $schema.Advanced }}hidden{{ end }}>
15 {{ $schema.Name }}
16 <input type="text" name="{{ $name }}" oninput="valueChanged({{ $name }}, parseInt(this.value))" {{ if $readonly }}disabled{{ end }} value="{{ index $data $name }}" />
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +040017 </label>
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040018 {{ else if eq $schema.Kind 1 }}
gio44f621b2024-04-29 09:44:38 +040019 <label {{ if $schema.Advanced }}hidden{{ end }}>
20 {{ $schema.Name }}
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040021 <input type="text" name="{{ $name }}" oninput="valueChanged({{ $name }}, this.value)" {{ if $readonly }}disabled{{ end }} value="{{ index $data $name }}" />
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040022 {{ else if eq $schema.Kind 4 }}
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040023 </label>
gio44f621b2024-04-29 09:44:38 +040024 <label {{ if $schema.Advanced }}hidden{{ end }}>
25 {{ $schema.Name }}
26 <input type="text" name="{{ $name }}" oninput="valueChanged({{ $name }}, this.value)" {{ if $readonly }}disabled{{ end }} value="{{ index $data $name }}" />
27 </label>
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040028 {{ else if eq $schema.Kind 3 }}
gio44f621b2024-04-29 09:44:38 +040029 <label {{ if $schema.Advanced }}hidden{{ end }}>
30 {{ $schema.Name }}
31 <select name="{{ $name }}" oninput="valueChanged({{ $name }}, this.value)" {{ if $readonly }}disabled{{ end }} >
32 {{ if not $readonly }}<option disabled selected value>Available networks</option>{{ end }}
33 {{ range $networks }}
34 <option {{if eq .Name (index $data $name) }}selected{{ end }}>{{ .Name }}</option>
35 {{ end }}
36 </select>
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040037 </label>
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040038 {{ else if eq $schema.Kind 5 }}
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040039 {{ $auth := index $data $name }}
40 {{ $authEnabled := false }}
41 {{ $authGroups := "" }}
42 {{ if and $auth (index $auth "enabled") }}{{ $authEnabled = true }}{{ end }}
43 {{ if and $auth (index $auth "groups") }}{{ $authGroups = index $auth "groups" }}{{ end }}
gio44f621b2024-04-29 09:44:38 +040044 <label {{ if $schema.Advanced }}hidden{{ end }}>
45 <input type="checkbox" role="swtich" name="authEnabled" oninput="valueChanged('{{- $name -}}.enabled', this.checked)" {{ if $readonly }}disabled{{ end }} {{ if $authEnabled }}checked{{ end }} />
46 <span>Require authentication</span>
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040047 </label>
gio44f621b2024-04-29 09:44:38 +040048 <label for="authGroups">
49 <span>Authentication groups</span>
50 <input type="text" name="authGroups" oninput="valueChanged('{{- $name -}}.groups', this.value)" {{ if $readonly }}disabled{{ end }} value="{{ $authGroups }}" />
51 </label>
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040052 {{ else if eq $schema.Kind 6 }}
53 {{ $sshKey := index $data $name }}
54 {{ $public := "" }}
55 {{ $private := "" }}
56 {{ if $sshKey }}{{ $public = index $sshKey "public" }}{{ end }}
57 {{ if $sshKey }}{{ $private = index $sshKey "private" }}{{ end }}
gio44f621b2024-04-29 09:44:38 +040058 <label {{ if $schema.Advanced }}hidden{{ end }}>
59 <span>Public Key</span>
60 <textarea name="{{ $name }}-public" disabled>{{ $public }}</textarea>
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040061 </label>
gio44f621b2024-04-29 09:44:38 +040062 <label {{ if $schema.Advanced }}hidden{{ end }}>
63 <span>Private Key</span>
64 <textarea name="{{ $name }}-private" disabled>{{ $private }}</textarea>
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040065 </label>
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040066 {{ end }}
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040067 {{ end }}
68{{ end }}
69
70{{ define "main" }}
71{{ $instance := .Instance }}
gio44f621b2024-04-29 09:44:38 +040072<h1 style="margin-bottom: 20px">{{ .App.Icon }}{{ .App.Name }}</h1>
73<pre id="readme" style="margin-bottom: 50px">{{ .App.Description }}</pre>
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040074
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040075{{ $schema := .App.Schema }}
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040076{{ $networks := .AvailableNetworks }}
77
78<form id="config-form">
79 {{ if $instance }}
gio3cdee592024-04-17 10:15:56 +040080 {{ template "schema-form" (dict "Schema" $schema "AvailableNetworks" $networks "ReadOnly" false "Data" ($instance.InputToValues $schema)) }}
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040081 {{ else }}
82 {{ template "schema-form" (dict "Schema" $schema "AvailableNetworks" $networks "ReadOnly" false "Data" (dict)) }}
83 {{ end }}
84 {{ if $instance }}
85 <div class="grid">
86 <button type="submit" id="submit" name="update">Update</button>
87 <button type="submit" id="uninstall" name="remove">Uninstall</button>
88 </div>
89 {{ else }}
90 <button type="submit" id="submit">{{ if $instance }}Update{{ else }}Install{{ end }}</button>
91 {{ end }}
92</form>
93
94{{ range .Instances }}
95 {{ if or (not $instance) (ne $instance.Id .Id)}}
96 <details>
97 <summary>{{ .Id }}</summary>
gio3cdee592024-04-17 10:15:56 +040098 {{ template "schema-form" (dict "Schema" $schema "AvailableNetworks" $networks "ReadOnly" true "Data" (.InputToValues $schema)) }}
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040099 <a href="/instance/{{ .Id }}" role="button" class="secondary">View</a>
100 </details>
101 {{ end }}
102{{ end }}
103
104
105<div id="toast-success" class="toast hidden">
106 <svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><path fill="currentColor" d="M18 2a16 16 0 1 0 16 16A16 16 0 0 0 18 2Zm0 30a14 14 0 1 1 14-14a14 14 0 0 1-14 14Z" class="clr-i-outline clr-i-outline-path-1"/><path fill="currentColor" d="M28 12.1a1 1 0 0 0-1.41 0l-11.1 11.05l-6-6A1 1 0 0 0 8 18.53L15.49 26L28 13.52a1 1 0 0 0 0-1.42Z" class="clr-i-outline clr-i-outline-path-2"/><path fill="none" d="M0 0h36v36H0z"/></svg> {{ if $instance }}Update succeeded{{ else }}Install succeeded{{ end}}
107</div>
108
109<div id="toast-failure" class="toast hidden">
110 <svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2S2 6.477 2 12s4.477 10 10 10Zm3-6L9 8m0 8l6-8"/></svg> {{ if $instance }}Update failed{{ else}}Install failed{{ end }}
111</div>
112
113<div id="toast-uninstall-success" class="toast hidden">
114 <svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><path fill="currentColor" d="M18 2a16 16 0 1 0 16 16A16 16 0 0 0 18 2Zm0 30a14 14 0 1 1 14-14a14 14 0 0 1-14 14Z" class="clr-i-outline clr-i-outline-path-1"/><path fill="currentColor" d="M28 12.1a1 1 0 0 0-1.41 0l-11.1 11.05l-6-6A1 1 0 0 0 8 18.53L15.49 26L28 13.52a1 1 0 0 0 0-1.42Z" class="clr-i-outline clr-i-outline-path-2"/><path fill="none" d="M0 0h36v36H0z"/></svg> Uninstalled application
115</div>
116
117<div id="toast-uninstall-failure" class="toast hidden">
118 <svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2S2 6.477 2 12s4.477 10 10 10Zm3-6L9 8m0 8l6-8"/></svg> Failed to uninstall application
119</div>
120
121<style>
122 pre {
123 white-space: pre-wrap; /* Since CSS 2.1 */
124 white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
125 white-space: -pre-wrap; /* Opera 4-6 */
126 white-space: -o-pre-wrap; /* Opera 7 */
127 word-wrap: break-word; /* Internet Explorer 5.5+ */
128 background-color: transparent;
129 }
130
131 .hidden {
132 visibility: hidden;
133 }
134
135 .toast {
136 position: fixed;
137 z-index: 999;
138 bottom: 10px;
139 }
140</style>
141
142<script>
gio3cdee592024-04-17 10:15:56 +0400143 let config = {{ if $instance }}JSON.parse({{ toJson ($instance.InputToValues $schema) }}){{ else }}{}{{ end }};
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400144
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400145 function setValue(name, value, config) {
146 let items = name.split(".")
147 for (let i = 0; i < items.length - 1; i++) {
148 if (!(items[i] in config)) {
149 config[items[i]] = {}
150 }
151 config = config[items[i]];
152 }
153 config[items[items.length - 1]] = value;
154}
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400155 function valueChanged(name, value) {
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400156 setValue(name, value, config);
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400157 }
158
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400159 function disableForm() {
160 document.querySelectorAll("#config-form input").forEach((i) => i.setAttribute("disabled", ""));
161 document.querySelectorAll("#config-form select").forEach((i) => i.setAttribute("disabled", ""));
162 document.querySelectorAll("#config-form button").forEach((i) => i.setAttribute("disabled", ""));
163 }
164
165 function enableForm() {
166 document.querySelectorAll("[aria-busy]").forEach((i) => i.removeAttribute("aria-busy"));
167 document.querySelectorAll("#config-form input").forEach((i) => i.removeAttribute("disabled"));
168 document.querySelectorAll("#config-form select").forEach((i) => i.removeAttribute("disabled"));
169 document.querySelectorAll("#config-form button").forEach((i) => i.removeAttribute("disabled"));
170 }
171
172 function installStarted() {
173 const submit = document.getElementById("submit");
174 submit.setAttribute("aria-busy", true);
175 submit.innerHTML = {{ if $instance }}"Updating ..."{{ else }}"Installing ..."{{ end }};
176 disableForm();
177 }
178
179 function uninstallStarted() {
180 const submit = document.getElementById("uninstall");
181 submit.setAttribute("aria-busy", true);
182 submit.innerHTML = "Uninstalling ...";
183 disableForm();
184 }
185
186 function actionFinished(toast) {
187 enableForm();
188 toast.classList.remove("hidden");
189 setTimeout(
190 () => toast.classList.add("hidden"),
191 2000,
192 );
193 }
194
195 function installSucceeded() {
196 actionFinished(document.getElementById("toast-success"));
197 }
198
199 function installFailed() {
200 actionFinished(document.getElementById("toast-failure"));
201 }
202
203 function uninstallSucceeded() {
204 actionFinished(document.getElementById("toast-uninstall-success"));
205 }
206
207 function uninstallFailed() {
208 actionFinished(document.getElementById("toast-uninstall-failure"));
209 }
210
gio44f621b2024-04-29 09:44:38 +0400211 const submitAddr = {{ if $instance }}"/api/instance/{{ $instance.Id }}/update"{{ else }}"/api/app/{{ .App.Slug }}/install"{{ end }};
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400212
213 async function install() {
214 installStarted();
215 const resp = await fetch(submitAddr, {
216 method: "POST",
217 headers: {
218 "Content-Type": "application/json",
219 "Accept": "application/json",
220 },
221 body: JSON.stringify(config),
222 });
223 if (resp.status === 200) {
224 installSucceeded();
225 } else {
226 installFailed();
227 }
228 }
229
230 async function uninstall() {
231 {{ if $instance }}
232 uninstallStarted();
233 const resp = await fetch("/api/instance/{{ $instance.Id }}/remove", {
234 method: "POST",
235 });
236 if (resp.status === 200) {
237 uninstallSucceeded();
238 } else {
239 uninstallFailed();
240 }
241 {{ end }}
242 }
243
244 document.getElementById("config-form").addEventListener("submit", (event) => {
245 event.preventDefault();
246 if (event.submitter.id === "submit") {
247 install();
248 } if (event.submitter.id === "uninstall") {
249 uninstall();
250 }
251 });
252</script>
253{{ end }}