diff --git a/jupyterhub_custom_config.yaml b/jupyterhub_custom_config.yaml index 9075ce77f6e3257d022bd88949d22c2e299df0f8..1841b8386e613c925f0e8ba3ac25f5073d3fc1ab 100644 --- a/jupyterhub_custom_config.yaml +++ b/jupyterhub_custom_config.yaml @@ -196,7 +196,10 @@ selfapihandler: services: JupyterLab: frontend: - key: "jupyterlab" + versionsSelect: + tab: "labconfig" + key: "versioncfg" + defaultValue: "4.2" navsidebar: - labconfig: show: true @@ -228,13 +231,11 @@ services: label: type: text value: "Versionss" - onChangeUpdateKeys: + onChangeUpdate: - system - type: hr allowedGroups: - default - optionsName: Version - defaultOption: 4.2 options: "4.2": name: "JupyterLab - 4.2" @@ -370,6 +371,8 @@ services: label: type: text value: "System--:" + onChangeUpdate: + - account - key: account show: true type: dropdown @@ -379,6 +382,8 @@ services: label: type: text value: "Account" + onChangeUpdate: + - project - key: project show: true type: dropdown @@ -388,6 +393,8 @@ services: label: type: text value: "Project" + onChangeUpdate: + - partition - key: partition show: true type: dropdown diff --git a/static/js/custom.js b/static/js/custom.js new file mode 100644 index 0000000000000000000000000000000000000000..6bf44cbe952e7553f746eb96cc4a919166f47257 --- /dev/null +++ b/static/js/custom.js @@ -0,0 +1,15 @@ +define(["jquery"], function ( + $ +) { + "use strict"; + + const functions = { + get_hpc_system + }; + + function get_hpc_system(software_key, tab_key, input_key, values) { + const systems = ["JUWELS", "JURECA", "JEDI", "JUSUF", "DEEP", "JSC-Cloud"]; + return systems; + } + return functions; +}) diff --git a/static/js/home/utils.js b/static/js/home/utils.js index 4ed692dd634f32285034e51db21a5b9e060019e8..02c3a64fa93ac7a749c09b0c089b975dd2d362da 100644 --- a/static/js/home/utils.js +++ b/static/js/home/utils.js @@ -53,7 +53,23 @@ define(["jquery", "jhapi",], function ( return id; } + var getSpecificValuesInTab = function(id, prefix) { + const values = {}; + $(`[id^="${id}"]`).filter('select, input').each(function() { + const id = $(this).attr('id'); + const suffixLength = $(this).prop("tagName").length + 1; + const key = id.substring(prefix.length, id.length - suffixLength); + if ($(this).is(':checkbox')) { + values[key] = $(this).is(':checked'); // Checkbox value + } else { + values[key] = $(this).val(); // Standard value + } + }); + return values; + } + var getLabConfigSelectValues = function (id) { + return { "service": $(`select#${id}-version-select`).val(), "system": $(`select#${id}-system-select`).val(), @@ -249,6 +265,7 @@ define(["jquery", "jhapi",], function ( var utils = { parseJSON: parseJSON, getId: getId, + getSpecificValuesInTab: getSpecificValuesInTab, getLabConfigSelectValues: getLabConfigSelectValues, setLabAsNA: setLabAsNA, setSpawnActive: setSpawnActive, diff --git a/templates/home.html b/templates/home.html index cf60188ecf2d6ed5f8885ffb99adb24afdd013f5..dde057e4a62346b6522265dc406c821c3123e7a3 100644 --- a/templates/home.html +++ b/templates/home.html @@ -1,5 +1,4 @@ {%- extends "page.html" -%} -{%- import "macros/custom.jinja" as custom -%} {%- import "macros/home.jinja" as home -%} {%- import "macros/svgs.jinja" as svg -%} @@ -332,19 +331,17 @@ require(["jquery", "jhapi", "home/utils", "home/dropdown-options", "home/lab-con } updateSpawnProgress(); -#} - {# For new labs, only the first option has to be - updated manually. All other updates will be triggered - via onChange and set default values. -#} - - {# let select = $("#jupyterlab-new-4.2-labconfig-versioncfg-select"); #} - let select = $("select[id*=versioncfg]"); - {# TODO -> use defaultOption of this software - -> trigger next changes via config #} - console.log(select); - select.val("4.2"); + {# Set initial value, which will trigger to fill other dropdowns #} + const defaultOptionTab = "{{ custom_config.get("services", {}).get(software_key, {}).get("frontend", {}).get("versionsSelect", {}).get("tab", "") }}"; + const defaultOptionKey = "{{ custom_config.get("services", {}).get(software_key, {}).get("frontend", {}).get("versionsSelect", {}).get("key", "") }}"; + const defaultOptionValue = "{{ custom_config.get("services", {}).get(software_key, {}).get("frontend", {}).get("versionsSelect", {}).get("defaultValue", "") }}"; + let select = $(`select[id*=${defaultOptionTab}-${defaultOptionKey}]`); + {%- for versionName, versionOptions in custom_config.get("services", {}).get(software_key, {}).get("options", {}).items() %} + select.append(`<option value="{{versionName}}">{{versionOptions.get("name", versionName)}}</option>`); + {%- endfor %} + select.val(defaultOptionValue); select.trigger("change"); - console.log(select); - console.log(select.val()); + {# dropdowns.updateServices("{{ software_key }}", "{{ software }}-{{ new }}"); #} {# $("#{{ software }}-{{ new }}-log-select").prepend(`<option value="latest">latest</option>`); #} diff --git a/templates/macros/custom.jinja b/templates/macros/custom.jinja deleted file mode 100644 index 37024bcdc39a6f06a10032f8e4418f19bbcbeba7..0000000000000000000000000000000000000000 --- a/templates/macros/custom.jinja +++ /dev/null @@ -1,121 +0,0 @@ -{%- import "macros/svgs.jinja" as svg -%} - -{%- macro nav_default_env_kernel(id, custom_config, kernel_set) -%} -{%- for kernel, options in custom_config.get("userModules", {}).get("kernels", {}).items() %} - {%- if kernel_set in options.get("sets", []) %} - <div id="{{id}}-{{kernel}}-cb-div" class="form-check col-sm-6 col-md-4 col-lg-3"> - <input type="checkbox" class="form-check-input" id="{{id}}-{{kernel}}-check" value="{{kernel}}" {% if options.get("default", false) %} checked {% endif %}> - <label class="form-check-label" for="{{id}}-{{kernel}}-check"> - <span class="align-middle">{{options.displayName}}</span> - <a href="{{options.href}}" target="_blank" class="module-info text-muted ms-3"> - <span>{{ svg.info_svg | safe }}</span> - <div class="module-info-link-div d-inline-block"> - <span class="module-info-link" id="{{kernel}}-info-link"> - {{ svg.link_svg | safe }} - </span> - </div> - </a> - </label> - </div> - {%- endif %} -{%- endfor %} -{%- endmacro -%} - -{%- macro nav_default_env_extensions(id, custom_config, extension_set) -%} -<p>Extensions: {{id}}</p> -{%- endmacro -%} - -{%- macro nav_default_env_proxies(id, custom_config, proxies_set) -%} -<p>Proxies: {{id}}</p> -{%- endmacro -%} - -{%- macro nav_default_env_selectall(id, custom_config) -%} -<p>Select All: {{id}}</p> -{%- endmacro -%} - -{%- macro nav_default_env_selectall_script(id, custom_config) -%} -<p>Select All Script: {{id}}</p> -{%- endmacro -%} - -{%- macro get_default_env_runtime(id, custom_config) -%} -<p>Runtime: {{id}}</p> -{%- endmacro -%} - -{%- macro get_default_env_runtime_label(id, custom_config) -%} -<p>Runtime Label: {{id}}</p> -{%- endmacro -%} - -{%- macro get_default_env_gpus(id, custom_config) -%} -<p>GPUs: {{id}}</p> -{%- endmacro -%} - -{%- macro get_default_env_gpus_label(id, custom_config) -%} -<p>GPUs Label: {{id}}</p> -{%- endmacro -%} - -{%- macro get_default_env_xserver(id, custom_config) -%} -<p>XServer: {{id}}</p> -{%- endmacro -%} - -{%- macro get_default_env_xserver_label(id, custom_config) -%} -<p>XServer Label: {{id}}</p> -{%- endmacro -%} - -{%- macro get_version(id, custom_config) -%} -<p>Version: {{id}}</p> -{%- endmacro -%} - -{%- macro get_hpc_system(id, custom_config) -%} -<p>HPC System: {{id}}</p> -{%- endmacro -%} - -{%- macro get_hpc_account(id, custom_config) -%} -<p>HPC Account: {{id}}</p> -{%- endmacro -%} - -{%- macro get_hpc_project(id, custom_config) -%} -<p>HPC Project: {{id}}</p> -{%- endmacro -%} - -{%- macro get_hpc_partition(id, custom_config) -%} -<p>HPC Partition: {{id}}</p> -{%- endmacro -%} - -{%- macro get_hpc_reservation(id, custom_config) -%} -<p>HPC Reservation: {{id}}</p> -{%- endmacro -%} - -{%- macro get_hpc_reservationsummary(id, custom_config) -%} -<p>HPC Reservation Summary: {{id}}</p> -{%- endmacro -%} - -{%- macro get_hpc_flavor(id, custom_config) -%} -<p>HPC Flavor: {{id}}</p> -{%- endmacro -%} - -{%- macro get_hpc_flavorsummary(id, custom_config) -%} -<p>HPC Flavor Summary: {{id}}</p> -{%- endmacro -%} - -{% set values_funcs = { - "nav_default_env_kernel": nav_default_env_kernel, - "nav_default_env_extensions": nav_default_env_extensions, - "nav_default_env_proxies": nav_default_env_proxies, - "nav_default_env_selectall": nav_default_env_selectall, - "nav_default_env_selectall_script": nav_default_env_selectall_script, - "get_default_env_runtime": get_default_env_runtime, - "get_default_env_runtime_label": get_default_env_runtime_label, - "get_default_env_gpus": get_default_env_gpus, - "get_default_env_gpus_label": get_default_env_gpus_label, - "get_default_env_xserver": get_default_env_xserver, - "get_default_env_xserver_label": get_default_env_xserver_label, - "get_version": get_version, - "get_hpc_system": get_hpc_system, - "get_hpc_account": get_hpc_account, - "get_hpc_project": get_hpc_project, - "get_hpc_partition": get_hpc_partition, - "get_hpc_reservation": get_hpc_reservation, - "get_hpc_reservationsummary": get_hpc_reservationsummary, - "get_hpc_flavor": get_hpc_flavor, - "get_hpc_flavorsummary": get_hpc_flavorsummary -} %} diff --git a/templates/macros/home.jinja b/templates/macros/home.jinja index b1c6ba7913268b259861c57c79e7384d7b6b9bca..be375fc6be18e473a277bb095b5e2b10fb8ff097 100644 --- a/templates/macros/home.jinja +++ b/templates/macros/home.jinja @@ -172,36 +172,43 @@ {%- for version_name, version_options in custom_config.services.get(software_key, {}).get("options", {}).items() %} {%- for nav_item in custom_config.services.get(software_key, {}).get("frontend", {}).get("navsidebar", []) %} {%- set counter = loop.index0 -%} - {%- for key in nav_item.keys() %} - {%- set _id = id ~ "-" ~ version_name ~ "-" ~ key %} + {%- for tab_key in nav_item.keys() %} + {%- set _id = id ~ "-" ~ version_name ~ "-" ~ tab_key %} <div class="{% if counter > 0 %}d-none{% endif %} tab-pane fade show active" id="{{ _id }}" role="tabpanel"> <form id="{{ _id }}-form"> {# This blocks comes from the software.frontend configuration and is added to all versions #} - {%- for tabOption in custom_config.services.get(software_key, {}).get("frontend", {}).get("tabs", {}).get(key, []) %} + {%- for tabOption in custom_config.services.get(software_key, {}).get("frontend", {}).get("tabs", {}).get(tab_key, []) %} + {%- if tabOption.show is boolean %} + {%- set show = tabOption.show %} + {%- else %} + {%- set show = false %} + {%- endif %} {%- if tabOption.type == "inputtext" %} - {{ inputs.create_text_input_2(_id ~ "-" ~ tabOption.key, tabOption.options, tabOption.label, true ) }} + {{ inputs.create_text_input_2(_id, software_key, tab_key, tabOption.key, tabOption.options, tabOption.get("label", {}), show ) }} {%- elif tabOption.type == "dropdown" %} - {{ inputs.create_select_2(_id ~ "-" ~ tabOption.key, tabOption.options, tabOption.label, true ) }} + {{ inputs.create_select_2(_id, software_key, tab_key, tabOption.key, tabOption.options, tabOption.get("label", {}), true ) }} {%- elif tabOption.type == "hr" %} <hr> {%- endif %} {%- endfor %} - - {# This block is specific for each version of the software - In the end we can simply show the right div and hide the others #} - {%- for tabOption in version_options.get("frontend", {}).get("tabs", {}).get(key, {}).get("options", []) %} - {%- if tabOption.type == "dropdown" %} - {{ inputs.create_select_2(_id ~ "-" ~ tabOption.key, tabOption.options, tabOption.label, false ) }} - {%- elif tabOption.type == "flavorsummary" %} - {{ create_flavor_summary(_id ~ "-" ~ tabOption.key, tabOption.options, false ) }} - {%- elif tabOption.type == "number" %} - {{ inputs.create_number_input_2(_id ~ "-" ~ tabOption.key, tabOption.options, tabOption.label, false ) }} - {%- elif tabOption.type == "reservationsummary" %} - {{ create_reservation_summary(_id ~ "-" ~ tabOption.key, false) }} - {%- elif tabOption.type == "multiple_checkboxes" %} - {{ inputs.create_multiple_checkboxes(_id ~ "-" ~ tabOption.key, tabOption.options, tabOption.label, custom_config, false ) }} - {%- endif %} - {%- endfor %} + {# Version specific #} + <div id={{ _id }}-specific> + {# This block is specific for each version of the software + In the end we can simply show the right div and hide the others #} + {%- for tabOption in version_options.get("frontend", {}).get("tabs", {}).get(tab_key, {}).get("options", []) %} + {%- if tabOption.type == "dropdown" %} + {{ inputs.create_select_2(_id, software_key, tab_key, tabOption.key, tabOption.options, tabOption.label, true ) }} + {%- elif tabOption.type == "flavorsummary" %} + {{ create_flavor_summary(_id, software_key, tab_key, tabOption.key, tabOption.options, true ) }} + {%- elif tabOption.type == "number" %} + {{ inputs.create_number_input_2(_id, software_key, tab_key, tabOption.key, tabOption.options, tabOption.label, true ) }} + {%- elif tabOption.type == "reservationsummary" %} + {{ create_reservation_summary(_id, software_key, tab_key, tabOption.key, true) }} + {%- elif tabOption.type == "multiple_checkboxes" %} + {{ inputs.create_multiple_checkboxes(_id, software_key, tab_key, tabOption.key, tabOption.options, tabOption.label, custom_config, true ) }} + {%- endif %} + {%- endfor %} + </div> </form> {{ create_lab_config_buttons_2(_id, add_save_reset_buttons=true) }} {#- {{ create_lab_config_buttons(id, id == new_lab_id or share_structure) }} #} @@ -242,26 +249,26 @@ </div> {%- endmacro %} -{%- macro create_reservation_summary(id, show) %} -<div id="{{id}}-reservation-info-div" class="row mb-3{% if not show %} d-none{% endif %}"> +{%- macro create_reservation_summary(id, software_key, tab_key, input_key, show) %} +<div id="{{id}}-{{input_key}}-reservation-info-div" class="row mb-3{% if not show %} d-none{% endif %}"> {%- set reservation_info_classes = "col-4 fw-bold"%} - <div id="{{id}}-reservation-info" class="col-8 offset-4"> + <div id="{{id}}-{{input_key}}-reservation-info" class="col-8 offset-4"> <div class="row"> <span class="{{ reservation_info_classes }}">Start Time:</span> - <span id="{{id}}-reservation-start" class="col-auto"></span> + <span id="{{id}}-{{input_key}}-reservation-start" class="col-auto"></span> </div> <div class="row"> <span class="{{ reservation_info_classes }}">End Time:</span> - <span id="{{id}}-reservation-end" class="col-auto"></span> + <span id="{{id}}-{{input_key}}-reservation-end" class="col-auto"></span> </div> <div class="row"> <span class="{{ reservation_info_classes }}">State:</span> - <span id="{{id}}-reservation-state" class="col-auto"></span> + <span id="{{id}}-{{input_key}}-reservation-state" class="col-auto"></span> </div> <div class="mt-1"> <details> <summary class="fw-bold">Detailed reservation information:</summary> - <pre id="{{id}}-reservation-details"></pre> + <pre id="{{id}}-{{input_key}}-reservation-details"></pre> {#- TODO: Fix horizontal width upon expanding the detail #} </details> </div> @@ -269,8 +276,8 @@ </div> {%- endmacro %} -{%- macro create_flavor_summary(id, options, show) -%} -<div id="{{id}}-flavor-legend-div" class="row align-items-center g-0 mt-4{% if not show %} d-none{% endif %}"> +{%- macro create_flavor_summary(id, software_key, tab_key, input_key, options, show) -%} +<div id="{{id}}-{{input_key}}-flavor-legend-div" class="row align-items-center g-0 mt-4{% if not show %} d-none{% endif %}"> <span class="col-4 fw-bold">{{ options.text }}</span> <div class="col d-flex align-items-center ms-2"> {%- set box_style = "height: 15px; width: 15px; border-radius: 0.25rem;"%} @@ -284,7 +291,7 @@ <span class="ms-1">= Limit exceeded</span> </div> </div> -<div id="{{id}}-flavor-info-div" class="mb-3"></div> +<div id="{{id}}-{{input_key}}-flavor-info-div" class="mb-3"></div> {%- endmacro %} {%- macro create_lab_config_buttons_2(id, add_save_reset_buttons=true) -%} diff --git a/templates/macros/inputs.jinja b/templates/macros/inputs.jinja index 3e9e431ee2d109ab124be57f7d39f867541bb5a6..87ef43c2adfc23e5e0eeea037360bf70f073f192 100644 --- a/templates/macros/inputs.jinja +++ b/templates/macros/inputs.jinja @@ -1,52 +1,53 @@ {%- import "macros/svgs.jinja" as svg -%} -{%- import "macros/custom.jinja" as custom -%} -{%- macro create_label(id, label) -%} - <label for="{{id}}-input" class="col-4 col-form-label"> - {%- if label.type == "text" %} - {%- if label.value is string %} - {{ label.value }} +{%- macro create_label(id, software_key, tab_key, input_key, label) -%} + {%- if label %} + <label for="{{id}}-{{input_key}}-input" class="col-4 col-form-label"> + {%- if label.type == "text" %} + {%- if label.value is string %} + {{ label.value }} + {%- endif %} + {%- elif label.type == "texticon" %} + <a class="lh-1 ms-3" style="padding-top: 1px;" + data-bs-toggle="tooltip" data-bs-placement="right" data-bs-html="true" + title="{{ label.icontext }}"> + {{ svg.info_svg | safe }} + </a> + {%- elif label.type == "texticonclick" %} + <button type="button" class="btn" + data-bs-toggle="tooltip" data-bs-placement="right" data-bs-html="true" + title="{{ label.icontext }}"> + {{ svg.info_svg | safe }} + <span class="text-muted" style="font-size: smaller">(click me)</span> + </button> + {%- elif label.type == "textdropdown" %} + {%- elif label.type == "textcheckbox" %} + {%- if label.value is string %} + {{ label.value }} + {%- endif %} + <input type="checkbox" class="form-check-input" id="{{id}}-{{input_key}}-cb-input" value="None" {% if label.options.get("default", false) %}checked{% endif %}> + {%- elif label.type == "dropdown" %} + {%- elif label.type == "function" %} + {# This will require an update of the label, depending on the value of other this or other inputs + The label may come with a default text #} + {%- if label.value is string %} + {{ label.value }} + {%- endif %} + {%- elif label.type == "header" %} + <h4>{{ label.value }}</h4> {%- endif %} - {%- elif label.type == "texticon" %} - <a class="lh-1 ms-3" style="padding-top: 1px;" - data-bs-toggle="tooltip" data-bs-placement="right" data-bs-html="true" - title="{{ label.icontext }}"> - {{ svg.info_svg | safe }} - </a> - {%- elif label.type == "texticonclick" %} - <button type="button" class="btn" - data-bs-toggle="tooltip" data-bs-placement="right" data-bs-html="true" - title="{{ label.icontext }}"> - {{ svg.info_svg | safe }} - <span class="text-muted" style="font-size: smaller">(click me)</span> - </button> - {%- elif label.type == "textdropdown" %} - {%- elif label.type == "textcheckbox" %} - {%- if label.value is string %} - {{ label.value }} - {%- endif %} - <input type="checkbox" class="form-check-input" id="{{id}}-cb-input" value="None" {% if label.options.get("default", false) %}checked{% endif %}> - {%- elif label.type == "dropdown" %} - {%- elif label.type == "function" %} - {# This will require an update of the label, depending on the value of other this or other inputs - The label may come with a default text #} - {%- if label.value is string %} - {{ label.value }} - {%- endif %} - {%- elif label.type == "header" %} - <h4>{{ label.value }}</h4> - {%- endif %} - </label> + </label> + {%- endif %} {%- endmacro -%} -{%- macro create_label_scripts(id, label) -%} +{%- macro create_label_scripts(id, software_key, tab_key, input_key, label) -%} {%- if label.type == "textcheckbox" %} {# I think it's reasonable to put the logic for this checkbox in here #} <script type="text/javascript"> - const checkbox = document.getElementById('{{id}}-cb-input'); + const checkbox = document.getElementById('{{id}}-{{input_key}}-cb-input'); function toggleNumberInput() { - document.getElementById('{{id}}-input').disabled = !checkbox.checked; + document.getElementById('{{id}}-{{input_key}}-input').disabled = !checkbox.checked; } checkbox.addEventListener('change', toggleNumberInput); @@ -58,95 +59,126 @@ {%- endif %} {%- endmacro -%} -{%- macro create_text_input_2(id, options, label, show) -%} +{%- macro create_text_input_2(id, software_key, tab_key, input_key, options, label, show) -%} {#- Macro to create a text input #} {#- We use a different margin than the other input elements since the warning text will already create a margin.#} -<div id="{{id}}-input-div" class="row mb-1 {% if not show %}d-none{% endif %}"> - {{ create_label(id, label) }} +<div id="{{id}}-{{input_key}}-input-div" class="row mb-1 {% if not show %}d-none{% endif %}"> + {{ create_label(id, software_key, tab_key, input_key, label) }} <div class="col-8"> - <input type="text" class="form-control" id="{{id}}-input" - {% if options.placeholder -%} placeholder="{{options.placeholder}}" {%- endif %} {% if options.pattern -%} pattern={{options.pattern}} {%- endif %}> + <input type="text" class="form-control" id="{{id}}-{{input_key}}-input" + {% if options.placeholder -%} placeholder="{{options.placeholder}}" {%- endif %} + {% if options.pattern -%} pattern={{options.pattern}} {%- endif %} + {% if options.value is defined -%} value="{{ options.value }}" {%- endif %}> <div class="invalid-feedback">{{ warning }}</div> </div> </div> -{{ create_label_scripts(id, label) }} +{{ create_label_scripts(id, software_key, tab_key, input_key, label) }} {%- endmacro -%} -{%- macro create_password_input(id, key, label="", placeholder="", pattern="", warning="", persistent_hover=False) -%} -{#- Macro to create a password input field #} -{%- set key = key.lower() %} -<div id="{{id}}-{{key}}-input-div" class="row mb-1"> - <label for="{{id}}-{{key}}-input" class="col-4 col-form-label"> - {{ label if label else key.capitalize() }} - </label> - <div class="col-8"> - <div class="input-group"> - <input type="password" class="form-control" id="{{id}}-{{key}}-input" - placeholder="{{placeholder}}" {% if pattern -%} pattern={{pattern}} {%- endif %}> - <span class="input-group-append"> - <button class="btn btn-light" type="button" id="{{id}}-view-password"> - <i id="{{id}}-password-eye" class="fa fa-eye" aria-hidden="true"></i> - </button> - </span> - <div class="invalid-feedback">{{ warning }}</div> - </div> - </div> -</div> -{%- endmacro -%} -{%- macro create_password_input_2(id, options, label, show) -%} -<div id="{{id}}-input-div" class="row mb-1{% if not show %} d-none{% endif %}"> - {{ create_label(id, label) }} + +{%- macro create_password_input_2(id, software_key, tab_key, input_key, options, label, show) -%} +<div id="{{id}}-{{input_key}}-input-div" class="row mb-1{% if not show %} d-none{% endif %}"> + {{ create_label(id, software_key, tab_key, input_key, label) }} <div class="col-8"> <div class="input-group"> - <input type="password" class="form-control" id="{{id}}-input" + <input type="password" class="form-control" id="{{id}}-{{input_key}}-input" placeholder="{{ tabOption.get("placeholder", "") }}" {% if tabOption.pattern -%} pattern={{ tabOption.pattern }} {%- endif %}> <span class="input-group-append"> - <button class="btn btn-light" type="button" id="{{id}}-view-password"> - <i id="{{id}}-password-eye" class="fa fa-eye" aria-hidden="true"></i> + <button class="btn btn-light" type="button" id="{{id}}-{{input_key}}-view-password"> + <i id="{{id}}-{{input_key}}-password-eye" class="fa fa-eye" aria-hidden="true"></i> </button> </span> <div class="invalid-feedback">{{ warning }}</div> </div> </div> </div> -{{ create_label_scripts(id,label) }} +{{ create_label_scripts(id, software_key, tab_key, input_key, label) }} {%- endmacro -%} -{%- macro create_select_2(id, options, label, show) -%} -<div id="{{id}}-select-div" class="row mb-3{% if not show %} d-none{% endif %}"> - {{ create_label(id, label) }} +{%- macro create_select_2(id, software_key, tab_key, input_key, options, label, show) -%} +<div id="{{id}}-{{input_key}}-select-div" class="row mb-3{% if not show %} d-none{% endif %}"> + {{ create_label(id, software_key, tab_key, input_key, label) }} <div class="col-8"> - <select id="{{id}}-select" class="form-select" required> - <option value="{{id}}">{{id}}</option> - <option value="{{id}}">{{id[-9:]}}</option> - {% if id[-10:] == "versioncfg" %} - <option value="4.2">JupyterLab - 4.2</option> - {% endif %} + <select id="{{id}}-{{input_key}}-select" class="form-select" required> </select> <div class="invalid-feedback">{{ options.get("invalidFeedback", "Input required") }}</div> </div> </div> -{{ create_label_scripts(id, label) }} -{{ create_select_onChange_scripts(id, options) }} +{{ create_label_scripts(id, software_key, tab_key, input_key, label) }} +{{ create_select_onChange_scripts(id, software_key, tab_key, input_key, options) }} {%- endmacro -%} -{%- macro create_select_onChange_scripts(id, options) -%} +{%- macro create_select_onChange_scripts(tab_id, software_key, tab_key, input_key, options) -%} + <script> - require(["jquery", "/static/js/home/utils.js", "/static/js/home/dropdown-options.js"], function ( + require(["jquery", "custom", "/static/js/home/utils.js", "/static/js/home/dropdown-options.js"], function ( $, + custom, utils, dropdowns ) { "use strict"; - const escapedId = "{{ id }}".replace(/\./g, '\\.'); + const id = "{{ tab_id }}".replace(/\./g, '\\.'); + const prefix = "{{ tab_id }}-"; - $("select[id^=" + escapedId + "]").change(function () { + $(`select[id*="${id}-{{input_key}}"]`).change(function () { {# const values = utils.getLabConfigSelectValues(id); #} - console.log("change"); + const values = utils.getSpecificValuesInTab(id, prefix); + + const serviceInfo = getServiceInfo(); + const softwareKey = "{{ software_key }}"; + const myTab = "{{ tab_key }}"; + const myKey = "{{ input_key }}"; + + const versionTab = serviceInfo[softwareKey]?.frontend?.versionsSelect?.tab || ""; + const versionKey = serviceInfo[softwareKey]?.frontend?.versionsSelect?.key || ""; + const version = values[versionKey] || ""; + + const toUpdateSoftwareGeneric = serviceInfo?.[softwareKey]?.frontend?.tabs?.[myTab] || []; + const toUpdateSoftwareSpecific = serviceInfo?.[softwareKey]?.options?.[version]?.frontend?.tabs?.[myTab]?.options || []; + const toUpdateKeys = [...toUpdateSoftwareGeneric, ...toUpdateSoftwareSpecific] + .filter(element => element.key === myKey) + ?. [0]?.onChangeUpdate || []; + + console.log(toUpdateKeys); + toUpdateKeys.forEach(inputKeyToUpdate => { + {# Let's get the function we have to use, to get the values we have to add. + From the generic configuration + from the specific configuration. They will be applied both. #} + const toUpdateSoftwareGeneric = serviceInfo?.[softwareKey]?.frontend?.tabs?.[myTab] || []; + const toUpdateSoftwareSpecific = serviceInfo?.[softwareKey]?.options?.[version]?.frontend?.tabs?.[myTab]?.options || []; + const toUpdateInfos = [...toUpdateSoftwareGeneric, ...toUpdateSoftwareSpecific] + .filter(element => element.key === inputKeyToUpdate) + ?.[0] || {}; + const toUpdateType = toUpdateInfos?.type || ""; + const toUpdateOptions = toUpdateInfos?.options || {}; + const funcToCall = toUpdateOptions?.values_func || ""; + + if ( toUpdateType === "dropdown" ) { + let select = $(`select[id*=${id}-${inputKeyToUpdate}]`); + console.log(custom); + console.log(funcToCall); + if (funcToCall in custom) { + const toAdd = custom[funcToCall](softwareKey, myTab, myKey, values) || []; + if (toAdd.length > 0) { + dropdowns.resetInputElement(select); + toAdd.forEach(item => { + select.append(`<option value="${item}">${item}</option>`); + }); + select.val(toAdd[0]); + select.trigger("change"); + } else { + console.log("Function " + funcToCall +" returned an empty list. Do not update "+ inputKeyToUpdate); + } + } else { + console.log("Function " + funcToCall + " has to be defined in custom.js - Otherwise "+ inputKeyToUpdate +" can't be updated."); + } + } + }); + {# if (!$(this).hasClass("no-update")) { try { dropdowns.updateSystems(id, values.service); @@ -167,67 +199,24 @@ since the warning text will already create a margin.#} </script> {%- endmacro -%} -{%- macro create_number_input_2(id, options, label, show) -%} -<div id="{{id}}-input-div" class="row mb-3{% if not show %} d-none{% endif %}"> {# style="display: none; #} - {{ create_label(id, label) }} +{%- macro create_number_input_2(id, software_key, tab_key, input_key, options, label, show) -%} +<div id="{{id}}-{{input_key}}-input-div" class="row mb-3{% if not show %} d-none{% endif %}"> {# style="display: none; #} + {{ create_label(id, software_key, tab_key, input_key, label) }} <div class="col-8"> - <input type="number" id="{{id}}-input" class="form-control" value="{{ options.get("default", -1)}}"> + <input type="number" id="{{id}}-{{input_key}}-input" class="form-control" value="{{ options.get("default", -1)}}"> {#- Set the warning message via JS for different min max values. #} <div class="invalid-feedback">{{ options.get("invalidFeedback", "Input required") }}</div> </div> </div> -{{ create_label_scripts(id, label) }} -{%- endmacro -%} - - - -{%- macro create_select(id, key, label="") -%} -{#- Macro to create an empty select which should be filled via JS. -#} -{%- set key = key.lower() %} -<div id="{{id}}-{{key}}-select-div" class="row mb-3"> - <label for="{{id}}-{{key}}-select" class="col-4 col-form-label">{{ label if label else key.capitalize() }}</label> - <div class="col-8"> - <select id="{{id}}-{{key}}-select" class="form-select" required> - </select> - <div class="invalid-feedback">Please choose a {{ key }}.</div> - {# {% if caller -%} {{ caller() }} {%- endif %} #} - </div> -</div> +{{ create_label_scripts(id, software_key, tab_key, input_key, label) }} {%- endmacro -%} -{%- macro create_number_input(id, key, label="") -%} -{%- set key = key.lower() %} -<div id="{{id}}-{{key}}-input-div" class="row mb-3"> {# style="display: none; #} - <label for="{{id}}-{{key}}-input" class="col-4 col-form-label">{{ label if label else key.capitalize() }}</label> - <div class="col-8"> - <input type="number" id="{{id}}-{{key}}-input" class="form-control" value="-1"> - {#- Set the warning message via JS for different min max values. #} - <div class="invalid-feedback"></div> - </div> -</div> -{%- endmacro -%} - -{%- macro create_checkbox_input(id, key, label="") -%} -{%- set key = key.lower() %} -<div id="{{id}}-{{key}}-input-div" class="row mb-3 align-items-center" style="display: none;"> - <label for="{{id}}-{{key}}-input" class="col-4 col-form-label">{{ label if label else key.capitalize() }}</label> - <div class="col-8"> - <input type="checkbox" class="form-check-input" id="{{id}}-{{key}}-input" value="None"> - </div> -</div> -{%- endmacro -%} - -{%- macro create_button(id, text) -%} -<button id="{{ id }}-{{ text }}-btn" type="button" class="btn btn-success me-2"> {{text}} </button> -{%- endmacro -%} - - -{%- macro create_multiple_checkboxes(id, options, label, custom_config, show) -%} +{%- macro create_multiple_checkboxes(id, software_key, tab_key, input_key, options, label, custom_config, show) -%} {#- User-selected Modules #} -<div id="{{ id }}-div" class="{% if not show %}d-none{% endif %}"> - {{ create_label(id, label) }} - <div id="{{ id }}-checkboxes-div" class="row g-0"> +<div id="{{ id }}-{{ input_key }}-div" class="{% if not show %}d-none{% endif %}"> + {{ create_label(id, software_key, tab_key, input_key, label) }} + <div id="{{ id }}-{{ input_key }}-checkboxes-div" class="row g-0"> {#{%- set func = custom.values_funcs.get(options.values_func) %} {%- if func %} {%- set args = [id, custom_config] + options.get("args", []) %}