AppManager: clean up UI

Change-Id: I8119ea81c80ff6165f4217dfdf9837e776703fc0
diff --git a/core/installer/welcome/appmanager-tmpl/app.html b/core/installer/welcome/appmanager-tmpl/app.html
index 8c25adf..cab78bf 100644
--- a/core/installer/welcome/appmanager-tmpl/app.html
+++ b/core/installer/welcome/appmanager-tmpl/app.html
@@ -2,73 +2,75 @@
   {{ $readonly := .ReadOnly }}
   {{ $networks := .AvailableNetworks }}
   {{ $data := .Data }}
-  {{ range $name, $schema := .Schema.Fields }}
+  {{ range $f := .Schema.Fields }}
+  {{ $name := $f.Name }}
+  {{ $schema := $f.Schema }}
     {{ if eq $schema.Kind 0 }}
-      <label for="{{ $name }}">
-        <span>{{ $name }}</span>
+      <label {{ if $schema.Advanced }}hidden{{ end }}>
+		  <input type="checkbox" role="swtich" name="{{ $name }}" oninput="valueChanged({{ $name }}, this.checked)" {{ if $readonly }}disabled{{ end }} {{ if index $data $name }}checked{{ end }} />
+          {{ $schema.Name }}
       </label>
-	  <input type="checkbox" role="swtich" name="{{ $name }}" oninput="valueChanged({{ $name }}, this.checked)" {{ if $readonly }}disabled{{ end }} {{ if index $data $name }}checked{{ end }} />
     {{ else if eq $schema.Kind 7 }}
-      <label for="{{ $name }}">
-        <span>{{ $name }}</span>
+      <label {{ if $schema.Advanced }}hidden{{ end }}>
+          {{ $schema.Name }}
+		  <input type="text" name="{{ $name }}" oninput="valueChanged({{ $name }}, parseInt(this.value))" {{ if $readonly }}disabled{{ end }} value="{{ index $data $name }}" />
       </label>
-	  <input type="text" name="{{ $name }}" oninput="valueChanged({{ $name }}, parseInt(this.value))" {{ if $readonly }}disabled{{ end }} value="{{ index $data $name }}" />
     {{ else if eq $schema.Kind 1 }}
-      <label for="{{ $name }}">
-        <span>{{ $name }}</span>
-      </label>
+      <label {{ if $schema.Advanced }}hidden{{ end }}>
+          {{ $schema.Name }}
 	  <input type="text" name="{{ $name }}" oninput="valueChanged({{ $name }}, this.value)" {{ if $readonly }}disabled{{ end }} value="{{ index $data $name }}" />
     {{ else if eq $schema.Kind 4 }}
-      <label for="{{ $name }}">
-        <span>{{ $name }}</span>
       </label>
-	  <input type="text" name="{{ $name }}" oninput="valueChanged({{ $name }}, this.value)" {{ if $readonly }}disabled{{ end }} value="{{ index $data $name }}" />
+      <label {{ if $schema.Advanced }}hidden{{ end }}>
+          {{ $schema.Name }}
+		  <input type="text" name="{{ $name }}" oninput="valueChanged({{ $name }}, this.value)" {{ if $readonly }}disabled{{ end }} value="{{ index $data $name }}" />
+      </label>
 	{{ else if eq $schema.Kind 3 }}
-      <label for="{{ $name }}">
-        <span>{{ $name }}</span>
+      <label {{ if $schema.Advanced }}hidden{{ end }}>
+          {{ $schema.Name }}
+		  <select name="{{ $name }}" oninput="valueChanged({{ $name }}, this.value)" {{ if $readonly }}disabled{{ end }} >
+			  {{ if not $readonly }}<option disabled selected value>Available networks</option>{{ end }}
+			  {{ range $networks }}
+			  <option {{if eq .Name (index $data $name) }}selected{{ end }}>{{ .Name }}</option>
+			  {{ end }}
+		  </select>
       </label>
-	  <select name="{{ $name }}" oninput="valueChanged({{ $name }}, this.value)" {{ if $readonly }}disabled{{ end }} >
-		{{ if not $readonly }}<option disabled selected value>Available networks</option>{{ end }}
-		{{ range $networks }}
-		  <option {{if eq .Name (index $data $name) }}selected{{ end }}>{{ .Name }}</option>
-		{{ end }}
-	  </select>
 	{{ else if eq $schema.Kind 5 }}
-      <label for="authEnabled">
-        <span>Require authentication</span>
-      </label>
 	  {{ $auth := index $data $name }}
 	  {{ $authEnabled := false }}
 	  {{ $authGroups := "" }}
 	  {{ if and $auth (index $auth "enabled") }}{{ $authEnabled = true }}{{ end }}
 	  {{ if and $auth (index $auth "groups") }}{{ $authGroups = index $auth "groups" }}{{ end }}
-      <input type="checkbox" role="swtich" name="authEnabled" oninput="valueChanged('{{- $name -}}.enabled', this.checked)" {{ if $readonly }}disabled{{ end }} {{ if $authEnabled  }}checked{{ end }} />
-      <label for="authGroups">
-        <span>Authentication Groups</span>
+      <label {{ if $schema.Advanced }}hidden{{ end }}>
+		  <input type="checkbox" role="swtich" name="authEnabled" oninput="valueChanged('{{- $name -}}.enabled', this.checked)" {{ if $readonly }}disabled{{ end }} {{ if $authEnabled  }}checked{{ end }} />
+          <span>Require authentication</span>
       </label>
-      <input type="text" name="authGroups" oninput="valueChanged('{{- $name -}}.groups', this.value)" {{ if $readonly }}disabled{{ end }} value="{{ $authGroups }}" />
+      <label for="authGroups">
+          <span>Authentication groups</span>
+		  <input type="text" name="authGroups" oninput="valueChanged('{{- $name -}}.groups', this.value)" {{ if $readonly }}disabled{{ end }} value="{{ $authGroups }}" />
+      </label>
 	{{ else if eq $schema.Kind 6 }}
  	  {{ $sshKey := index $data $name }}
 	  {{ $public := "" }}
 	  {{ $private := "" }}
 	  {{ if $sshKey }}{{ $public = index $sshKey "public" }}{{ end }}
 	  {{ if $sshKey }}{{ $private = index $sshKey "private" }}{{ end }}
-      <label for="{{ $name }}-public">
-        <span>Public Key</span>
+      <label {{ if $schema.Advanced }}hidden{{ end }}>
+          <span>Public Key</span>
+		  <textarea name="{{ $name }}-public" disabled>{{ $public }}</textarea>
       </label>
-	  <textarea name="{{ $name }}-public" disabled>{{ $public }}</textarea>
-      <label for="{{ $name }}-private">
-        <span>Private Key</span>
+      <label {{ if $schema.Advanced }}hidden{{ end }}>
+          <span>Private Key</span>
+		  <textarea name="{{ $name }}-private" disabled>{{ $private }}</textarea>
       </label>
-	  <textarea name="{{ $name }}-private" disabled>{{ $private }}</textarea>
     {{ end }}
   {{ end }}
 {{ end }}
 
 {{ define "main" }}
 {{ $instance := .Instance }}
-<h1>{{ .App.Icon }}{{ .App.Name }}</h1>
-<pre id="readme"></pre>
+<h1 style="margin-bottom: 20px">{{ .App.Icon }}{{ .App.Name }}</h1>
+<pre id="readme" style="margin-bottom: 50px">{{ .App.Description }}</pre>
 
 {{ $schema := .App.Schema }}
 {{ $networks := .AvailableNetworks }}
@@ -138,7 +140,6 @@
 </style>
 
 <script>
- let readme = "";
  let config = {{ if $instance }}JSON.parse({{ toJson ($instance.InputToValues $schema) }}){{ else }}{}{{ end }};
 
  function setValue(name, value, config) {
@@ -153,24 +154,8 @@
 }
  function valueChanged(name, value) {
 	 setValue(name, value, config);
-     renderReadme();
  }
 
- async function renderReadme() {
-	 const resp = await fetch("/api/app/{{ .App.Name }}/render", {
-         method: "POST",
-         headers: {
-             "Content-Type": "application/json",
-             "Accept": "application/json",
-         },
-         body: JSON.stringify(config),
-     });
-     const app = await resp.json();
-     document.getElementById("readme").innerHTML = app.readme;
- }
-
- {{ if $instance }}renderReadme();{{ end }}
-
  function disableForm() {
      document.querySelectorAll("#config-form input").forEach((i) => i.setAttribute("disabled", ""));
      document.querySelectorAll("#config-form select").forEach((i) => i.setAttribute("disabled", ""));
@@ -223,7 +208,7 @@
      actionFinished(document.getElementById("toast-uninstall-failure"));
  }
 
- const submitAddr = {{ if $instance }}"/api/instance/{{ $instance.Id }}/update"{{ else }}"/api/app/{{ .App.Name }}/install"{{ end }};
+ const submitAddr = {{ if $instance }}"/api/instance/{{ $instance.Id }}/update"{{ else }}"/api/app/{{ .App.Slug }}/install"{{ end }};
 
  async function install() {
      installStarted();
diff --git a/core/installer/welcome/appmanager.go b/core/installer/welcome/appmanager.go
index e8c929d..a6eb243 100644
--- a/core/installer/welcome/appmanager.go
+++ b/core/installer/welcome/appmanager.go
@@ -52,7 +52,6 @@
 	e := echo.New()
 	e.StaticFS("/static", echo.MustSubFS(staticAssets, "static"))
 	e.GET("/api/app-repo", s.handleAppRepo)
-	e.POST("/api/app/:slug/render", s.handleAppRender)
 	e.POST("/api/app/:slug/install", s.handleAppInstall)
 	e.GET("/api/app/:slug", s.handleApp)
 	e.GET("/api/instance/:slug", s.handleInstance)
@@ -80,7 +79,7 @@
 	}
 	resp := make([]app, len(all))
 	for i, a := range all {
-		resp[i] = app{a.Name(), a.Icon(), a.Description(), a.Name(), nil}
+		resp[i] = app{a.Name(), a.Icon(), a.Description(), a.Slug(), nil}
 	}
 	return c.JSON(http.StatusOK, resp)
 }
@@ -95,7 +94,7 @@
 	if err != nil {
 		return err
 	}
-	return c.JSON(http.StatusOK, app{a.Name(), a.Icon(), a.Description(), a.Name(), instances})
+	return c.JSON(http.StatusOK, app{a.Name(), a.Icon(), a.Description(), a.Slug(), instances})
 }
 
 func (s *AppManagerServer) handleInstance(c echo.Context) error {
@@ -108,50 +107,7 @@
 	if err != nil {
 		return err
 	}
-	return c.JSON(http.StatusOK, app{a.Name(), a.Icon(), a.Description(), a.Name(), []installer.AppInstanceConfig{instance}})
-}
-
-type file struct {
-	Name     string `json:"name"`
-	Contents string `json:"contents"`
-}
-
-type rendered struct {
-	Readme string `json:"readme"`
-}
-
-func (s *AppManagerServer) handleAppRender(c echo.Context) error {
-	slug := c.Param("slug")
-	contents, err := ioutil.ReadAll(c.Request().Body)
-	if err != nil {
-		return err
-	}
-	env, err := s.m.Config()
-	if err != nil {
-		return err
-	}
-	var values map[string]any
-	if err := json.Unmarshal(contents, &values); err != nil {
-		return err
-	}
-	a, err := installer.FindEnvApp(s.r, slug)
-	if err != nil {
-		return err
-	}
-	r, err := a.Render(installer.Release{}, env, values)
-	if err != nil {
-		return err
-	}
-	var resp rendered
-	resp.Readme = r.Readme
-	out, err := json.Marshal(resp)
-	if err != nil {
-		return err
-	}
-	if _, err := c.Response().Writer.Write(out); err != nil {
-		return err
-	}
-	return nil
+	return c.JSON(http.StatusOK, app{a.Name(), a.Icon(), a.Description(), a.Slug(), []installer.AppInstanceConfig{instance}})
 }
 
 func (s *AppManagerServer) handleAppInstall(c echo.Context) error {
@@ -180,7 +136,7 @@
 	if err != nil {
 		return err
 	}
-	instanceId := a.Name() + suffix
+	instanceId := a.Slug() + suffix
 	appDir := fmt.Sprintf("/apps/%s", instanceId)
 	namespace := fmt.Sprintf("%s%s%s", env.NamespacePrefix, a.Namespace(), suffix)
 	if err := s.m.Install(a, instanceId, appDir, namespace, values); err != nil {
@@ -240,7 +196,7 @@
 	}
 	resp := make([]app, len(all))
 	for i, a := range all {
-		resp[i] = app{a.Name(), a.Icon(), a.Description(), a.Name(), nil}
+		resp[i] = app{a.Name(), a.Icon(), a.Description(), a.Slug(), nil}
 	}
 	return tmpl.Execute(c.Response(), resp)
 }
@@ -305,7 +261,7 @@
 	if err != nil {
 		return err
 	}
-	instances, err := s.m.FindAllAppInstances(a.Name())
+	instances, err := s.m.FindAllAppInstances(a.Slug())
 	if err != nil {
 		return err
 	}
diff --git a/core/installer/welcome/welcome.go b/core/installer/welcome/welcome.go
index c5d732c..d7bccdd 100644
--- a/core/installer/welcome/welcome.go
+++ b/core/installer/welcome/welcome.go
@@ -223,7 +223,7 @@
 				http.Error(w, err.Error(), http.StatusInternalServerError)
 				return
 			}
-			instanceId := fmt.Sprintf("%s-%s", app.Name(), req.Username)
+			instanceId := fmt.Sprintf("%s-%s", app.Slug(), req.Username)
 			appDir := fmt.Sprintf("/apps/%s", instanceId)
 			namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
 			if err := appManager.Install(app, instanceId, appDir, namespace, map[string]any{