diff --git a/static/images/2fa/jupyter-jsc_2fa_img01.png b/static/images/2fa/jupyter-jsc_2fa_img01.png deleted file mode 100644 index 27bc7a6164be17d97c232133ad919aceae99497b..0000000000000000000000000000000000000000 Binary files a/static/images/2fa/jupyter-jsc_2fa_img01.png and /dev/null differ diff --git a/static/images/2fa/jupyter-jsc_2fa_img02.png b/static/images/2fa/jupyter-jsc_2fa_img02.png deleted file mode 100644 index 0f9484e22a6510c76cd95b20e46042a184ceb358..0000000000000000000000000000000000000000 Binary files a/static/images/2fa/jupyter-jsc_2fa_img02.png and /dev/null differ diff --git a/static/images/2fa/jupyter-jsc_2fa_img03.png b/static/images/2fa/jupyter-jsc_2fa_img03.png deleted file mode 100644 index 81d2571d0f3ecafde4e0c6c5f86413ca819efe24..0000000000000000000000000000000000000000 Binary files a/static/images/2fa/jupyter-jsc_2fa_img03.png and /dev/null differ diff --git a/static/images/2fa/jupyter-jsc_2fa_img04-1.png b/static/images/2fa/jupyter-jsc_2fa_img04-1.png deleted file mode 100644 index 9e730fa0042b4206ff3771d09770d7a7c6e219ce..0000000000000000000000000000000000000000 Binary files a/static/images/2fa/jupyter-jsc_2fa_img04-1.png and /dev/null differ diff --git a/static/images/2fa/jupyter-jsc_2fa_img04.png b/static/images/2fa/jupyter-jsc_2fa_img04.png deleted file mode 100644 index adb1446bc3599361f32c34e0464206656179521b..0000000000000000000000000000000000000000 Binary files a/static/images/2fa/jupyter-jsc_2fa_img04.png and /dev/null differ diff --git a/static/images/2fa/jupyter-jsc_2fa_img05.png b/static/images/2fa/jupyter-jsc_2fa_img05.png deleted file mode 100644 index 8572a76adf3587a4646b3eb01b948b7adc97967d..0000000000000000000000000000000000000000 Binary files a/static/images/2fa/jupyter-jsc_2fa_img05.png and /dev/null differ diff --git a/static/images/2fa/jupyter-jsc_2fa_img06.png b/static/images/2fa/jupyter-jsc_2fa_img06.png deleted file mode 100644 index e80fd7f265e87467b3c4efadff0a1d07df4a52da..0000000000000000000000000000000000000000 Binary files a/static/images/2fa/jupyter-jsc_2fa_img06.png and /dev/null differ diff --git a/static/images/2fa/jupyter-jsc_2fa_short_img01.png b/static/images/2fa/jupyter-jsc_2fa_short_img01.png deleted file mode 100644 index b15e46e82570bced9b0da5334736e61026a98c37..0000000000000000000000000000000000000000 Binary files a/static/images/2fa/jupyter-jsc_2fa_short_img01.png and /dev/null differ diff --git a/static/images/2fa/jupyter-jsc_2fa_short_img02.png b/static/images/2fa/jupyter-jsc_2fa_short_img02.png deleted file mode 100644 index d6e9255d6e70e2a2f1d77d991c22ec19f43b2db8..0000000000000000000000000000000000000000 Binary files a/static/images/2fa/jupyter-jsc_2fa_short_img02.png and /dev/null differ diff --git a/static/images/footer/systems/deep.svg b/static/images/footer/systems/deep.svg new file mode 100644 index 0000000000000000000000000000000000000000..a822de445b5d84d15b45fc859927f886d526c1d0 --- /dev/null +++ b/static/images/footer/systems/deep.svg @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 141.73 141.73" style="enable-background:new 0 0 141.73 141.73;" xml:space="preserve"><script xmlns="" id="__gaOptOutExtension"/> +<style type="text/css"> + .st0{fill:#B9D25F;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st1{fill:#FAEB5A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st2{fill:#FAB45A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st3{fill:#808080;} + .st4{fill:#B9D25F;} + .st5{fill:#FAB45A;} + .st6{fill:#FF1D25;} + .st7{fill:#8C0000;} + .st8{fill:none;stroke:#7AC943;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st9{fill:#FFFFFF;} + .st10{fill:#7AC943;stroke:#7AC943;stroke-miterlimit:10;} +</style> +<g> + <path class="st3" d="M121.89,18H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h102.05 c3.13,0,5.67-2.54,5.67-5.67V23.67C127.56,20.54,125.02,18,121.89,18z M54.27,33.59c0,0.78-0.64,1.42-1.42,1.42H24.57 c-0.78,0-1.41-0.64-1.41-1.42v-2.83c0-0.79,0.63-1.42,1.41-1.42h28.28c0.78,0,1.42,0.63,1.42,1.42V33.59z"/> + <path class="st3" d="M121.89,56.69H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h55.72 c4.6-13.33,17.26-22.9,32.16-22.9c7.4,0,14.25,2.36,19.84,6.38v-6.16C127.56,59.23,125.02,56.69,121.89,56.69z M54.27,73.59 c0,0.78-0.64,1.42-1.42,1.42H24.57c-0.78,0-1.41-0.64-1.41-1.42v-2.83c0-0.79,0.63-1.42,1.41-1.42h28.28 c0.78,0,1.42,0.63,1.42,1.42V73.59z"/> + <path class="st3" d="M73.7,96.15c0-0.25,0-0.51,0.01-0.76H19.84c-3.13,0-5.67,2.53-5.67,5.66v17.01c0,3.13,2.54,5.67,5.67,5.67 H87.8C79.26,117.56,73.7,107.5,73.7,96.15z M54.27,110.98c0,0.78-0.64,1.41-1.42,1.41H24.57c-0.78,0-1.41-0.63-1.41-1.41v-2.84 c0-0.78,0.63-1.42,1.41-1.42h28.28c0.78,0,1.42,0.64,1.42,1.42V110.98z"/> +</g> +<g> + <path class="st10" d="M103.64,112.72c0-2.49,1.73-4.28,4.08-4.28c2.49,0,4.08,1.8,4.08,4.28c0,2.42-1.59,4.28-4.08,4.28 C105.3,117,103.64,115.14,103.64,112.72z M105.3,100.49l-0.83-28.33c-0.04-1.36,1.05-2.49,2.42-2.49h1.65 c1.36,0,2.46,1.13,2.42,2.49l-0.83,28.33c-0.04,1.31-1.11,2.35-2.42,2.35l0,0C106.41,102.84,105.34,101.8,105.3,100.49z"/> +</g> +</svg> \ No newline at end of file diff --git a/static/images/footer/systems/jedi.svg b/static/images/footer/systems/jedi.svg new file mode 100644 index 0000000000000000000000000000000000000000..fd54b621f76ea3ae6b46b9fbf3a1109dfeee75a6 --- /dev/null +++ b/static/images/footer/systems/jedi.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 141.73 141.73" style="enable-background:new 0 0 141.73 141.73;" xml:space="preserve"><script xmlns="" id="__gaOptOutExtension"/> +<style type="text/css"> + .st0{fill:#B9D25F;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st1{fill:#FAEB5A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st2{fill:#FAB45A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st3{fill:#808080;} + .st4{fill:#B9D25F;} + .st5{fill:#FAB45A;} + .st6{fill:#FF1D25;} + .st7{fill:#8C0000;} + .st8{fill:none;stroke:#7AC943;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st9{fill:#FFFFFF;} + .st10{fill:#7AC943;stroke:#7AC943;stroke-miterlimit:10;} +</style> +<g> + <path class="st3" d="M121.89,18H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h102.05 c3.13,0,5.67-2.54,5.67-5.67V23.67C127.56,20.54,125.02,18,121.89,18z M54.27,33.59c0,0.78-0.64,1.42-1.42,1.42H24.57 c-0.78,0-1.41-0.64-1.41-1.42v-2.83c0-0.79,0.63-1.42,1.41-1.42h28.28c0.78,0,1.42,0.63,1.42,1.42V33.59z"/> + <path class="st3" d="M121.89,56.69H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h55.72 c4.6-13.33,17.26-22.9,32.16-22.9c7.4,0,14.25,2.36,19.84,6.38v-6.16C127.56,59.23,125.02,56.69,121.89,56.69z M54.27,73.59 c0,0.78-0.64,1.42-1.42,1.42H24.57c-0.78,0-1.41-0.64-1.41-1.42v-2.83c0-0.79,0.63-1.42,1.41-1.42h28.28 c0.78,0,1.42,0.63,1.42,1.42V73.59z"/> + <path class="st3" d="M73.7,96.15c0-0.25,0-0.51,0.01-0.76H19.84c-3.13,0-5.67,2.53-5.67,5.66v17.01c0,3.13,2.54,5.67,5.67,5.67 H87.8C79.26,117.56,73.7,107.5,73.7,96.15z M54.27,110.98c0,0.78-0.64,1.41-1.42,1.41H24.57c-0.78,0-1.41-0.63-1.41-1.41v-2.84 c0-0.78,0.63-1.42,1.41-1.42h28.28c0.78,0,1.42,0.64,1.42,1.42V110.98z"/> +</g> +<polyline class="st8" points="90.14,95.96 100.35,112.97 125.29,81.22 "/> +</svg> \ No newline at end of file diff --git a/static/images/footer/systems/jsccloud.svg b/static/images/footer/systems/jsccloud.svg new file mode 100644 index 0000000000000000000000000000000000000000..fd54b621f76ea3ae6b46b9fbf3a1109dfeee75a6 --- /dev/null +++ b/static/images/footer/systems/jsccloud.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 141.73 141.73" style="enable-background:new 0 0 141.73 141.73;" xml:space="preserve"><script xmlns="" id="__gaOptOutExtension"/> +<style type="text/css"> + .st0{fill:#B9D25F;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st1{fill:#FAEB5A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st2{fill:#FAB45A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st3{fill:#808080;} + .st4{fill:#B9D25F;} + .st5{fill:#FAB45A;} + .st6{fill:#FF1D25;} + .st7{fill:#8C0000;} + .st8{fill:none;stroke:#7AC943;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st9{fill:#FFFFFF;} + .st10{fill:#7AC943;stroke:#7AC943;stroke-miterlimit:10;} +</style> +<g> + <path class="st3" d="M121.89,18H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h102.05 c3.13,0,5.67-2.54,5.67-5.67V23.67C127.56,20.54,125.02,18,121.89,18z M54.27,33.59c0,0.78-0.64,1.42-1.42,1.42H24.57 c-0.78,0-1.41-0.64-1.41-1.42v-2.83c0-0.79,0.63-1.42,1.41-1.42h28.28c0.78,0,1.42,0.63,1.42,1.42V33.59z"/> + <path class="st3" d="M121.89,56.69H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h55.72 c4.6-13.33,17.26-22.9,32.16-22.9c7.4,0,14.25,2.36,19.84,6.38v-6.16C127.56,59.23,125.02,56.69,121.89,56.69z M54.27,73.59 c0,0.78-0.64,1.42-1.42,1.42H24.57c-0.78,0-1.41-0.64-1.41-1.42v-2.83c0-0.79,0.63-1.42,1.41-1.42h28.28 c0.78,0,1.42,0.63,1.42,1.42V73.59z"/> + <path class="st3" d="M73.7,96.15c0-0.25,0-0.51,0.01-0.76H19.84c-3.13,0-5.67,2.53-5.67,5.66v17.01c0,3.13,2.54,5.67,5.67,5.67 H87.8C79.26,117.56,73.7,107.5,73.7,96.15z M54.27,110.98c0,0.78-0.64,1.41-1.42,1.41H24.57c-0.78,0-1.41-0.63-1.41-1.41v-2.84 c0-0.78,0.63-1.42,1.41-1.42h28.28c0.78,0,1.42,0.64,1.42,1.42V110.98z"/> +</g> +<polyline class="st8" points="90.14,95.96 100.35,112.97 125.29,81.22 "/> +</svg> \ No newline at end of file diff --git a/static/images/footer/systems/jupyter.svg b/static/images/footer/systems/jupyter.svg new file mode 100644 index 0000000000000000000000000000000000000000..fd54b621f76ea3ae6b46b9fbf3a1109dfeee75a6 --- /dev/null +++ b/static/images/footer/systems/jupyter.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 141.73 141.73" style="enable-background:new 0 0 141.73 141.73;" xml:space="preserve"><script xmlns="" id="__gaOptOutExtension"/> +<style type="text/css"> + .st0{fill:#B9D25F;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st1{fill:#FAEB5A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st2{fill:#FAB45A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st3{fill:#808080;} + .st4{fill:#B9D25F;} + .st5{fill:#FAB45A;} + .st6{fill:#FF1D25;} + .st7{fill:#8C0000;} + .st8{fill:none;stroke:#7AC943;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st9{fill:#FFFFFF;} + .st10{fill:#7AC943;stroke:#7AC943;stroke-miterlimit:10;} +</style> +<g> + <path class="st3" d="M121.89,18H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h102.05 c3.13,0,5.67-2.54,5.67-5.67V23.67C127.56,20.54,125.02,18,121.89,18z M54.27,33.59c0,0.78-0.64,1.42-1.42,1.42H24.57 c-0.78,0-1.41-0.64-1.41-1.42v-2.83c0-0.79,0.63-1.42,1.41-1.42h28.28c0.78,0,1.42,0.63,1.42,1.42V33.59z"/> + <path class="st3" d="M121.89,56.69H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h55.72 c4.6-13.33,17.26-22.9,32.16-22.9c7.4,0,14.25,2.36,19.84,6.38v-6.16C127.56,59.23,125.02,56.69,121.89,56.69z M54.27,73.59 c0,0.78-0.64,1.42-1.42,1.42H24.57c-0.78,0-1.41-0.64-1.41-1.42v-2.83c0-0.79,0.63-1.42,1.41-1.42h28.28 c0.78,0,1.42,0.63,1.42,1.42V73.59z"/> + <path class="st3" d="M73.7,96.15c0-0.25,0-0.51,0.01-0.76H19.84c-3.13,0-5.67,2.53-5.67,5.66v17.01c0,3.13,2.54,5.67,5.67,5.67 H87.8C79.26,117.56,73.7,107.5,73.7,96.15z M54.27,110.98c0,0.78-0.64,1.41-1.42,1.41H24.57c-0.78,0-1.41-0.63-1.41-1.41v-2.84 c0-0.78,0.63-1.42,1.41-1.42h28.28c0.78,0,1.42,0.64,1.42,1.42V110.98z"/> +</g> +<polyline class="st8" points="90.14,95.96 100.35,112.97 125.29,81.22 "/> +</svg> \ No newline at end of file diff --git a/static/images/footer/systems/jureca.svg b/static/images/footer/systems/jureca.svg new file mode 100644 index 0000000000000000000000000000000000000000..fd54b621f76ea3ae6b46b9fbf3a1109dfeee75a6 --- /dev/null +++ b/static/images/footer/systems/jureca.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 141.73 141.73" style="enable-background:new 0 0 141.73 141.73;" xml:space="preserve"><script xmlns="" id="__gaOptOutExtension"/> +<style type="text/css"> + .st0{fill:#B9D25F;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st1{fill:#FAEB5A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st2{fill:#FAB45A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st3{fill:#808080;} + .st4{fill:#B9D25F;} + .st5{fill:#FAB45A;} + .st6{fill:#FF1D25;} + .st7{fill:#8C0000;} + .st8{fill:none;stroke:#7AC943;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st9{fill:#FFFFFF;} + .st10{fill:#7AC943;stroke:#7AC943;stroke-miterlimit:10;} +</style> +<g> + <path class="st3" d="M121.89,18H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h102.05 c3.13,0,5.67-2.54,5.67-5.67V23.67C127.56,20.54,125.02,18,121.89,18z M54.27,33.59c0,0.78-0.64,1.42-1.42,1.42H24.57 c-0.78,0-1.41-0.64-1.41-1.42v-2.83c0-0.79,0.63-1.42,1.41-1.42h28.28c0.78,0,1.42,0.63,1.42,1.42V33.59z"/> + <path class="st3" d="M121.89,56.69H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h55.72 c4.6-13.33,17.26-22.9,32.16-22.9c7.4,0,14.25,2.36,19.84,6.38v-6.16C127.56,59.23,125.02,56.69,121.89,56.69z M54.27,73.59 c0,0.78-0.64,1.42-1.42,1.42H24.57c-0.78,0-1.41-0.64-1.41-1.42v-2.83c0-0.79,0.63-1.42,1.41-1.42h28.28 c0.78,0,1.42,0.63,1.42,1.42V73.59z"/> + <path class="st3" d="M73.7,96.15c0-0.25,0-0.51,0.01-0.76H19.84c-3.13,0-5.67,2.53-5.67,5.66v17.01c0,3.13,2.54,5.67,5.67,5.67 H87.8C79.26,117.56,73.7,107.5,73.7,96.15z M54.27,110.98c0,0.78-0.64,1.41-1.42,1.41H24.57c-0.78,0-1.41-0.63-1.41-1.41v-2.84 c0-0.78,0.63-1.42,1.41-1.42h28.28c0.78,0,1.42,0.64,1.42,1.42V110.98z"/> +</g> +<polyline class="st8" points="90.14,95.96 100.35,112.97 125.29,81.22 "/> +</svg> \ No newline at end of file diff --git a/static/images/footer/systems/jusuf.svg b/static/images/footer/systems/jusuf.svg new file mode 100644 index 0000000000000000000000000000000000000000..37a0a2ffbb53890be33bd0805736cf874a6e9349 --- /dev/null +++ b/static/images/footer/systems/jusuf.svg @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 141.73 141.73" style="enable-background:new 0 0 141.73 141.73;" xml:space="preserve"><script xmlns="" id="__gaOptOutExtension"/> +<style type="text/css"> + .st0{fill:#B9D25F;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st1{fill:#FAEB5A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st2{fill:#FAB45A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st3{fill:#808080;} + .st4{fill:#B9D25F;} + .st5{fill:#FAB45A;} + .st6{fill:#FF1D25;} + .st7{fill:#8C0000;} + .st8{fill:none;stroke:#7AC943;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st9{fill:#FFFFFF;} + .st10{fill:#7AC943;stroke:#7AC943;stroke-miterlimit:10;} +</style> +<path class="st3" d="M121.89,18H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h102.05 c3.13,0,5.67-2.54,5.67-5.67V23.67C127.56,20.54,125.02,18,121.89,18z M54.27,33.59c0,0.78-0.64,1.42-1.42,1.42H24.57 c-0.78,0-1.42-0.64-1.42-1.42v-2.83c0-0.79,0.64-1.42,1.42-1.42h28.28c0.78,0,1.42,0.63,1.42,1.42V33.59z"/> +<path class="st3" d="M121.89,56.69H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h54.8 c4.6-13.33,17.26-22.9,32.16-22.9c7.82,0,15.02,2.63,20.76,7.07v-6.85C127.56,59.23,125.02,56.69,121.89,56.69z M54.27,73.59 c0,0.78-0.64,1.42-1.42,1.42H24.57c-0.78,0-1.42-0.64-1.42-1.42v-2.83c0-0.79,0.64-1.42,1.42-1.42h28.28c0.78,0,1.42,0.63,1.42,1.42 V73.59z"/> +<path class="st3" d="M72.78,96.15c0-0.25,0-0.51,0.01-0.76H19.84c-3.13,0-5.67,2.53-5.67,5.66v17.01c0,3.13,2.54,5.67,5.67,5.67 h67.04C78.34,117.56,72.78,107.5,72.78,96.15z M54.27,110.98c0,0.78-0.64,1.41-1.42,1.41H24.57c-0.78,0-1.42-0.63-1.42-1.41v-2.84 c0-0.78,0.64-1.42,1.42-1.42h28.28c0.78,0,1.42,0.64,1.42,1.42V110.98z"/> +<path class="st4" d="M132.32,104.79c0.69-2.02,1.13-4.14,1.32-6.33l-4.37-2.11c0-0.71-0.02-1.42-0.08-2.14 c-0.02-0.25-0.05-0.49-0.08-0.74l4.11-2.6c-0.43-2.16-1.11-4.22-2.01-6.14l-4.85,0.35c-0.47-0.84-1-1.65-1.58-2.41l2.26-4.29 c-1.43-1.62-3.05-3.07-4.82-4.31l-4.02,2.73c-0.82-0.49-1.68-0.92-2.57-1.3l-0.19-4.85c-2.02-0.69-4.15-1.13-6.33-1.32l-2.12,4.37 c-0.71-0.01-1.42,0.02-2.14,0.08c-0.25,0.02-0.49,0.05-0.74,0.08l-2.59-4.11c-2.16,0.43-4.22,1.11-6.15,2.01l0.35,4.85 c-0.84,0.47-1.65,1-2.41,1.58l-4.3-2.26c-1.63,1.43-3.07,3.05-4.31,4.82l2.73,4.02c-0.49,0.82-0.93,1.68-1.31,2.57l-4.85,0.19 c-0.69,2.02-1.13,4.14-1.32,6.33l4.37,2.11c0,0.71,0.02,1.42,0.08,2.14c0.02,0.25,0.05,0.49,0.09,0.74l-4.11,2.59 c0.43,2.16,1.11,4.22,2.01,6.14l4.85-0.35c0.48,0.84,1,1.64,1.58,2.41l-2.26,4.29c1.43,1.63,3.05,3.07,4.82,4.31l4.02-2.73 c0.83,0.49,1.68,0.93,2.57,1.31l0.19,4.85c2.02,0.68,4.14,1.13,6.33,1.32l2.12-4.37c0.7,0,1.42-0.02,2.14-0.08 c0.25-0.02,0.49-0.05,0.73-0.08l2.59,4.12c2.16-0.43,4.22-1.11,6.15-2.01l-0.35-4.85c0.84-0.48,1.64-1,2.41-1.58l4.29,2.26 c1.62-1.43,3.07-3.05,4.31-4.82l-2.72-4.02c0.48-0.83,0.92-1.68,1.3-2.57L132.32,104.79z M106.8,111.99 c-8.73,0-15.83-7.1-15.83-15.83c0-8.73,7.1-15.83,15.83-15.83c8.73,0,15.83,7.1,15.83,15.83 C122.64,104.88,115.53,111.99,106.8,111.99z"/> +</svg> \ No newline at end of file diff --git a/static/images/footer/systems/juwels.svg b/static/images/footer/systems/juwels.svg new file mode 100644 index 0000000000000000000000000000000000000000..fd54b621f76ea3ae6b46b9fbf3a1109dfeee75a6 --- /dev/null +++ b/static/images/footer/systems/juwels.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 141.73 141.73" style="enable-background:new 0 0 141.73 141.73;" xml:space="preserve"><script xmlns="" id="__gaOptOutExtension"/> +<style type="text/css"> + .st0{fill:#B9D25F;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st1{fill:#FAEB5A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st2{fill:#FAB45A;stroke:#023D6B;stroke-width:2;stroke-miterlimit:10;} + .st3{fill:#808080;} + .st4{fill:#B9D25F;} + .st5{fill:#FAB45A;} + .st6{fill:#FF1D25;} + .st7{fill:#8C0000;} + .st8{fill:none;stroke:#7AC943;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st9{fill:#FFFFFF;} + .st10{fill:#7AC943;stroke:#7AC943;stroke-miterlimit:10;} +</style> +<g> + <path class="st3" d="M121.89,18H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h102.05 c3.13,0,5.67-2.54,5.67-5.67V23.67C127.56,20.54,125.02,18,121.89,18z M54.27,33.59c0,0.78-0.64,1.42-1.42,1.42H24.57 c-0.78,0-1.41-0.64-1.41-1.42v-2.83c0-0.79,0.63-1.42,1.41-1.42h28.28c0.78,0,1.42,0.63,1.42,1.42V33.59z"/> + <path class="st3" d="M121.89,56.69H19.84c-3.13,0-5.67,2.54-5.67,5.67v17.01c0,3.13,2.54,5.67,5.67,5.67h55.72 c4.6-13.33,17.26-22.9,32.16-22.9c7.4,0,14.25,2.36,19.84,6.38v-6.16C127.56,59.23,125.02,56.69,121.89,56.69z M54.27,73.59 c0,0.78-0.64,1.42-1.42,1.42H24.57c-0.78,0-1.41-0.64-1.41-1.42v-2.83c0-0.79,0.63-1.42,1.41-1.42h28.28 c0.78,0,1.42,0.63,1.42,1.42V73.59z"/> + <path class="st3" d="M73.7,96.15c0-0.25,0-0.51,0.01-0.76H19.84c-3.13,0-5.67,2.53-5.67,5.66v17.01c0,3.13,2.54,5.67,5.67,5.67 H87.8C79.26,117.56,73.7,107.5,73.7,96.15z M54.27,110.98c0,0.78-0.64,1.41-1.42,1.41H24.57c-0.78,0-1.41-0.63-1.41-1.41v-2.84 c0-0.78,0.63-1.42,1.41-1.42h28.28c0.78,0,1.42,0.64,1.42,1.42V110.98z"/> +</g> +<polyline class="st8" points="90.14,95.96 100.35,112.97 125.29,81.22 "/> +</svg> \ No newline at end of file diff --git a/static/images/pages/2FA/img01.png b/static/images/pages/2FA/img01.png deleted file mode 100644 index 27bc7a6164be17d97c232133ad919aceae99497b..0000000000000000000000000000000000000000 Binary files a/static/images/pages/2FA/img01.png and /dev/null differ diff --git a/static/images/pages/2FA/img03.png b/static/images/pages/2FA/img03.png deleted file mode 100644 index 81d2571d0f3ecafde4e0c6c5f86413ca819efe24..0000000000000000000000000000000000000000 Binary files a/static/images/pages/2FA/img03.png and /dev/null differ diff --git a/static/images/pages/2FA/jupyter-jsc_2fa_img01.png b/static/images/pages/2FA/jupyter-jsc_2fa_img01.png deleted file mode 100644 index 27bc7a6164be17d97c232133ad919aceae99497b..0000000000000000000000000000000000000000 Binary files a/static/images/pages/2FA/jupyter-jsc_2fa_img01.png and /dev/null differ diff --git a/static/images/pages/2FA/jupyter-jsc_2fa_img02.png b/static/images/pages/2FA/jupyter-jsc_2fa_img02.png deleted file mode 100644 index 0f9484e22a6510c76cd95b20e46042a184ceb358..0000000000000000000000000000000000000000 Binary files a/static/images/pages/2FA/jupyter-jsc_2fa_img02.png and /dev/null differ diff --git a/static/images/pages/2FA/jupyter-jsc_2fa_img03.png b/static/images/pages/2FA/jupyter-jsc_2fa_img03.png deleted file mode 100644 index 81d2571d0f3ecafde4e0c6c5f86413ca819efe24..0000000000000000000000000000000000000000 Binary files a/static/images/pages/2FA/jupyter-jsc_2fa_img03.png and /dev/null differ diff --git a/static/images/pages/2FA/jupyter-jsc_2fa_img04.png b/static/images/pages/2FA/jupyter-jsc_2fa_img04.png deleted file mode 100644 index adb1446bc3599361f32c34e0464206656179521b..0000000000000000000000000000000000000000 Binary files a/static/images/pages/2FA/jupyter-jsc_2fa_img04.png and /dev/null differ diff --git a/static/images/pages/2FA/jupyter-jsc_2fa_img05.png b/static/images/pages/2FA/jupyter-jsc_2fa_img05.png deleted file mode 100644 index 8572a76adf3587a4646b3eb01b948b7adc97967d..0000000000000000000000000000000000000000 Binary files a/static/images/pages/2FA/jupyter-jsc_2fa_img05.png and /dev/null differ diff --git a/static/images/pages/2FA/jupyter-jsc_2fa_img06.png b/static/images/pages/2FA/jupyter-jsc_2fa_img06.png deleted file mode 100644 index e80fd7f265e87467b3c4efadff0a1d07df4a52da..0000000000000000000000000000000000000000 Binary files a/static/images/pages/2FA/jupyter-jsc_2fa_img06.png and /dev/null differ diff --git a/static/images/pages/2FA/jupyter-jsc_2fa_short_img01.png b/static/images/pages/2FA/jupyter-jsc_2fa_short_img01.png deleted file mode 100644 index b15e46e82570bced9b0da5334736e61026a98c37..0000000000000000000000000000000000000000 Binary files a/static/images/pages/2FA/jupyter-jsc_2fa_short_img01.png and /dev/null differ diff --git a/static/images/pages/2FA/jupyter-jsc_2fa_short_img02.png b/static/images/pages/2FA/jupyter-jsc_2fa_short_img02.png deleted file mode 100644 index d6e9255d6e70e2a2f1d77d991c22ec19f43b2db8..0000000000000000000000000000000000000000 Binary files a/static/images/pages/2FA/jupyter-jsc_2fa_short_img02.png and /dev/null differ diff --git a/static/images/pages/vo_info/HIFIS.png b/static/images/pages/vo_info/HIFIS.png deleted file mode 100644 index 0feed5de4cf753c94d87fd7548b86df61b54f09d..0000000000000000000000000000000000000000 Binary files a/static/images/pages/vo_info/HIFIS.png and /dev/null differ diff --git a/static/images/pages/vo_info/default.png b/static/images/pages/vo_info/default.png deleted file mode 100644 index 24d226b5d3c24214c979f3c5bdaf116fbecd42b0..0000000000000000000000000000000000000000 Binary files a/static/images/pages/vo_info/default.png and /dev/null differ diff --git a/templates/2FA.html b/templates/2FA.html deleted file mode 100644 index 0d62c0b00e17773a0277b86ed87ed592fc90f41a..0000000000000000000000000000000000000000 --- a/templates/2FA.html +++ /dev/null @@ -1,170 +0,0 @@ -{%- extends "page.html" -%} - -{%- block stylesheet -%} - <link rel="stylesheet" href='{{ static_url("css/2fa.css", include_version=True) }}' type="text/css"/> -{%- endblock -%} - - -{%- block main -%} -<div class="container p-4"> - <div class="row justify-content-between mt-1"> - <h2 class="col col-auto">2-Factor Authentication for Jupyter-JSC</h2> - <div class="col col-auto"> - {%- if user %} - <a id="activate-2fa" role="button" class="activate-2fa btn btn-primary mr-2 mb-1">Request - 2FA</a> - <a id="remove-2fa" role="button" class="remove-2fa btn btn-danger mr-2 mb-1">Remove 2FA</a> - {%- else %} - <a role="button" class="btn btn-primary mr-2 mb-1" href="{{ base_url }}oauth_login?next=2FA">Login - required</a> - {%- endif %} - <a role="button" class="btn btn-warning mb-1" - href="https://docs.{{hostname}}/github/FZJ-JSC/jupyter-jsc-notebooks/blob/master/001-Jupyter/Activate_JupyterJSC_2-factor-authentication.ipynb" - target="_blank">Detailed Information</a> - </div> - </div> - <div class="text-container"> - <div class="d-flex align-items-center" style="margin-top: 20px;"> - <div class="image-container"> - <img src='{{ static_url("images/pages/2FA/img01.png", include_version=True) }}' - title="2-factor-authentication" /> - </div> - <div> - <h3>Preparation</h3> - <p>2-Factor Authentication (2FA) better protects both your user credentials and the resources that you can - access. - Jupyter-JSC uses the time-based One-Time Password (OTP) generated by an OTP-App as a 2nd factor. </p> - <ul> - <li><b>Install an OTP-App</b> - <p>On one of your personal devices (eg. your smartphone) install an OTP-App:</p> - <ul> - <li><a href="https://freeotp.github.io" target="_blank"><b>FreeOTP</b></a> (iOS, Android)</li> - <li><a href="https://keeweb.info" target="_blank"><b>KeeWeb</b></a> (Linux, macOS, Windows, Online)</li> - <li>more alternatives can be found in <a href="https://docs.{{hostname}}/github/FZJ-JSC/jupyter-jsc-notebooks/blob/master/001-Jupyter/Activate_JupyterJSC_2-factor-authentication.ipynb" - target="_blank">Detailed Information</a></li> - </ul> - </li> - </ul> - <ul> - <li><b>Initialize this OTP-App</b> - <p>The required secret initialization code will be provided to you in the next step of this 2FA-activation - process - as a QR-Code (or string). - Then please scan the QR-code with your newly installed OTP-App (or type-in the string) for initialization. - </p> - </li> - </ul> - </div> - </div> - <div class="d-flex align-items-center" style="margin-top: 20px;"> - <div class="image-container"> - <img src='{{ static_url("images/pages/2FA/img03.png", include_version=True) }}' title="2-factor-authentication" - width="200" style="float:left" /> - </div> - <div> - <h3>New two-step login</h3> - <p>After you installed & initialized your <b>OTP-App</b> it will provide you (in our case every 30 seconds) - with an unique <b>One-Time Password</b> whenever you want to login to Jupyter-JSC.</p> - <p>The 2FA-Login will be almost as simple as before</p> - <ul> - <li><b>Enter your JSC-account password</b> - <p>Each time you log in, you will enter your JSC-account password as usual.</p> - </li> - <li><b>Enter the current One-Time Password</b> - <p>You will then be asked for an One-Time Password that you read from your installed and initialized - OTP-App. - </p> - </li> - </ul> - </div> - </div> - </div> -</div> -{%- endblock -%} - -{%- block script -%} -{{ super() }} -<script type="text/javascript"> - window.jhdata_code = { - {%- if code is defined %} - code: true, - code_success: "{{ code_success }}".toLowerCase() == "true", - code_header: "{{ code_header}}", - code_text: "{{ code_text }}", - {%- else %} - code: false, - {%- endif %} - } - - $(document).ready(function () { - var user = window.jhdata.user; - var user_active = window.jhdata.user_active; - var code = window.jhdata_code.code; - if (code) { - var code_success = window.jhdata_code.code_success; - var code_header = window.jhdata_code.code_header; - var code_text = window.jhdata_code.code_text; - if (code_success) { - $.confirm({ - title: "2-Factor Authentication - Activation", - backgroundDismiss: 'Two factor authentication', - content: "Activation successful.<br>Please re-login to initialize your 2nd factor.", - buttons: { - Ok: { - text: "RE-LOGIN to initialize", - btnClass: 'btn-primary', - action: function () { - window.location.replace("{{ base_url }}logout?stopall=false&alldevices=true"); - } - }, - Cancel: { - text: "LATER", - btnClass: 'btn-default', - action: function () { - } - } - } - }); - } else if (code_text.includes('expired')) { - $.confirm({ - title: "2-Factor Authentication - Activation Failed", - backgroundDismiss: 'Two factor authentication', - content: "This activation link is not vaild anymore.<br>Please click \"Request 2FA\" for a new activation link.", - buttons: { - Ok: { - text: "REQUEST 2FA", - btnClass: 'btn-blue', - action: function () { - document.getElementById("activate-2fa").click(); - } - }, - Cancel: { - text: "Cancel", - btnClass: 'btn-default', - action: function () { - } - } - } - }); - } else { - $.confirm({ - title: "2-Factor Authentication - Activation Failed", - backgroundDismiss: 'Two factor authentication', - content: "Code unknown.<br>Please try again with a new request or contact support.", - buttons: { - Ok: { - text: "Ok", - btnClass: 'btn-default', - action: function () { - } - } - } - }); - } - } - }); -</script> - -<script src='{{static_url("js/2FA.js", include_version=True) }}' type="text/javascript" - charset="utf-8"></script> -{%- endblock -%} diff --git a/templates/footer.html b/templates/footer.html index e1c9bf09c830f6b1615715277f32f60ecda49dcf..9b7bfeadfa64506f36e10b207472758b59175344 100644 --- a/templates/footer.html +++ b/templates/footer.html @@ -31,7 +31,7 @@ </button> </div> </div> - <div id="footer-bottom" class="container-fluid justify-content-center"> + <div id="footer-bottom" class="container-fluid justify-content-center" data-sse-incidents> {%- set logo_width = "220px" -%} {%- set div_classes = "px-2 text-center" %} <a class="py-2 {{div_classes}}" target="_blank" href="https://www.fz-juelich.de">© Forschungszentrum Jülich</a> @@ -275,18 +275,6 @@ require(["jquery"], function ( } } } - - function updateSystemHoverTooltips() { - const incidents = {{ incidents | tojson }}; - for (const [system, systemInfo] of Object.entries(incidents)) { - if (systemInfo.incident) { - $(`#ampel-${system.toLowerCase()}-tooltip`) - .attr('data-bs-original-title', systemInfo.incident); - } - } - reorderSystems(incidents); - } - // Update the carousel when the window is resized $(window).resize(function () { createCarouselPages(); @@ -294,17 +282,36 @@ require(["jquery"], function ( $(document).ready(function() { createCarouselPages(); - updateSystemHoverTooltips(); }) + $(`[data-sse-incidents]`).on("sse", function (event, incidents) { + $(`[id^='ampel-'][id$='-tooltip']`).tooltip("dispose"); + let newMaintenanceList = []; + for (const [system, systemInfo] of Object.entries(incidents)) { + if (systemInfo.incident) { + $(`#ampel-${system.toLowerCase()}-tooltip`) + .attr('data-bs-original-title', systemInfo.incident); + if ( systemInfo.health > incidentsThresholdInteractive ) { + const _system = incidentsmapping[system] ?? system; + if ( !newMaintenanceList.includes(_system) ) { + newMaintenanceList.push(_system); + } + } + } + } + globalMaintenanceSystems = newMaintenanceList; + $(`[id$='-option-input']`).trigger("option"); + $(`[id^='ampel-'][id$='-tooltip']`).tooltip(); + reorderSystems(incidents); + }); $(`[data-sse-usercount]`).on("sse", function (event, data) { var systems = {}; $("div[id^='ampel']").each((i, e) => { let system = $(e).attr("id").split('-')[1]; systems[system] = false; - }) - // Update systems with info from request + }) + $(`[id^='ampel-'][id$='-tooltip']`).tooltip("dispose"); for (const [system, usercount] of Object.entries(data)) { switch (system) { case 'jupyterhub': @@ -322,18 +329,26 @@ require(["jquery"], function ( for (const [partition, users] of Object.entries(usercount['partitions'])) { partitionInfos += `\n${partition}: ${users}`; } + $(`#${system.toLowerCase()}-users`) + .parents("[data-toggle]").tooltip("dispose"); $(`#${system.toLowerCase()}-users`) .parents("[data-bs-toggle]") .attr("data-bs-original-title", `Number of active servers${partitionInfos}`); + $(`#${system.toLowerCase()}-users`) + .parents("[data-toggle]").tooltip(); } } // If there was no info about a system, set running labs to 0 and reset tooltip for (const [system, systemInfo] of Object.entries(systems)) { if (systemInfo == false) { - $(`#${system}-users`).html(0); + $(`#${system.toLowerCase()}-users`) + .parents("[data-toggle]").tooltip("dispose"); + $(`#${system.toLowerCase()}-users`).html(0); $(`#${system.toLowerCase()}-users`) .parents("[data-toggle]") .attr("data-bs-original-title", `Number of active servers`); + $(`#${system.toLowerCase()}-users`) + .parents("[data-toggle]").tooltip(); } } }); diff --git a/templates/macros/table/config/announcement.jinja b/templates/macros/table/config/announcement.jinja new file mode 100644 index 0000000000000000000000000000000000000000..1d4e7fe931800970a28088883c3879b34bba9936 --- /dev/null +++ b/templates/macros/table/config/announcement.jinja @@ -0,0 +1,13 @@ +{%- import "macros/svgs.jinja" as svg -%} + +{%- set show_announcement = false %} +{%- macro announcement() %} +<div class="alert bg-info alert-dismissible fade show" style="color: #023d6b;" role="alert"> + <h4 class="alert-heading"> + {{ svg.announcement_svg | safe }} + <span class="align-middle">This is the announcement title</span> + </h4> + This is my announcement text. + <button type="button" class="btn-close" data-bs-dismiss="alert"></button> +</div> +{%- endmacro %} \ No newline at end of file diff --git a/templates/macros/table/elements_js.jinja b/templates/macros/table/elements_js.jinja index 7e919e41537859e2b92cd2583b69417280a4bed3..f047d9d3ceb281ed967024012b0698bb3bcdecae 100644 --- a/templates/macros/table/elements_js.jinja +++ b/templates/macros/table/elements_js.jinja @@ -1,6 +1,6 @@ {%- import "macros/svgs.jinja" as svg -%} -{%- include "macros/table/table_js.jinja" %} +{%- include "macros/table/table_js.jinja" with context %} {%- import "macros/table/variables.jinja" as vars with context %} <script> diff --git a/templates/macros/table/helpers/systems_js.jinja b/templates/macros/table/helpers/systems_js.jinja index db1adf77674a0e8eba2ad6742f6c8d05d8b02113..bea2974fb07f0a4702b9c4ad666ae18e9c784387 100644 --- a/templates/macros/table/helpers/systems_js.jinja +++ b/templates/macros/table/helpers/systems_js.jinja @@ -10,6 +10,16 @@ const kubeSystems = _getKubeSystems(); + function _getKubeFlavorSystems() { + return Object.keys(systemConfig).filter(system => { + const backendService = systemConfig[system].backendService; + // Check if the backend service type is "kube" + return backendServicesConfig[backendService]?.flavorsRequired; + }); + } + + const kubeFlavorSystems = _getKubeFlavorSystems(); + function getAvailableKubeFlavorsS(systems) { let ret = []; @@ -52,7 +62,7 @@ const resPattern = /^urn:(?<namespace>.+?(?=:res:)):res:(?<systempartition>[^:]+):(?<project>[^:]+):act:(?<account>[^:]+):(?<accounttype>[^:]+)$/; const unicoreEntitlements = {{ auth_state.entitlements | list | tojson }}; const unicorePreferredUsername = {{ auth_state.preferred_username | tojson }}; - const unicoreReservations = {{ reservations | tojson }}; + const unicoreReservations = {{ reservations | default({}, true) | tojson }}; const unicoreMapSystems = {{ custom_config.mapSystems | tojson }}; const unicoreMapPartitions = {{ custom_config.mapPartitions | tojson }}; const unicoreDefaultPartitions = {{ custom_config.defaultPartitions | tojson }}; @@ -550,33 +560,31 @@ allSystems = allSystems.filter(system => allowedSystems.includes(system)); } {%- endif %} - + allSystems = allSystems.filter(system => !globalMaintenanceSystems.includes(system)); return allSystems; } - const allSystems = _getAllSystems(); - function getAvailableSystemOptions(serviceId, options) { let ret = []; options.forEach(option => { - if (getServiceConfig(serviceId)?.options) { + if (getServiceConfig(serviceId)?.options && Object.keys(getServiceConfig(serviceId)?.options).includes(option)) { const subSystems1 = getServiceConfig(serviceId).options[option].allowedLists.systems; - ret.push(...allSystems.filter(system => subSystems1.includes(system))); + ret.push(..._getAllSystems().filter(system => subSystems1.includes(system))); } else { // return all systems, if it's not reduced by the option - ret.push(...allSystems); + ret.push(..._getAllSystems()); } }); - const uniqueSystems = [...new Set(ret)]; + let uniqueSystems = [...new Set(ret)]; uniqueSystems.sort((a, b) => (systemConfig[a].weight || 0) - (systemConfig[b].weight || 0)); - + uniqueSystems = uniqueSystems.filter(system => !globalMaintenanceSystems.includes(system) ); return uniqueSystems.map(item => [item, item]); } function getMissingSystemOptions(serviceId, rowId, options) { let availableSystems = getAvailableSystemOptions(serviceId, options); - let missingSystems = allSystems.filter(system => !availableSystems.map(([key, value]) => key).includes(system)); + let missingSystems = _getAllSystems().filter(system => !availableSystems.map(([key, value]) => key).includes(system)); {%- if pagetype == vars.pagetype_workshop %} const allowedSystems = {{ spawner.user_options.get("workshop", {}).get("system", false) | tojson }}; diff --git a/templates/macros/table/table.jinja b/templates/macros/table/table.jinja index 1449ec2dc3b623a9df6bdefb3969e26b04568f26..68a302085d14b3b52cac1ea5ef62c3f3b289fcfb 100644 --- a/templates/macros/table/table.jinja +++ b/templates/macros/table/table.jinja @@ -1,3 +1,5 @@ +{%- import "macros/table/config/announcement.jinja" as announcement %} + {%- macro tables( frontend_config, macro_description, @@ -7,6 +9,9 @@ macro_row_content )%} <div id="global-content-div" class="container-fluid p-4"> + {%- if announcement.show_announcement %} + {{ announcement.announcement() }} + {%- endif %} <input id="service-input" class="form-control" data-collect="true" data-group="default" data-type="input" name="service" data-element="service" value="{{ frontend_config.get("services", {}).get("default", "jupyterlab") }}" style="display: none"/> {#- TABLE #} {%- for service_id, service_options in frontend_config.get("services", {}).get("options", {}).items() %} diff --git a/templates/macros/table/table_js.jinja b/templates/macros/table/table_js.jinja index 839a8d48017cae97e31b32fc312ac41e2ed60260..a0628d686ba056979d5b24770b705b72856db009 100644 --- a/templates/macros/table/table_js.jinja +++ b/templates/macros/table/table_js.jinja @@ -12,21 +12,34 @@ // Define the regex pattern with named capture groups - const serviceConfig = {{ custom_config.services | default({}, true) | tojson }}; - const userModulesConfig = {{ custom_config.userModules | default({}, true) | tojson }}; - const systemConfig = {{ custom_config.systems | default({}, true) | tojson }}; - const resourcesConfig = {{ custom_config.resources | default({}, true) | tojson }}; - const backendServicesConfig = {{ custom_config.backendServices | default({}, true) | tojson }}; + const serviceConfig = {{ custom_config.services | tojson }}; + const userModulesConfig = {{ custom_config.userModules | tojson }}; + const systemConfig = {{ custom_config.systems | tojson }}; + const resourcesConfig = {{ custom_config.resources | tojson }}; + const backendServicesConfig = {{ custom_config.backendServices | tojson }}; const notAllowedKeys = ["secret_keys", "defaultvalues", "attachvalues"]; const mappingDict = {}; const globalUserOptions = {}; const globalFillingOrder = {}; + let globalMaintenanceSystems = []; + const initIncidents = {{ incidents | tojson }}; + const incidentsmapping = { + "JSCCLOUD": "JSC-Cloud" + }; + const incidentsThresholdInteractive = {{ custom_config.get("incidentCheck", {}).get("healthThreshold", {}).get("interactive", 50) | tojson }}; + Object.entries(initIncidents).forEach(([system, incident]) =>{ + const health = incident?.health ?? 0; + if ( health >= incidentsThresholdInteractive ) { + const _system = incidentsmapping?.[system] ?? system; + if ( !globalMaintenanceSystems.includes(_system) ) globalMaintenanceSystems.push(_system); + } + }); {%- for service_id, service_options in config.frontend_config.get("services", {}).get("options", {}).items() %} if ( !Object.keys(globalFillingOrder).includes("{{ service_id }}") ) { - globalFillingOrder["{{ service_id }}"] = {{ service_options.get("fillingOrder", []) | default([], true) | tojson }}; + globalFillingOrder["{{ service_id }}"] = {{ service_options.get("fillingOrder", []) | tojson }}; } {%- if pagetype == vars.pagetype_home %} {%- for s in spawners %} @@ -35,12 +48,12 @@ if ( !Object.keys(globalUserOptions).includes("{{ service_id }}") ) { globalUserOptions["{{ service_id }}"] = {}; } - globalUserOptions["{{ service_id }}"]["{{ spawner.name }}"] = {{ decrypted_user_options.get(spawner.name, spawner.user_options) | default({}, true) | tojson }}; + globalUserOptions["{{ service_id }}"]["{{ spawner.name }}"] = {{ decrypted_user_options.get(spawner.name, spawner.user_options) | tojson }}; {%- endif %} {%- endfor %} {%- elif pagetype == vars.pagetype_workshop %} globalUserOptions["{{ service_id }}"] = {}; - globalUserOptions["{{ service_id }}"]["{{ spawner.name }}"] = {{ spawner.user_options | default({}, true) | tojson }}; + globalUserOptions["{{ service_id }}"]["{{ spawner.name }}"] = {{ spawner.user_options | tojson }}; {%- endif %} {%- endfor %} @@ -59,7 +72,7 @@ Object.entries(value.options).forEach(([optionKey, optionValue]) => { mappingDict[serviceId]["option"][optionKey] = optionValue.mapping ?? optionKey; }); - allSystems.forEach(system => { + _getAllSystems().forEach(system => { const backendService = systemConfig[system].backendService; const systemType = backendServicesConfig[backendService]?.mapping ?? system; if (!Object.keys(mappingDict[serviceId]["system"]).includes(systemType)) { @@ -124,10 +137,11 @@ function fillSelect(elementId, select, values_, groups = {}, inactive_values = [], inactive_text = "N/A") { let values = values_; + const key = select.attr("name"); + const serviceId = select.attr("data-service"); + const rowId = select.attr("data-row"); {%- if pagetype == vars.pagetype_workshop %} - const key = select.attr("name"); - const rowId = select.attr("data-row"); - const workshopValues = {{ workshop_options | default({}, true) | tojson }}; + const workshopValues = {{ workshop_options | tojson }}; if ( Object.keys(workshopValues).includes(key) ) { let valueKeys = workshopValues[key]; if ( !Array.isArray(valueKeys) ){ @@ -187,7 +201,6 @@ select.val(values[0][0]); } else { console.error(`Could not fill object. Check configuration.`); - {%- if pagetype == vars.pagetype_workshop %} workshopNotUsable(select); {%- endif %} @@ -204,9 +217,9 @@ const serviceId = element.attr("data-service"); const rowId = element.attr("data-row"); const elementName = element.attr("data-element"); - const workshop = {{ workshop_options | default({}, true) | tojson }}; + const workshop = {{ workshop_options | tojson }}; const workshopId = "{{ spawner.user_options.get("workshop_id", workshop_options.get("workshopid")) }}"; - const allowedSystems = {{ workshop_options.get("system", false) | default({}, true) | tojson }}; + const allowedSystems = {{ workshop_options.get("system", false) | tojson }}; const workshopSystems = workshop?.system || []; let workshopProject = workshop?.project || []; @@ -261,7 +274,7 @@ <li style="color: #333;">Select these partitions: ${workshopPartition}.</li> ` } - var missingSystems = allSystems.filter(key => workshopSystems.includes(key)); + var missingSystems = _getAllSystems().filter(key => workshopSystems.includes(key)); var stepLogin = ""; var stepSystem = ""; var stepProject = ""; @@ -480,7 +493,11 @@ inputElement.val(newValue); inputElement.trigger("change"); } else { - availableDescription = `${key} ${newValue} is not available for your account. Please try re-logging in.`; + if ( inputElement.attr("data-element") === "system" && globalMaintenanceSystems.includes(newValue) ) { + availableDescription = `${key} ${newValue} is currently in maintenace. See footer for more information.`; + } else { + availableDescription = `${key} ${newValue} is not available for your account. Please try re-logging in.`; + } console.log(`${key} ${newValue} currently not available`); } } else if (dataType == "number" ) { @@ -712,9 +729,6 @@ form.find(`[id^='${serviceId}-${rowId}-'][id$='-input'][data-collect="true"]:not([data-group="none"])`).each(function () { let $this = $(this).first(); let dataGroupValue = $this.attr('data-group'); - if ( dataGroupValue == "modules" ){ - console.log("Break"); - } let value = ""; let addValue = true; let id = $this.prop("id"); @@ -837,7 +851,7 @@ {%- if pagetype == vars.pagetype_workshop %} {# Only allow options, which are available for the selected systems #} - let allowedSystems = {{ workshop_options.get("system", false) | default({}, true) | tojson }}; + let allowedSystems = {{ workshop_options.get("system", false) | tojson }}; if ( allowedSystems ) { if ( !Array.isArray(allowedSystems) ){ allowedSystems = [allowedSystems]; @@ -853,11 +867,29 @@ } values = allowedOptions; } + {% elif pagetype == vars.pagetype_home %} + let allowedSystems = _getAllSystems(); + if ( !Array.isArray(allowedSystems) ){ + allowedSystems = [allowedSystems]; + } + let allowedOptions = {}; + for ( const [key, valueInformation] of Object.entries(values) ) { + allowedSystems.forEach(system => { + const systemsPerOption = getServiceConfig(serviceId)?.options?.[key]?.allowedLists?.systems ?? []; + if ( systemsPerOption.includes(system) && !allowedOptions.hasOwnProperty(key) ) { + allowedOptions[key] = valueInformation; + } + }); + } + values = allowedOptions; {%- endif %} const optionInput = $(`#${serviceId}-${rowId}-${tabId}-option-input`); - - fillSelect("init", optionInput, Object.entries(values).map(([key, value]) => [key, value.name]), {}, [], "N/A"); + let _values = Object.entries(values).map(([key, value]) => [key, value.name]); + if ( _values.length == 0 ){ + _values = [["none", "No Option available. Please contact support"]]; + } + fillSelect("init", optionInput, _values, {}, [], "N/A"); } function wmTriggerOption(trigger, serviceId, rowId, tabId, elementId, elementOptions) { @@ -879,13 +911,13 @@ if ( optionInput.prop("disabled") ){ // If option is disabled -> make all systems available - fillSelect(elementId, systemInput, allSystems.map(item => [item, item])); + fillSelect(elementId, systemInput, _getAllSystems().map(item => [item, item])); } else { // Update available systems let inactiveText = "N/A" let displayNames = []; options.forEach(option => { - if (getServiceConfig(serviceId)?.options) { + if (getServiceConfig(serviceId)?.options && Object.keys(getServiceConfig(serviceId)?.options).includes(option) ) { displayNames.push(getServiceConfig(serviceId).options[option].name); } }) @@ -961,7 +993,7 @@ let reservations = getReservationOptions(serviceId, rowId); {%- if pagetype == vars.pagetype_workshop %} - const workshopValues = {{ workshop_options | default({}, true) | tojson }}; + const workshopValues = {{ workshop_options | tojson }}; {# Only allow options, which are available for the selected systems #} let allowedReservations = workshopValues?.reservation ?? false; if ( allowedReservations ) { @@ -1192,7 +1224,7 @@ inputElement.attr("data-collect", true); } {%- if pagetype == vars.pagetype_workshop %} - const workshopValues = {{ workshop_options | default({}, true) | tojson }} + const workshopValues = {{ workshop_options | tojson }} if ( Object.keys(workshopValues).includes(elementId) ){ console.log(`Yeah - ${elementId} is defined`); } @@ -1214,9 +1246,15 @@ function homeTriggerFlavor(trigger, serviceId, rowId, tabId, elementId, elementOptions) { const systems = val(getInputElement(serviceId, rowId, "system")); - if ( systems.some(item => kubeSystems.includes(item)) ) { + if ( systems.some(item => kubeFlavorSystems.includes(item)) ) { + let availableFlavors = getAvailableKubeFlavorsS(systems); + let unavailableFlavors = getUnavailableKubeFlavorsS(systems); + if ( availableFlavors.length == 0 ) { + availableFlavors = [["_undefined", "Couldn't receive flavors. Please re-login to use this system"]]; + } + const selectInput = getInputElement(serviceId, rowId, "flavor"); - fillSelect(elementId, selectInput, getAvailableKubeFlavorsS(systems), {}, getUnavailableKubeFlavorsS(systems), "maximum reached"); + fillSelect(elementId, selectInput, availableFlavors, {}, unavailableFlavors, "maximum reached"); // selectInput.trigger("change"); } } @@ -1318,7 +1356,7 @@ function homeTriggerFlavorInfo(trigger, serviceId, rowId, tabId, elementId, elementOptions) { const systems = val(getInputElement(serviceId, rowId, "system")); - if ( systems.some(item => kubeSystems.includes(item)) && systems.length == 1 ){ + if ( systems.some(item => kubeFlavorSystems.includes(item)) && systems.length == 1 ){ setFlavorInfo(serviceId, rowId, systems[0]); // $(`[id^='${serviceId}-${rowId}-'][id$='-flavorinfo-info-div']`).show(); } @@ -1344,7 +1382,7 @@ {# WorkshopManager.default.repo2docker.repopathtype --> #} function R2DgetRepoPathType(serviceId, rowId, tabId, elementId) { - return {{ custom_config.get("binderRepos", {}).get("notebookTypes", ["File", "URL"]) | default([], true) | tojson }}.map(item => [item, item]); + return {{ custom_config.get("binderRepos", {}).get("notebookTypes", ["File", "URL"]) | tojson }}.map(item => [item, item]); } function homeTriggerRepoPathTypeInit(trigger, serviceId, rowId, tabId, elementId, elementOptions) { @@ -1390,7 +1428,7 @@ {# WorkshopManager.default.repo2docker.repotype --> #} function R2DgetRepoType() { - return {{ custom_config.get("binderRepos", {}).get("repos", ["GitHub"]) | default([], true) | tojson }}.map(item => [item, item]); + return {{ custom_config.get("binderRepos", {}).get("repos", ["GitHub"]) | tojson }}.map(item => [item, item]); } function homeTriggerRepoType(trigger, serviceId, rowId, tabId, elementId, elementOptions) { @@ -1492,6 +1530,10 @@ $(`#${serviceId}-${rowId}-config-td-option`).html(`${option}`); $(`#${serviceId}-${rowId}-config-td-system`).html(`${system}`); + const nameThElement = $(`#${serviceId}-${rowId}-summary-tr th.name-td`); + const name = $(`[id^='${serviceId}-${rowId}-'][id$='-name-input']`).val(); + nameThElement.html(name); + const projectDiv = $(`#${serviceId}-${rowId}-config-td-project-div`); const partitionDiv = $(`#${serviceId}-${rowId}-config-td-partition-div`); @@ -1748,6 +1790,14 @@ updateHeaderButtons(serviceId, rowId, "stopped"); progressBarUpdate(serviceId, rowId, "", 0); appendToLog(serviceId, rowId, getStopEvent(buttonId)); + + const navbarLogsButton = $(`[id^='${serviceId}-${rowId}-'][id$='-logs-navbar-button']`); + if ( navbarLogsButton.hasClass("active") ) { + const navbarLabConfigButton = $(`[id^='${serviceId}-${rowId}-'][id$='-labconfig-navbar-button']`); + if ( navbarLabConfigButton ) { + navbarLabConfigButton.trigger("click"); + } + } } updateHeaderButtons(serviceId, rowId, "stopping"); progressBarUpdate(serviceId, rowId, "stopping", 100); @@ -1758,12 +1808,17 @@ function homeSummaryButtonCancel(serviceId, rowId, buttonId, button_options, user, api, base_url, utils) { const options = getAPIOptions(); options["success"] = function (data, textStatus, jqXHR) { - console.log("Stopped"); - console.log(serviceId); - console.log(rowId); updateHeaderButtons(serviceId, rowId, "stopped"); progressBarUpdate(serviceId, rowId, "", 0); - appendToLog(serviceId, rowId, getStopEvent(buttonId)); + appendToLog(serviceId, rowId, getStopEvent(buttonId)); + + const navbarLogsButton = $(`[id^='${serviceId}-${rowId}-'][id$='-logs-navbar-button']`); + if ( navbarLogsButton.hasClass("active") ) { + const navbarLabConfigButton = $(`[id^='${serviceId}-${rowId}-'][id$='-labconfig-navbar-button']`); + if ( navbarLabConfigButton ) { + navbarLabConfigButton.trigger("click"); + } + } } updateHeaderButtons(serviceId, rowId, "cancelling"); progressBarUpdate(serviceId, rowId, "cancelling", 99); @@ -1905,7 +1960,7 @@ const group = elementOptions.options.group || tabId; const name = elementOptions.options.name || elementId; {%- if pagetype == vars.pagetype_workshop %} - const workshopValues = {{ workshop_options | default({}, true) | tojson }} + const workshopValues = {{ workshop_options | tojson }} if ( Object.keys(workshopValues).includes(group) && Object.keys(workshopValues[group]).includes(name) ){ workshopPreset = true; const modules = workshopValues[group][name]; @@ -2002,7 +2057,7 @@ {%- if pagetype == vars.pagetype_workshop %} function wTriggerName(trigger, serviceId, rowId, tabId, elementId, elementOptions) { const inputName = getInputElement(serviceId, rowId, elementId); - const user_options = {{ workshop_options | default({}, true) | tojson }} || {}; + const user_options = {{ workshop_options | tojson }} || {}; const displayName = user_options.name || "Workshop {{ workshop_id }}"; inputName.val(displayName); } @@ -2153,9 +2208,7 @@ } let userOptions = collectSelectedOptions(serviceId, rowId); - - - + sseInit() options["data"] = JSON.stringify(userOptions); clearLogs(serviceId, rowId); @@ -2166,6 +2219,18 @@ } globalUserOptions[serviceId][rowId] = userOptions; homeHeaderUpdate(serviceId, rowId); + + setTimeout(function() { + const logInputElement = $(`[id^='${serviceId}-${rowId}-logs'][id$='-logcontainer-input']`); + if ( logInputElement.html() == "" ) { + console.log("Logs not fetched. Reload website"); + const url = new URL(window.location.href); + url.searchParams.set('service', serviceId); + url.searchParams.set('row', rowId); + url.searchParams.set('showlogs', true); + window.location.href = url.toString(); + } + }, 1000); } api.start_named_server(user, rowId, options); @@ -2181,7 +2246,6 @@ accordionIcon.removeClass("collapsed"); new bootstrap.Collapse(collapse); } - const navbarLogsButton = $(`[id^='${serviceId}-${rowId}-'][id$='-logs-navbar-button']`); if ( navbarLogsButton ) { navbarLogsButton.trigger("click");