Commit b2a6fe01 authored by jan.koester's avatar jan.koester
Browse files

test

parent 2b54c3ef
Loading
Loading
Loading
Loading
+2 −0
Changes for modules/containers/containers.cpp: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -258,8 +258,10 @@ json_object *apps() {
                app = json_object_new_object();
                json_object_object_add(app, "name", jstr(f.second));
                json_object_object_add(app, "tags", json_object_new_array());
                json_object_object_add(app, "volumes", json_object_new_array());
                json_object_array_add(list, app);
            } else if (app && f.first == "tag") json_object_array_add(json_object_object_get(app, "tags"), jstr(f.second));
            else if (app && f.first == "volume") json_object_array_add(json_object_object_get(app, "volumes"), jstr(f.second));
            else if (app) json_object_object_add(app, f.first.c_str(), jstr(f.second));
        }
    }
+31 −2
Changes for www/modules/containers.js: 31 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -326,6 +326,20 @@
  }

  // app: installing it, a new container on an image not pulled yet
  // host directories for an image's volumes: the first below /etc is the
  // container's directory itself, the others keep their path below it
  function defaultBinds(container, volumes) {
    const base = '/srv/container/' + container;
    let config = false;
    return volumes.map(v => v.replace(/\/+$/, '')).filter(Boolean).map(v => {
      if (!config && v.startsWith('/etc/')) {
        config = true;
        return base + ':' + v;
      }
      return base + v + ':' + v;
    });
  }

  async function containerDialog(name, app) {
    const images = data.images || [];
    if (!name && !app && !images.length) {
@@ -408,9 +422,24 @@
        net.addEventListener('change', update);
        update();
        const area = (nm, list, rows) => h('textarea', {name: nm, rows: rows || 3, class: 'mono'}, (list || []).join('\n'));
        const nameInput = h('input', {name: 'name', value: c.name, required: true, pattern: '[A-Za-z0-9_.\\-]{1,64}'});
        const binds = area('binds', c.binds);
        // a new container's binds follow its name and image until edited
        let bindsEdited = !!name;
        const proposeBinds = () => {
          if (bindsEdited) return;
          const img = images.find(i => i.image === imageSel.value);
          const volumes = (img && img.volumes) || (app && app.volumes) || [];
          const container = nameInput.value.trim();
          binds.value = container ? defaultBinds(container, volumes).join('\n') : '';
        };
        binds.addEventListener('input', () => { bindsEdited = binds.value !== ''; proposeBinds(); });
        nameInput.addEventListener('input', proposeBinds);
        imageSel.addEventListener('change', proposeBinds);
        proposeBinds();
        return [
          h('div', {class: 'row'},
            h('label', {}, t('Name'), h('input', {name: 'name', value: c.name, required: true, pattern: '[A-Za-z0-9_.\\-]{1,64}'})),
            h('label', {}, t('Name'), nameInput),
            h('label', {}, t('Image'), imageSel)),
          h('div', {class: 'row'},
            h('label', {class: 'check'}, h('input', {type: 'checkbox', name: 'autostart', checked: c.autostart}), t('Start automatically')),
@@ -422,7 +451,7 @@
          portsHint,
          h('label', {}, t('Arguments (replace the image\'s CMD)'), args),
          h('label', {}, t('Environment (KEY=value, one per line)'), area('env', c.env)),
          h('label', {}, t('Bind mounts (/host/path:/container/path[:ro], one per line)'), area('binds', c.binds)),
          h('label', {}, t('Bind mounts (/host/path:/container/path[:ro], one per line)'), binds),
          volumesHint,
          h('details', {},
            h('summary', {}, t('Advanced')),