mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-19 07:53:00 +00:00
progress toward bootstrap 5
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -22,6 +22,8 @@ jupyterhub_cookie_secret
|
|||||||
jupyterhub.sqlite
|
jupyterhub.sqlite
|
||||||
jupyterhub.sqlite*
|
jupyterhub.sqlite*
|
||||||
share/jupyterhub/static/components
|
share/jupyterhub/static/components
|
||||||
|
share/jupyterhub/static/css/style.css
|
||||||
|
share/jupyterhub/static/css/style.css.map
|
||||||
share/jupyterhub/static/css/style.min.css
|
share/jupyterhub/static/css/style.min.css
|
||||||
share/jupyterhub/static/css/style.min.css.map
|
share/jupyterhub/static/css/style.min.css.map
|
||||||
share/jupyterhub/static/js/admin-react.js*
|
share/jupyterhub/static/js/admin-react.js*
|
||||||
|
1
jsx/.gitignore
vendored
1
jsx/.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
node_modules
|
node_modules
|
||||||
build/admin-react.js
|
build/admin-react.js
|
||||||
|
.yarn
|
||||||
|
@@ -342,7 +342,7 @@ const ServerDashboard = (props) => {
|
|||||||
variant={open ? "secondary" : "primary"}
|
variant={open ? "secondary" : "primary"}
|
||||||
size="sm"
|
size="sm"
|
||||||
>
|
>
|
||||||
<span className="caret"></span>
|
<span className="fa fa-caret-down"></span>
|
||||||
</Button>{" "}
|
</Button>{" "}
|
||||||
</span>
|
</span>
|
||||||
<span data-testid={`user-name-div-${userServerName}`}>
|
<span data-testid={`user-name-div-${userServerName}`}>
|
||||||
@@ -565,7 +565,7 @@ const ServerDashboard = (props) => {
|
|||||||
Stop All
|
Stop All
|
||||||
</Button>
|
</Button>
|
||||||
{/* spacing between start/stop and Shutdown */}
|
{/* spacing between start/stop and Shutdown */}
|
||||||
<span style={{ marginLeft: "56px" }}> </span>
|
<span style={{ marginLeft: "30px" }}> </span>
|
||||||
{/* Shutdown Jupyterhub */}
|
{/* Shutdown Jupyterhub */}
|
||||||
<Button
|
<Button
|
||||||
variant="danger"
|
variant="danger"
|
||||||
|
@@ -7,13 +7,6 @@
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-light {
|
|
||||||
/* backport bs5 btn-light colors */
|
|
||||||
background-color: #f9fafb;
|
|
||||||
border-color: #f9fafb;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.server-dashboard-container .btn-light {
|
.server-dashboard-container .btn-light {
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
|
@@ -3,21 +3,19 @@
|
|||||||
height: 80vh;
|
height: 80vh;
|
||||||
|
|
||||||
& #insecure-login-warning {
|
& #insecure-login-warning {
|
||||||
// @include bg-warning();
|
background-color: $warning-bg-subtle;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.service-login {
|
.service-login {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin: auto auto 20% auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
form {
|
form {
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin: auto auto 20% auto;
|
margin: auto;
|
||||||
width: 350px;
|
width: 350px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,8 +29,8 @@
|
|||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: $jupyter-orange;
|
background: $jupyter-orange;
|
||||||
border-radius: $border-radius-large $border-radius-large 0 0;
|
|
||||||
font-size: large;
|
font-size: large;
|
||||||
|
border-radius: $border-radius-large $border-radius-large 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-form-header > h1 {
|
.auth-form-header > h1 {
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
@import "./variables.scss";
|
|
||||||
|
|
||||||
$logo-height: 28px;
|
$logo-height: 28px;
|
||||||
|
$grid-float-breakpoint: map-get($grid-breakpoints, "sm");
|
||||||
|
|
||||||
#jupyterhub-logo {
|
#jupyterhub-logo {
|
||||||
@media (max-width: $grid-float-breakpoint) {
|
@media (max-width: $grid-float-breakpoint) {
|
||||||
@@ -9,7 +8,18 @@ $logo-height: 28px;
|
|||||||
}
|
}
|
||||||
.jpy-logo {
|
.jpy-logo {
|
||||||
height: $logo-height;
|
height: $logo-height;
|
||||||
margin-top: ($navbar-height - $logo-height) / 2;
|
margin-top: calc($navbar-brand-height - $logo-height) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-nav {
|
||||||
|
.nav-link {
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
// no color change
|
||||||
|
color: var(--#{$prefix}navbar-color);
|
||||||
|
background-color: darken($body-tertiary-bg, 10%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +81,7 @@ $logo-height: 28px;
|
|||||||
0 0 8px $jupyter-orange;
|
0 0 8px $jupyter-orange;
|
||||||
border-color: $jupyter-orange;
|
border-color: $jupyter-orange;
|
||||||
outline-color: $jupyter-orange;
|
outline-color: $jupyter-orange;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-jupyter {
|
.btn-jupyter {
|
||||||
@include button-variant(#fff, $jupyter-orange, $jupyter-red);
|
@include button-variant(#fff, $jupyter-orange, $jupyter-red);
|
||||||
|
@@ -1,31 +1,60 @@
|
|||||||
/*! variables */
|
|
||||||
@import "./variables.scss";
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
*
|
*
|
||||||
* Twitter Bootstrap
|
* Bootstrap
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc)
|
||||||
@import "../components/bootstrap/scss/functions"; // Required
|
@import "../components/bootstrap/scss/functions"; // Required
|
||||||
@import "../components/bootstrap/scss/variables"; // Required
|
|
||||||
@import "../components/bootstrap/scss/mixins"; // Required
|
|
||||||
|
|
||||||
@import "../components/bootstrap/scss/root"; // Required
|
// 2. Include any default variable overrides here
|
||||||
@import "../components/bootstrap/scss/reboot"; // Required
|
@import "./variables.scss";
|
||||||
|
|
||||||
@import "../components/bootstrap/scss/alert";
|
@import "../components/bootstrap/scss/bootstrap"; // Full bootstrap (maybe wasteful?)
|
||||||
@import "../components/bootstrap/scss/buttons";
|
|
||||||
@import "../components/bootstrap/scss/containers";
|
// // 3. Include remainder of required Bootstrap stylesheets (including any separate color mode stylesheets)
|
||||||
@import "../components/bootstrap/scss/grid";
|
// @import "../components/bootstrap/scss/variables"; // Required
|
||||||
@import "../components/bootstrap/scss/utilities";
|
// @import "../components/bootstrap/scss/variables-dark"; // Required
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// // 4. Include any default map overrides here
|
||||||
|
//
|
||||||
|
// // 5. Include remainder of required parts
|
||||||
|
// @import "../components/bootstrap/scss/maps"; // Required
|
||||||
|
// @import "../components/bootstrap/scss/mixins"; // Required
|
||||||
|
// @import "../components/bootstrap/scss/root"; // Required
|
||||||
|
//
|
||||||
|
// // 6. Optionally include any other parts as needed
|
||||||
|
// @import "../components/bootstrap/scss/utilities";
|
||||||
|
// @import "../components/bootstrap/scss/reboot";
|
||||||
|
// @import "../components/bootstrap/scss/type";
|
||||||
|
// @import "../components/bootstrap/scss/images";
|
||||||
|
// @import "../components/bootstrap/scss/navbar";
|
||||||
|
// @import "../components/bootstrap/scss/alert";
|
||||||
|
// @import "../components/bootstrap/scss/buttons";
|
||||||
|
// @import "../components/bootstrap/scss/containers";
|
||||||
|
// @import "../components/bootstrap/scss/grid";
|
||||||
|
// @import "../components/bootstrap/scss/modal";
|
||||||
|
|
||||||
|
// 7. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss`
|
||||||
|
// @import "../components/bootstrap/scss/utilities/api";
|
||||||
|
|
||||||
|
// redefine .btn-xs, removed in bootstrap 4
|
||||||
|
.btn-xs {
|
||||||
|
// $padding-y, $padding-x, $font-size, $border-radius
|
||||||
|
@include button-size(1px, 5px, 14px, 3px);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
*
|
*
|
||||||
* Font Awesome
|
* Font Awesome
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
// $fa-font-path: "../components/font-awesome/fonts";
|
$fa-font-path: "../components/@fortawesome/fontawesome-free/webfonts";
|
||||||
// @import "../components/font-awesome/scss/font-awesome.scss";
|
@import "../components/@fortawesome/fontawesome-free/scss/fontawesome";
|
||||||
|
// You can include all the other styles the same as before
|
||||||
|
@import "../components/@fortawesome/fontawesome-free/scss/regular.scss";
|
||||||
|
@import "../components/@fortawesome/fontawesome-free/scss/solid.scss";
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
*
|
*
|
||||||
|
@@ -1,23 +1,17 @@
|
|||||||
$border-radius-small: 2px;
|
$border-radius-large: 5px;
|
||||||
$border-radius-base: 2px;
|
|
||||||
$border-radius-large: 3px;
|
|
||||||
$navbar-height: 40px;
|
$navbar-height: 40px;
|
||||||
$grid-float-breakpoint: $screen-xs-min;
|
|
||||||
|
|
||||||
$navbar-default-color: #222;
|
|
||||||
$navbar-default-link-color: $navbar-default-color;
|
|
||||||
// darken background on hover, no change to text
|
// darken background on hover, no change to text
|
||||||
$navbar-default-link-hover-color: $navbar-default-color;
|
// background part is in page.scss
|
||||||
$navbar-default-link-hover-bg: darken($navbar-default-bg, 10%);
|
$nav-link-color: var(--bs-navbar-color);
|
||||||
|
$nav-link-hover-color: $nav-link-color;
|
||||||
|
|
||||||
$jupyter-orange: #f37524;
|
$jupyter-orange: #f37524;
|
||||||
|
|
||||||
$jupyter-red: #e34f21;
|
$jupyter-red: #e34f21;
|
||||||
// color blind-friendly alternative to red/green
|
|
||||||
|
// accessible alternative to red/green
|
||||||
// from 5-class RdYlBu via colorbrewer.org
|
// from 5-class RdYlBu via colorbrewer.org
|
||||||
// eliminate distinction between 'primary' and 'success'
|
// eliminate distinction between 'primary' and 'success'
|
||||||
$brand-primary: #2c7bb6;
|
$primary: #2c7bb6;
|
||||||
$brand-success: $brand-primary;
|
$success: $primary;
|
||||||
$brand-danger: #d7191c;
|
$danger: #d7191c;
|
||||||
|
|
||||||
$text-muted: #222;
|
|
||||||
|
@@ -29,7 +29,7 @@
|
|||||||
<div class="auth-form-header">
|
<div class="auth-form-header">
|
||||||
<h1>Sign in</h1>
|
<h1>Sign in</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class='auth-form-body'>
|
<div class='auth-form-body m-auto'>
|
||||||
|
|
||||||
<p id='insecure-login-warning' class='hidden'>
|
<p id='insecure-login-warning' class='hidden'>
|
||||||
Warning: JupyterHub seems to be served over an unsecured HTTP connection.
|
Warning: JupyterHub seems to be served over an unsecured HTTP connection.
|
||||||
|
@@ -40,7 +40,7 @@
|
|||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="{{static_url("components/requirejs/require.js") }}" type="text/javascript" charset="utf-8"></script>
|
<script src="{{static_url("components/requirejs/require.js") }}" type="text/javascript" charset="utf-8"></script>
|
||||||
<script src="{{static_url("components/jquery/dist/jquery.min.js") }}" type="text/javascript" charset="utf-8"></script>
|
<script src="{{static_url("components/jquery/dist/jquery.min.js") }}" type="text/javascript" charset="utf-8"></script>
|
||||||
<script src="{{static_url("components/bootstrap/dist/js/bootstrap.min.js") }}" type="text/javascript" charset="utf-8"></script>
|
<!-- <script src="{{static_url("components/bootstrap/dist/js/bootstrap.min.js") }}" type="text/javascript" charset="utf-8"></script> -->
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
<script>
|
<script>
|
||||||
require.config({
|
require.config({
|
||||||
@@ -104,35 +104,30 @@
|
|||||||
</noscript>
|
</noscript>
|
||||||
|
|
||||||
{% block nav_bar %}
|
{% block nav_bar %}
|
||||||
<nav class="navbar navbar-default">
|
<nav class="navbar navbar-expand-lg bg-body-tertiary mb-4">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="navbar-header">
|
|
||||||
{% block logo %}
|
{% block logo %}
|
||||||
<span id="jupyterhub-logo" class="pull-left">
|
<span id="jupyterhub-logo" class="navbar-brand">
|
||||||
<a href="{{logo_url or base_url}}"><img src='{{base_url}}logo' alt='JupyterHub logo' class='jpy-logo' title='Home'/></a>
|
<a href="{{logo_url or base_url}}"><img src='{{base_url}}logo' alt='JupyterHub logo' class='jpy-logo' title='Home'/></a>
|
||||||
</span>
|
</span>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% if user %}
|
{% if user %}
|
||||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#thenavbar" aria-expanded="false">
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#thenavbar" aria-controls="thenavbar" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<span class="sr-only">Toggle navigation</span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="thenavbar">
|
<div class="collapse navbar-collapse" id="thenavbar">
|
||||||
{% if user %}
|
{% if user %}
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
{% block nav_bar_left_items %}
|
{% block nav_bar_left_items %}
|
||||||
<li><a href="{{base_url}}home">Home</a></li>
|
<li class="nav-item"><a class="nav-link" href="{{base_url}}home">Home</a></li>
|
||||||
<li><a href="{{base_url}}token">Token</a></li>
|
<li class="nav-item"><a class="nav-link" href="{{base_url}}token">Token</a></li>
|
||||||
{% if 'admin-ui' in parsed_scopes %}
|
{% if 'admin-ui' in parsed_scopes %}
|
||||||
<li><a href="{{base_url}}admin">Admin</a></li>
|
<li class="nav-item"><a class="nav-link" href="{{base_url}}admin">Admin</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if services %}
|
{% if services %}
|
||||||
<li class="dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Services<span class="caret"></span></a>
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Services<span class="caret"></span></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
{% for service in services %}
|
{% for service in services %}
|
||||||
@@ -146,16 +141,16 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav me-2">
|
||||||
{% block nav_bar_right_items %}
|
{% block nav_bar_right_items %}
|
||||||
<li>
|
<li class="nav-item">
|
||||||
{% block login_widget %}
|
{% block login_widget %}
|
||||||
<span id="login_widget">
|
<span id="login_widget">
|
||||||
{% if user %}
|
{% if user %}
|
||||||
<p class="navbar-text">{{user.name}}</p>
|
<span class="navbar-text">{{user.name}}</span>
|
||||||
<a id="logout" role="button" class="navbar-btn btn-sm btn btn-default" href="{{logout_url}}"> <i aria-hidden="true" class="fa fa-sign-out"></i> Logout</a>
|
<a id="logout" role="button" class="btn btn-sm btn-outline-dark" href="{{logout_url}}"> <i aria-hidden="true" class="fa fa-sign-out"></i> Logout</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a id="login" role="button" class="btn-sm btn navbar-btn btn-default" href="{{login_url}}">Login</a>
|
<a id="login" role="button" class="btn btn-sm btn-outline-dark" href="{{login_url}}">Login</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="sr-only">Manage JupyterHub Tokens</h1>
|
<h1 class="sr-only">Manage JupyterHub Tokens</h1>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<form id="request-token-form" class="col-md-offset-3 col-md-6">
|
<form id="request-token-form" class="m-auto col-lg-6">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<button type="submit" class="btn btn-lg btn-jupyter">
|
<button type="submit" class="btn btn-lg btn-jupyter">
|
||||||
Request new API token
|
Request new API token
|
||||||
@@ -48,16 +48,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div id="token-area" class="col-md-6 col-md-offset-3" style="display: none;">
|
<div id="token-area" class="col-lg-6 m-auto" style="display: none;">
|
||||||
<div class="panel panel-default">
|
<div class="card">
|
||||||
<div class="panel-heading">
|
<div class="card-header">
|
||||||
Your new API Token
|
Your new API Token
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="card-body">
|
||||||
<p class="lead text-center">
|
<p class="card-title text-center">
|
||||||
<span id="token-result"></span>
|
<span id="token-result"></span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p class="card-text">
|
||||||
Copy this token. You won't be able to see it again,
|
Copy this token. You won't be able to see it again,
|
||||||
but you can always come back here to get a new one.
|
but you can always come back here to get a new one.
|
||||||
</p>
|
</p>
|
||||||
@@ -86,10 +86,10 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for token in api_tokens %}
|
{% for token in api_tokens %}
|
||||||
<tr class="token-row" data-token-id="{{token.api_id}}">
|
<tr class="token-row container" data-token-id="{{token.api_id}}">
|
||||||
{% block token_row scoped %}
|
{% block token_row scoped %}
|
||||||
<td class="note-col col-sm-4">{{token.note}}</td>
|
<td class="note-col col">{{token.note}}</td>
|
||||||
<td class="scope-col col-sm-1">
|
<td class="scope-col col">
|
||||||
<details>
|
<details>
|
||||||
<summary>scopes</summary>
|
<summary>scopes</summary>
|
||||||
{% for scope in token.scopes %}
|
{% for scope in token.scopes %}
|
||||||
@@ -97,28 +97,28 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</details>
|
</details>
|
||||||
</td>
|
</td>
|
||||||
<td class="time-col col-sm-3">
|
<td class="time-col col">
|
||||||
{%- if token.last_activity -%}
|
{%- if token.last_activity -%}
|
||||||
{{ token.last_activity.isoformat() + 'Z' }}
|
{{ token.last_activity.isoformat() + 'Z' }}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
Never
|
Never
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
</td>
|
</td>
|
||||||
<td class="time-col col-sm-3">
|
<td class="time-col col">
|
||||||
{%- if token.created -%}
|
{%- if token.created -%}
|
||||||
{{ token.created.isoformat() + 'Z' }}
|
{{ token.created.isoformat() + 'Z' }}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
N/A
|
N/A
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
</td>
|
</td>
|
||||||
<td class="time-col col-sm-3">
|
<td class="time-col col">
|
||||||
{%- if token.expires_at -%}
|
{%- if token.expires_at -%}
|
||||||
{{ token.expires_at.isoformat() + 'Z' }}
|
{{ token.expires_at.isoformat() + 'Z' }}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
Never
|
Never
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
</td>
|
</td>
|
||||||
<td class="col-sm-1 text-center">
|
<td class="col text-center">
|
||||||
<button class="revoke-token-btn btn btn-xs btn-danger">revoke</button>
|
<button class="revoke-token-btn btn btn-xs btn-danger">revoke</button>
|
||||||
</td>
|
</td>
|
||||||
{% endblock token_row %}
|
{% endblock token_row %}
|
||||||
|
Reference in New Issue
Block a user