webapp_detail.html 11.7 KB
Newer Older
1
{% extends "base.html" %}
2
{% load static converters htmlattrs humanize %}
3

4
{% block title %}{{ webapp.name | fancy_webapp_name | title }} application{% endblock %}
5

BERJON Matthieu's avatar
BERJON Matthieu committed
6
{% block breadcrumb %}
7
<li class="breadcrumb-item"><a href="{% url 'main:webapp_list' %}">Applications</a></li>
8
<li class="breadcrumb-item active" aria-current="page">{{ webapp.name | fancy_webapp_name | title }}</li>
BERJON Matthieu's avatar
BERJON Matthieu committed
9
10
{% endblock %}

11
{% block content %}
BERJON Matthieu's avatar
BERJON Matthieu committed
12
<div class="container">
13
14
  <div class="allgo-page">
    <div class="row">
15
16
17
18
19
20
21
22
23
24


      <div class="col">
        <h1>
          {% if webapp.logo_file_name %}
          <img class="card-img-top img-thumbnail rounded-circle mx-auto" src="{% get_media_prefix %}{{ webapp.docker_name }}/{{ webapp.logo_file_name }}" alt="{{ webapp.title }} logo" style="max-width: 45px;">
          {% endif %}
          {{ webapp.name | fancy_webapp_name | title }}</h1>
      </div>
      <div class="col text-right">
25
          {% if webapp.user == user %}
26
27
28
29
          <a class="fa-layers fa-2x"
            href="{% url 'main:webapp_update' webapp.docker_name %}"
            data-toggle="tooltip"
            data-placement="top"
30
            title="Edit properties">
31
32
            <i class="fas fa-square"></i>
            <i class="fa-inverse fas fa-pencil-alt" data-fa-transform="shrink-7 down-.25 left-.25"></i>
33
            <span class="text-hide">Edit properties</span>
34
          </a>
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

          <a class="fa-layers fa-2x"
            href="{% url 'main:webapp_sandbox_panel' webapp.docker_name %}"
            data-toggle="tooltip"
            data-placement="top"
            title="Create new version">
            <i class="fas fa-square"></i>
            <i class="fa-inverse fas fa-plus" data-fa-transform="shrink-7 down-.25 left-.25"></i>
            <span class="text-hide">Create a new version</span>
          </a>

          {% if webapp.imported %}
          <a class="fa-layers fa-2x"
            href="{% url 'main:webapp_version_import' webapp.docker_name %}"
            data-toggle="tooltip"
            data-placement="top"
            title="Import version">
            <i class="fas fa-square"></i>
            <i class="fa-inverse fas fa-cloud-download-alt" data-fa-transform="shrink-7 down-.25 left-2"></i>
            <span class="text-hide">Import version</span>
          </a>
          {% endif %}
BERJON Matthieu's avatar
BERJON Matthieu committed
57
          {% endif %}
58
      </div>
59
    </div>
60

61
62
63
      <ul class="list-inline app-tags small mb-4">
        <li class="list-inline-item">{{ webapp.contact | email2name }}</li>
        <li class="list-inline-item">Updated {{ webapp.updated_at | naturalday }}</li>
BERJON Matthieu's avatar
BERJON Matthieu committed
64
        <li class="list-inline-item"><i class="fas fa-tags"></i></li>
65
66
67
        {% for tag in webapp.tags.all %}
        <li class="list-inline-item"><a class="badge badge-secondary" href="{% url 'main:tag_webapp_list' tag.slug %}">{{ tag.name }}</a></li>
        {% endfor %}
BERJON Matthieu's avatar
BERJON Matthieu committed
68
69
      </ul>

70
71
      {% if readme %}
        {{ readme | markdown | safe }}
BERJON Matthieu's avatar
BERJON Matthieu committed
72
      {% elif webapp.description %}
73
        {{ webapp.description | markdown | safe }}
74
75
76
77
      {% else %}
        <p>No description available</p>
      {% endif %}

78
79
80
81
82
83
84
85
86
87
88
89
90
    {# Link to the sandbox panel #}
    {% if webapp.sandbox_state != webapp.IDLE and user == webapp.user %}
    <div class="card">
      <div class="card-body">
        <h5 class="card-title">This application has an active sandbox</h5>
        <p class="card-text">You can run test jobs using the job submission form below</p>
        <p class="card-text">Once you are done, you can <b>commit</b> a new version
        (to save your work permanently and make it usable by other users)
        or <b>rollback</b> (to discard your changes)</p>
        <a href="{% url 'main:webapp_sandbox_panel' webapp.docker_name %}" class="card-link">Go to the sandbox panel</a>
      </div>
    </div>
    {% endif %}
91

92
    {# Panels #}
93
    <ul class="nav nav-tabs mt-3">
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
      <li class="nav-item"><a class="nav-link active" data-toggle="tab" href="#create-job"><i class="fas fa-database"></i> Run a job</a></li>
      <li class="nav-item"><a class="nav-link" data-toggle="tab" href="#api"><i class="fas fa-terminal"></i> Use the API</a></li>
      {% if webapp.notebook_gitrepo %}
      <li class="nav-item"><a class="nav-link" data-toggle="tab" href="#notebook"><i class="fas fa-file-alt"></i> Notebook</a></li>
      {% endif %}
    </ul>

      <div class="tab-content">
        <div class="tab-pane active" id="create-job">
          {% if user.is_authenticated %}
          <form method="post" enctype="multipart/form-data">
            {% csrf_token %}

            <div class="form-group">
              {{ form.files.label_tag }}
BAIRE Anthony's avatar
BAIRE Anthony committed
109
110
111
112
113
114
115
116
              <button type="button" class="btn btn-secondary btn-sm" onClick="add_input_file($(this).next())">+</button>
              <span class="form-inline input-group">
                <label for="input-file01" class="btn btn-secondary mr-sm-2" tabindex="0">Choose file</label>
                <input type="file" id="input-file01" name="{{ form.files.name }}" style="display:none"
                  multiple onChange="list_filenames_in_next_elt(this)">
                <input type="text" class="mr-sm-2 form-control" disabled >
                <button type="button" class="btn btn-secondary" onClick="$(this).prev()[0].value='';">x</button>
              </span>
117
              <small class="form-text text-muted">{{ form.files.help_text }}</small>
118
119
120
121
122
123
124
125
126
127
            </div>

            {{ form.param | label_with_classes:"d-block" }}
            <div class="form-group">
              <div class="input-group">
                <div class="input-group-prepend">
                  <button class="btn btn-outline-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Presets</button>
                  <div class="dropdown-menu">
                    {% for choice in form.webapp_parameters.field.queryset %}
                      <a class="dropdown-item" href="#" data-param="{{ choice.value }}">{{ choice.name }}</a>
128
129
                    {% empty %}
                    <p class="dropdown-item">No presets available</p>
130
131
132
                    {% endfor %}
                  </div>
                </div>
133
                {{ form.param | attr:"placeholder:Type your parameters here" | add_class:"form-control dropdown-value" }}
134
              </div>
135
              <small class="form-text text-muted">{{ form.param.help_text }}</small>
136
137
138
139
140
141
142
143
144
145
            </div>

            <div class="row">
              <div class="col form-group">
                {{ form.version.label_tag }}
                <select name="version" id="id_version" class="form-control">
                  {% for choice in versions %}
                  <option value="{{ choice }}">{{ choice }}</option>
                  {% endfor %}
                </select>
146
                <small class="form-text text-muted">{{ form.version.help_text }}</small>
147
              </div>
148

149
150
151
152
153
              <div class="col form-group">
                {{ form.queue_id.label_tag }}

                <select name="{{ form.queue_id.name }}" id="{{ form.queue_id.id_for_label }}" class="form-control">
                  {% for choice in form.queue_id.field.queryset %}
154
155
156
                  <option value="{{ choice.pk }}"
                    {% if choice.pk == webapp.job_queue_id %} selected {% endif %}
                    >{{ choice | fancy_job_queue }}</option>
157
158
                  {% endfor %}
                </select>
159
                <small class="form-text text-muted">{{ form.queue_id.help_text }}</small>
160
161
162
              </div>
            </div>

163
            <input class="btn btn-primary" type="submit" value="Run this job">
164
165
166
167
        </form>


        {% else %}
BAIRE Anthony's avatar
typo    
BAIRE Anthony committed
168
          <p class="mt-3">In order to run a job you need to be <a href="{% url 'account_login' %}" title="Sign in on A||Go">identified</a>
169
170
171
172
173
174
          or <a href="{% url 'account_signup' %}" title="Sign up on A||Go">register a new account</a>.</p>
        {% endif %}
        </div>

        <div class="tab-pane" id="api">
          <p class="mt-3">The following curl command will create a job:</p>
175
176
          <div class="row">
            <div class="col-11">
177
178
              <pre><code class="lang-bash"># create a job for this app with the ID {{ webapp.id }}
{{ job_create_cmd | command_multiline }}</code></pre>
179
180
181
182
183
            </div>
            <div class="col">
              <button 
                 class="btn btn-primary js-copy"
                 data-toggle="tooltip"
184
                 data-copy="{{ job_create_cmd | command_oneline }}"
185
186
187
188
                 data-placement="top"
                 title="Copy to clipboard" type="button"><i class="fas fa-clipboard"></i><span class="text-hide">Copy to clipboard</span></button>
            </div>
          </div>
189
    
190
          <p>Checkout the result:</p>
191
192
          <div class="row">
            <div class="col-11">
193
              <pre><code class="lang-bash">{{ job_result_cmd | command_multiline }}</code></pre>
194
            </div>
BERJON Matthieu's avatar
BERJON Matthieu committed
195

196
197
198
199
            <div class="col">
              <button 
                 class="btn btn-primary js-copy"
                 data-toggle="tooltip"
200
                 data-copy="{{ job_result_cmd | command_oneline }}"
201
202
203
204
                 data-placement="top"
                 title="Copy to clipboard" type="button"><i class="fas fa-clipboard"></i><span class="text-hide">Copy to clipboard</span></button>
            </div>
          </div>
205
        </div>
BERJON Matthieu's avatar
BERJON Matthieu committed
206

207
208
209
210
211
212
213
214
        {% if webapp.notebook_gitrepo %}
        <div class="tab-pane" id="notebook">
          <p class="mt-3">A Jupyter notebook is available to try the application online. You can
          launch it <a href="/jupyter?repo={{ webapp.notebook_gitrepo }}" title="Jupyter notebook">using this link</a>.</p>
          <p class="small text-muted">If you don't know what Jupyter is, you can <a href="https://jupyter.org/" title="Project Jupyter">visit their website</a>.</p>
        </div>
        {% endif %}
      </div>
215

BERJON Matthieu's avatar
BERJON Matthieu committed
216
217
218
    </div>
  </div>
</div>
219
{% endblock %}
BERJON Matthieu's avatar
BERJON Matthieu committed
220

221
222
223
224
225
226
227
228
229
230
231
232
233
{% block messages %}
{{ block.super }}
{% for field in form %}
  {% for error in field.errors %}
  <div class="alert alert-danger alert-dismissible fade show" role="alert">
    <div class="container">{{ error|escape }}</div>
      <button type="button" class="close" data-dismiss="alert" aria-label="Close">
        <span aria-hidden="true">&times;</span>
      </button>
    </div>
  {% endfor %}
{% endfor %}
{% endblock %}
BERJON Matthieu's avatar
BERJON Matthieu committed
234
235
236
237

{% block javascript %}
{{ block.super }}
<script defer src="{% static 'js/tooltip.js' %}"></script>
238
<script defer src="{% static 'js/copy.js' %}"></script>
BAIRE Anthony's avatar
BAIRE Anthony committed
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
              <script>
function list_filenames_in_next_elt(elt)
{
    let files = $.map( elt.files, function(v){ return v.name; } );
    $(elt).next()[0].value = files.join(",");
}

{
/* == File chooser - to allow selection of file from different directories ==
 * closure to reduce to scope of variables.
 * i_btn   : counter used to define ids.
 *
 * The file-chooser is composed of those elements :
 * span
 *   - label, used as button to activate the input-file
 *   - input type file, hidden.
 *   - input type text, used to display the selected files.
 * This seems to be quite "classical" management of input-file when style is involved.
 *  https://www.quirksmode.org/dom/inputfile.html
 *  https://buzut.net/customisez-le-input-file/
 *  https://www.creativejuiz.fr/blog/tutoriels/input-file-personnalise-css-js
 *
 * Here we clone the first span element, update ids
 * and insert the new span right before the small help text line.
 */
    let i_btn = 2;

    function add_input_file(span_elt)
    {
        let new_span = $(span_elt).clone(false);
        let new_id   = "input-file0"+i_btn;

        new_span.children('label')
                    .prop("for", new_id);
        inputs = new_span.children('input');
        inputs[0].id    = new_id;
        inputs[1].value = '';

        ++i_btn;

        let last_small = $(span_elt).parent().children('small').last();
        last_small.before(new_span);
    }

} // == File chooser

              </script>
BERJON Matthieu's avatar
BERJON Matthieu committed
286
{% endblock %}