snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
This commit is contained in:
39
server/auth/assets/public/fonts.css
Normal file
39
server/auth/assets/public/fonts.css
Normal file
@@ -0,0 +1,39 @@
|
||||
@font-face {
|
||||
font-family: 'Poppins-Bold';
|
||||
src: url('./fonts/poppins/Poppins-Bold.ttf') format('truetype');
|
||||
font-weight: 100 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Poppins-Medium';
|
||||
src: url('./fonts/poppins/Poppins-Medium.ttf') format('truetype');
|
||||
font-weight: 100 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Poppins-Regular';
|
||||
src: url('./fonts/poppins/Poppins-Regular.ttf') format('truetype');
|
||||
font-weight: 100 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Poppins-SemiBold';
|
||||
src: url('./fonts/poppins/Poppins-SemiBold.ttf') format('truetype');
|
||||
font-weight: 100 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Poppins-Italic';
|
||||
src: url('./fonts/poppins/Poppins-Italic.ttf') format('truetype');
|
||||
font-weight: 100 900;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
||||
18
server/auth/assets/public/script.js
Normal file
18
server/auth/assets/public/script.js
Normal file
@@ -0,0 +1,18 @@
|
||||
$(function () {
|
||||
$('.toast').toast('show');
|
||||
|
||||
$('form').not('do-not-disable-buttons-on-submit').on('submit', function() {
|
||||
let form = this
|
||||
setTimeout(function() {
|
||||
$('button, input[type=submit]', form)
|
||||
.not('do-not-disable-on-submit')
|
||||
.attr('disabled', true)
|
||||
}, 50)
|
||||
})
|
||||
|
||||
$('input.mfa-code-mask').mask('000 000')
|
||||
|
||||
$('#avatar').change(function () {
|
||||
$('form').submit();
|
||||
})
|
||||
})
|
||||
52
server/auth/assets/public/style.css
Normal file
52
server/auth/assets/public/style.css
Normal file
@@ -0,0 +1,52 @@
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100%;
|
||||
display: grid;
|
||||
grid-template-rows: auto;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
label {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.logo {
|
||||
max-height: 45px;
|
||||
max-width: 25%;
|
||||
}
|
||||
|
||||
.version {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: var(--light) !important;
|
||||
}
|
||||
|
||||
/* Navigation */
|
||||
.nav-item.active {
|
||||
border-bottom: 4px solid var(--primary);
|
||||
}
|
||||
|
||||
.login-title {
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.auth {
|
||||
width: 100%;
|
||||
max-width: 650px;
|
||||
margin: auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.bi::before {
|
||||
vertical-align: middle;
|
||||
}
|
||||
44
server/auth/assets/templates/authorized-clients.html.tpl
Normal file
44
server/auth/assets/templates/authorized-clients.html.tpl
Normal file
@@ -0,0 +1,44 @@
|
||||
{{ template "inc_header.html.tpl" set . "activeNav" "clients" }}
|
||||
<div class="card-body p-0">
|
||||
<form
|
||||
method="POST"
|
||||
action="{{ links.AuthorizedClients }}"
|
||||
class="clearfix p-3"
|
||||
>
|
||||
|
||||
{{ .csrfField }}
|
||||
|
||||
{{ range .authorizedClients }}
|
||||
<div class="mb-2 pb-2 border-bottom">
|
||||
<div class="text-primary font-weight-bold">{{ .Name }}</div>
|
||||
<div>
|
||||
{{ tr "authorized-clients.template.list.authorized-on" }}
|
||||
<time
|
||||
datetime="{{ .ConfirmedAt | date "2006-01-02T15:04:05Z07:00" }}"
|
||||
>
|
||||
{{ .ConfirmedAt | date "Mon, 02 Jan 2006 15:04 MST" }}
|
||||
</time>
|
||||
</div>
|
||||
<button
|
||||
data-test-id="button-revoke-access"
|
||||
type="submit"
|
||||
name="revoke"
|
||||
value="{{ .ID }}"
|
||||
class="btn btn-sm btn-danger my-2"
|
||||
>
|
||||
{{ tr "authorized-clients.template.list.buttons.revoke" }}
|
||||
</button>
|
||||
</div>
|
||||
{{ end }}
|
||||
</form>
|
||||
|
||||
{{ if not .authorizedClients}}
|
||||
<div
|
||||
data-test-id="text-empty-list"
|
||||
class="text-center m-3 mb-3"
|
||||
>
|
||||
<i>{{ tr "authorized-clients.template.list.empty" }}</i>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
75
server/auth/assets/templates/change-password.html.tpl
Normal file
75
server/auth/assets/templates/change-password.html.tpl
Normal file
@@ -0,0 +1,75 @@
|
||||
{{ template "inc_header.html.tpl" set . "activeNav" "security" }}
|
||||
<div class="card-body p-0">
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "change-password.template.title" }}</h4>
|
||||
<form
|
||||
method="POST"
|
||||
action="{{ links.ChangePassword }}"
|
||||
class="p-3"
|
||||
>
|
||||
{{ .csrfField }}
|
||||
{{ if .form.error }}
|
||||
<div
|
||||
data-test-id="error"
|
||||
class="text-danger font-weight-bold mb-3"
|
||||
role="alert"
|
||||
>
|
||||
{{ .form.error }}
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "change-password.template.form.email.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-email"
|
||||
type="email"
|
||||
class="form-control"
|
||||
name="email"
|
||||
readonly
|
||||
placeholder="{{ tr "change-password.template.form.email.placeholder" }}"
|
||||
value="{{ .user.Email }}"
|
||||
aria-label="{{ tr "change-password.template.form.email.label" }}"
|
||||
>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "change-password.template.form.old-password.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-old-password"
|
||||
type="password"
|
||||
required
|
||||
class="form-control"
|
||||
name="oldPassword"
|
||||
autocomplete="current-password"
|
||||
placeholder="{{ tr "change-password.template.form.old-password.placeholder" }}"
|
||||
aria-label="{{ tr "change-password.template.form.old-password.label" }}"
|
||||
>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "change-password.template.form.new-password.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-new-password"
|
||||
type="password"
|
||||
required
|
||||
class="form-control"
|
||||
name="newPassword"
|
||||
autocomplete="new-password"
|
||||
placeholder="{{ tr "change-password.template.form.new-password.placeholder" }}"
|
||||
aria-label="{{ tr "change-password.template.form.new-password.label" }}"
|
||||
>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<button
|
||||
data-test-id="button-change-password"
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
type="submit"
|
||||
>
|
||||
{{ tr "change-password.template.form.button.change-password" }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
59
server/auth/assets/templates/create-password.html.tpl
Normal file
59
server/auth/assets/templates/create-password.html.tpl
Normal file
@@ -0,0 +1,59 @@
|
||||
{{ template "inc_header.html.tpl" set . "activeNav" "security" }}
|
||||
<div class="card-body p-0">
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "create-password.template.title" }}</h4>
|
||||
<form
|
||||
method="POST"
|
||||
action="{{ links.CreatePassword }}"
|
||||
class="p-3"
|
||||
>
|
||||
{{ .csrfField }}
|
||||
{{ if .form.error }}
|
||||
<div
|
||||
data-test-id="error"
|
||||
class="text-danger font-weight-bold mb-3"
|
||||
role="alert"
|
||||
>
|
||||
{{ .form.error }}
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "create-password.template.form.email.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-email"
|
||||
type="email"
|
||||
class="form-control"
|
||||
name="email"
|
||||
readonly
|
||||
value="{{ .user.Email }}"
|
||||
aria-label="{{ tr "create-password.template.form.email.label" }}"
|
||||
>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "create-password.template.form.password.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-password"
|
||||
type="password"
|
||||
required
|
||||
class="form-control"
|
||||
name="password"
|
||||
autocomplete="password"
|
||||
placeholder="{{ tr "create-password.template.form.password.placeholder" }}"
|
||||
aria-label="{{ tr "create-password.template.form.password.label" }}"
|
||||
>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<button
|
||||
data-test-id="button-create-password"
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
type="submit"
|
||||
>
|
||||
{{ tr "create-password.template.form.button.create-password" }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
8
server/auth/assets/templates/error-internal.html.tpl
Normal file
8
server/auth/assets/templates/error-internal.html.tpl
Normal file
@@ -0,0 +1,8 @@
|
||||
{{ template "inc_header.html.tpl" . }}
|
||||
<div class="card-body p-0">
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "error-internal.template.title" }}</h4>
|
||||
<div class="text-danger mb-4 font-weight-bold p-3" role="alert">
|
||||
{{ .error }}
|
||||
</div>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
12
server/auth/assets/templates/inc_footer.html.tpl
Normal file
12
server/auth/assets/templates/inc_footer.html.tpl
Normal file
@@ -0,0 +1,12 @@
|
||||
</main>
|
||||
{{ template "inc_toasts.html.tpl" .alerts }}
|
||||
<footer class="d-flex align-items-end justify-content-center text-white py-4">
|
||||
{{ tr "inc_footer.code-link" }}
|
||||
<a data-test-id="link-github" href="https://github.com/cortezaproject/" target="_blank" class="text-white ml-1">GitHub</a>
|
||||
</footer>
|
||||
</body>
|
||||
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.mask/1.14.16/jquery.mask.js" integrity="sha512-0XDfGxFliYJPFrideYOoxdgNIvrwGTLnmK20xZbCAvPfLGQMzHUsaqZK8ZoH+luXGRxTrS46+Aq400nCnAT0/w==" crossorigin="anonymous"></script>
|
||||
<script src="{{ links.AuthAssets }}/script.js?{{ buildtime }}"></script>
|
||||
</html>
|
||||
56
server/auth/assets/templates/inc_header.html.tpl
Normal file
56
server/auth/assets/templates/inc_header.html.tpl
Normal file
@@ -0,0 +1,56 @@
|
||||
<!doctype html>
|
||||
<html data-color-mode="{{ .theme }}" lang="{{ language }}">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Bootstrap icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.3.0/font/bootstrap-icons.css">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="icon" id="favicon" href="{{ links.Assets }}/icon.svg">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link href="{{ links.AuthAssets }}/fonts.css" rel="stylesheet">
|
||||
|
||||
<!-- Custom CSS -->
|
||||
<link href="/custom.css" rel="stylesheet">
|
||||
<link href="{{ links.AuthAssets }}/style.css?{{ buildtime }}" rel="stylesheet">
|
||||
|
||||
<title>Corteza</title>
|
||||
<style>
|
||||
body {
|
||||
font-size: 1rem !important;
|
||||
{{ .authBg }}
|
||||
background-size: cover;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
{{ if .user }}
|
||||
<div class="d-flex justify-content-end align-items-center text-white m-2">
|
||||
<a class="text-white font-weight-bold" href="{{ links.Base }}">
|
||||
{{ tr "inc_header.menu" }}
|
||||
</a>
|
||||
<span class="mx-2">
|
||||
|
|
||||
</span>
|
||||
{{ tr "inc_header.logged-in-as" }}
|
||||
<a data-test-id="link-redirect-to-profile" class="font-weight-bold text-white mx-2"
|
||||
href="{{ links.Profile }}">{{ coalesce .user.Name .user.Handle .user.Email }}
|
||||
</a>
|
||||
|
|
||||
<a data-test-id="link-logout" class="font-weight-bold text-white ml-2" href="{{ links.Logout }}">
|
||||
{{ tr "inc_header.logout" }}
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
</header>
|
||||
|
||||
<main class="auth mt-sm-5">
|
||||
<div class="tabs card">
|
||||
{{ template "inc_nav.html.tpl" . }}
|
||||
56
server/auth/assets/templates/inc_nav.html.tpl
Normal file
56
server/auth/assets/templates/inc_nav.html.tpl
Normal file
@@ -0,0 +1,56 @@
|
||||
<div class="header card-header border-0 p-0">
|
||||
<div class="text-center w-100 my-2 my-sm-4">
|
||||
<a href="{{ links.Profile }}">
|
||||
<img
|
||||
data-test-id="img-corteza-logo"
|
||||
class="logo"
|
||||
alt="Company logo"
|
||||
src="{{ links.Assets }}/logo.svg"
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
{{ $activeNav := default "" .activeNav }}
|
||||
|
||||
{{ if not .hideNav }}
|
||||
{{ if .user }}
|
||||
<ul class="nav d-flex justify-content-around">
|
||||
<li class="nav-item {{ if eq $activeNav "profile" }}active{{ end }}">
|
||||
<a
|
||||
data-test-id="link-tab-profile"
|
||||
class="nav-link"
|
||||
href="{{ links.Profile }}"
|
||||
>
|
||||
{{ tr "inc_nav.template.class.your-profile" }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item {{ if eq $activeNav "security" }}active{{ end }}">
|
||||
<a
|
||||
data-test-id="link-tab-security"
|
||||
class="nav-link"
|
||||
href="{{ links.Security }}"
|
||||
>
|
||||
{{ tr "inc_nav.template.class.security" }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item {{ if eq $activeNav "sessions" }}active{{ end }}">
|
||||
<a
|
||||
data-test-id="link-tab-login-session"
|
||||
class="nav-link"
|
||||
href="{{ links.Sessions }}"
|
||||
>
|
||||
{{ tr "inc_nav.template.class.login-session" }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item {{ if eq $activeNav "clients" }}active{{ end }}">
|
||||
<a
|
||||
data-test-id="link-tab-authorized-clients"
|
||||
class="nav-link"
|
||||
href="{{ links.AuthorizedClients }}"
|
||||
>
|
||||
{{ tr "inc_nav.template.class.authorized-clients" }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
12
server/auth/assets/templates/inc_toasts.html.tpl
Normal file
12
server/auth/assets/templates/inc_toasts.html.tpl
Normal file
@@ -0,0 +1,12 @@
|
||||
<div class="position-fixed bottom-0 right-0 p-3 mb-2" style="z-index: 5; right: 0; bottom: 0;">
|
||||
{{ range . }}
|
||||
<div class="toast align-items-center bg-dark text-white" role="alert" aria-live="polite" aria-atomic="true" data-delay="5000" style="min-width:200px;">
|
||||
<div class="d-flex align-items-center toast-body border-top border-{{ .Type }}">
|
||||
{{ .Text | html }}
|
||||
<button type="button" class="ml-auto text-white btn p-0" data-dismiss="toast" aria-label="Close">
|
||||
<i class="bi bi-x"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
56
server/auth/assets/templates/invite.html.tpl
Normal file
56
server/auth/assets/templates/invite.html.tpl
Normal file
@@ -0,0 +1,56 @@
|
||||
{{ template "inc_header.html.tpl" . }}
|
||||
<div class="card-body p-0">
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "invite.template.title" }}</h4>
|
||||
<form
|
||||
method="POST"
|
||||
action="{{ links.AcceptInvite }}"
|
||||
class="p-3"
|
||||
>
|
||||
{{ .csrfField }}
|
||||
{{ if .form.error }}
|
||||
<div class="text-danger font-weight-bold p-3" role="alert">
|
||||
{{ .form.error }}
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "invite.template.form.email.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-email"
|
||||
type="email"
|
||||
class="form-control"
|
||||
name="email"
|
||||
readonly
|
||||
placeholder="{{ tr "invite.template.form.email.placeholder" }}"
|
||||
value="{{ .user.Email }}"
|
||||
aria-label="{{ tr "invite.template.form.emaillabel" }}"
|
||||
>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "invite.template.form.new-password.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-new-password"
|
||||
type="password"
|
||||
required
|
||||
class="form-control"
|
||||
name="password"
|
||||
autocomplete="new-password"
|
||||
placeholder="{{ tr "invite.template.form.new-password.placeholder" }}"
|
||||
aria-label="{{ tr "invite.template.form.new-passwordlabel" }}"
|
||||
>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<button
|
||||
data-test-id="button-change-password"
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
type="submit"
|
||||
>
|
||||
{{ tr "invite.template.form.buttons.password" }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
123
server/auth/assets/templates/login.html.tpl
Normal file
123
server/auth/assets/templates/login.html.tpl
Normal file
@@ -0,0 +1,123 @@
|
||||
{{ template "inc_header.html.tpl" . }}
|
||||
<div class="card-body p-0">
|
||||
<h4 class="login-title mb-0 p-3 border-bottom">{{ tr "login.template.title" }}</h4>
|
||||
{{ if .settings.LocalEnabled }}
|
||||
<form
|
||||
method="POST"
|
||||
action="{{ links.Login }}"
|
||||
class="p-3"
|
||||
>
|
||||
{{ .csrfField }}
|
||||
{{ if .form.error }}
|
||||
<div
|
||||
data-test-id="error"
|
||||
class="text-danger mb-4 font-weight-bold"
|
||||
role="alert"
|
||||
>
|
||||
{{ .form.error }}
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "login.template.form.email.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-email"
|
||||
type="email"
|
||||
class="form-control"
|
||||
name="email"
|
||||
required
|
||||
placeholder="{{ tr "login.template.form.email.placeholder" }}"
|
||||
value="{{ if .form }}{{ .form.email }}{{ end }}"
|
||||
autocomplete="username"
|
||||
aria-label="{{ tr "login.template.form.email.label" }}">
|
||||
</div>
|
||||
{{ if not .form.splitCredentialsCheck }}
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "login.template.form.password.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-password"
|
||||
type="password"
|
||||
required
|
||||
class="form-control"
|
||||
name="password"
|
||||
placeholder="{{ tr "login.template.form.password.placeholder" }}"
|
||||
autocomplete="current-password"
|
||||
aria-label="{{ tr "login.template.form.password.label" }}">
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-right">
|
||||
{{ if .enableRememberMe }}
|
||||
<button
|
||||
data-test-id="button-login-and-remember"
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
name="keep-session"
|
||||
value="true"
|
||||
type="submit"
|
||||
>
|
||||
{{ tr "login.template.form.button.login-and-remember" }}
|
||||
</button>
|
||||
{{ end }}
|
||||
<button
|
||||
data-test-id="button-login"
|
||||
class="btn btn-light btn-block btn-lg"
|
||||
type="submit"
|
||||
>
|
||||
{{ tr "login.template.form.button.login" }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{ else }}
|
||||
<div class="row">
|
||||
<div class="col text-right">
|
||||
<button
|
||||
data-test-id="button-continue"
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
name="keep-session"
|
||||
value="true"
|
||||
type="submit"
|
||||
>
|
||||
{{ tr "login.template.form.button.continue" }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</form>
|
||||
<div class="row text-center px-3 pb-3">
|
||||
{{ if .settings.PasswordResetEnabled }}
|
||||
<div class="col cols-6">
|
||||
<a
|
||||
data-test-id="link-request-password-reset"
|
||||
href="{{ links.RequestPasswordReset }}"
|
||||
>
|
||||
{{ tr "login.template.links.request-password-reset" }}
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ if .settings.SignupEnabled }}
|
||||
<div class="col cols-6">
|
||||
<a
|
||||
data-test-id="link-signup"
|
||||
href="{{ links.Signup }}"
|
||||
>
|
||||
{{ tr "login.template.links.signup" }}
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ if .settings.ExternalEnabled }}
|
||||
<div class="px-3 pb-3">
|
||||
{{ range .providers }}
|
||||
<a href="{{ links.External }}/{{ .Handle }}" class="btn btn-light btn-block btn-lg mb-2 mt-1 text-dark">
|
||||
<i class="bi bi-{{ .Icon }} mr-1"></i>
|
||||
{{ tr "login.template.links.external.login-with" "idp" (coalesce .Label .Handle) }}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
24
server/auth/assets/templates/logout.html.tpl
Normal file
24
server/auth/assets/templates/logout.html.tpl
Normal file
@@ -0,0 +1,24 @@
|
||||
{{ template "inc_header.html.tpl" . }}
|
||||
<div class="card-body">
|
||||
<form>
|
||||
{{ if .form.error }}
|
||||
<div
|
||||
data-test-id="error"
|
||||
class="text-danger font-weight-bold"
|
||||
role="alert"
|
||||
>
|
||||
{{ .form.error }}
|
||||
</div>
|
||||
{{ else }}
|
||||
<div class="text-dark font-weight-bold" role="primary">
|
||||
{{ tr "logout.template.log-out" }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="text-center my-3">
|
||||
{{ tr "logout.template.log-in" "link" .link }}
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
44
server/auth/assets/templates/mfa-totp-disable.html.tpl
Normal file
44
server/auth/assets/templates/mfa-totp-disable.html.tpl
Normal file
@@ -0,0 +1,44 @@
|
||||
{{ template "inc_header.html.tpl" set . "hideNav" true }}
|
||||
<div class="card-body p-0">
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "mfa-totp-disable.template.title" }}</h4>
|
||||
|
||||
<form
|
||||
class="p-3"
|
||||
method="POST"
|
||||
action="{{ links.MfaTotpDisable }}"
|
||||
>
|
||||
{{ tr "mfa-totp-disable.template.instructions" }}
|
||||
|
||||
{{ if .form.error }}
|
||||
<div class="pt-3 text-danger font-weight-bold" role="alert">
|
||||
{{ .form.error }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ .csrfField }}
|
||||
<div class="input-group my-3">
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
class="form-control lg text-center mfa-code-mask"
|
||||
name="code"
|
||||
maxlength="6"
|
||||
minlength="6"
|
||||
aria-required="true"
|
||||
placeholder="000 000"
|
||||
autocomplete="off"
|
||||
style="letter-spacing:5px;font-size:20px;"
|
||||
aria-label="Code">
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
name="keep-session"
|
||||
value="true"
|
||||
type="submit"
|
||||
>
|
||||
{{ tr "mfa-totp-disable.template.button.remove" }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
83
server/auth/assets/templates/mfa-totp.html.tpl
Normal file
83
server/auth/assets/templates/mfa-totp.html.tpl
Normal file
@@ -0,0 +1,83 @@
|
||||
{{ template "inc_header.html.tpl" set . "hideNav" true }}
|
||||
<div class="card-body p-0">
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "mfa-totp.template.title" }}</h4>
|
||||
|
||||
{{ if .enforced }}
|
||||
<p
|
||||
data-test-id="p-enforced-TOTP"
|
||||
class="p-3 text-danger mb-0 font-weight-bold"
|
||||
>
|
||||
{{ tr "mfa-totp.template.enforced" }}
|
||||
</p>
|
||||
{{ end }}
|
||||
|
||||
|
||||
<div
|
||||
data-test-id="div-configure-TOTP"
|
||||
class="container p-3 m-0"
|
||||
>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6">
|
||||
<p>
|
||||
{{ tr "mfa-totp.template.instructions" }}
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
{{ tr "mfa-totp.template.lastpass" "lastpass" "https://lastpass.com/auth/" }}
|
||||
</li>
|
||||
<li>
|
||||
{{ tr "mfa-totp.template.gauth" "android" "https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2" "iphone" "https://apps.apple.com/us/app/google-authenticator/id388497605" }}
|
||||
</li>
|
||||
<li>
|
||||
{{ tr "mfa-totp.template.authy" "link" "https://authy.com" }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 p-0 mb-3">
|
||||
<img class="px-4 w-100" style="margin-top: -1rem; margin-bottom: -1rem;" src="{{ if .devQRImage }}{{ .devQRImage }}{{ else }}{{ links.MfaTotpQRImage }}{{ end }}" />
|
||||
<h5 class="px-4 text-center mb-3">{{ .secret }}</h5>
|
||||
|
||||
<form
|
||||
class="px-3"
|
||||
method="POST"
|
||||
action="{{ links.MfaTotpNewSecret }}"
|
||||
>
|
||||
{{ tr "mfa-totp.template.form.title" }}
|
||||
|
||||
{{ if .form.error }}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
{{ .form.error }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ .csrfField }}
|
||||
<div class="input-group my-3">
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
class="form-control lg text-center mfa-code-mask"
|
||||
name="code"
|
||||
maxlength="6"
|
||||
minlength="6"
|
||||
aria-required="true"
|
||||
placeholder="000 000"
|
||||
autocomplete="off"
|
||||
style="letter-spacing:5px;font-size:20px;"
|
||||
aria-label="Code">
|
||||
</div>
|
||||
|
||||
<button
|
||||
data-test-id="button-submit"
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
name="keep-session"
|
||||
value="true"
|
||||
type="submit"
|
||||
>
|
||||
{{ tr "mfa-totp.template.form.button" }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
106
server/auth/assets/templates/mfa.html.tpl
Normal file
106
server/auth/assets/templates/mfa.html.tpl
Normal file
@@ -0,0 +1,106 @@
|
||||
{{ template "inc_header.html.tpl" set . "hideNav" true }}
|
||||
<div class="card-body p-0 mb-2">
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "mfa.template.title" }}</h4>
|
||||
|
||||
{{ if .emailOtpPending }}
|
||||
<form
|
||||
class="p-3"
|
||||
method="POST"
|
||||
action="{{ links.Mfa }}"
|
||||
>
|
||||
<p>{{ tr "mfa.template.email.instructions" }}</p>
|
||||
|
||||
{{ if .form.emailOtpError }}
|
||||
<div class="text-danger my-4 font-weight-bold" role="alert">
|
||||
{{ .form.emailOtpError }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ .csrfField }}
|
||||
|
||||
|
||||
<div class="input-group my-3">
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
class="form-control text-center mfa-code-mask"
|
||||
name="code"
|
||||
maxlength="6"
|
||||
minlength="6"
|
||||
aria-required="true"
|
||||
placeholder="000 000"
|
||||
autocomplete="off"
|
||||
style="letter-spacing:5px;font-size:20px;"
|
||||
aria-label="{{ tr "mfa.template.email.code" }}">
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
name="action"
|
||||
value="verifyEmailOtp"
|
||||
type="submit"
|
||||
>
|
||||
{{ tr "mfa.template.email.verify" }}
|
||||
</button>
|
||||
|
||||
<a
|
||||
href="{{ links.Mfa }}?action=resendEmailOtp"
|
||||
class="btn btn-light btn-block btn-lg text-dark"
|
||||
name="action"
|
||||
value="resendEmailOtp"
|
||||
>
|
||||
{{ tr "mfa.template.email.resend" }}
|
||||
</a>
|
||||
</form>
|
||||
{{ else if not .emailOtpDisabled }}
|
||||
<p class="p-3 mb-0">
|
||||
<i class="bi bi-check-circle text-success h5 mr-1"></i> {{ tr "mfa.template.email.confirmed" }}
|
||||
</p>
|
||||
{{ end }}
|
||||
|
||||
{{ if .totpPending }}
|
||||
<form
|
||||
class="p-3"
|
||||
method="POST"
|
||||
action="{{ links.Mfa }}"
|
||||
>
|
||||
<p>{{ tr "mfa.template.totp.instructions" }}</p>
|
||||
|
||||
{{ if .form.totpError }}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
{{ .form.totpError }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ .csrfField }}
|
||||
|
||||
|
||||
<div class="input-group my-3">
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
class="form-control text-center mfa-code-mask"
|
||||
name="code"
|
||||
maxlength="6"
|
||||
minlength="6"
|
||||
aria-required="true"
|
||||
placeholder="000 000"
|
||||
autocomplete="off"
|
||||
style="letter-spacing:5px;font-size:20px;"
|
||||
aria-label="{{ tr "mfa.template.totp.code" }}">
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
type="submit"
|
||||
name="action"
|
||||
value="verifyTotp"
|
||||
>
|
||||
{{ tr "mfa.template.totp.verify" }}
|
||||
</button>
|
||||
</form>
|
||||
{{ else if and (not .totpDisabled) (not .totpPending) (not .totpUnconfigured) }}
|
||||
<p class="px-3 pt-3 pb-2 mb-0">
|
||||
<i class="bi bi-check-circle text-success h5 mr-1"></i> {{ tr "mfa.template.totp.confirmed" }}
|
||||
</p>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
@@ -0,0 +1,52 @@
|
||||
{{/* setting hideNav=true to root scope and passign it to header template */}}
|
||||
{{ template "inc_header.html.tpl" set . "hideNav" true }}
|
||||
<div class="card-body p-0">
|
||||
{{ if .invalidUser }}
|
||||
<div class="text-danger font-weight-bold p-3" role="alert">
|
||||
{{ tr "oauth2-authorize-client.template.errors.invalid-user" "link" links.Profile }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "oauth2-authorize-client.template.title" }} "{{ coalesce .client.Name }}"</h1>
|
||||
|
||||
<form
|
||||
action="{{ links.OAuth2AuthorizeClient }}"
|
||||
method="POST"
|
||||
class="p-3"
|
||||
>
|
||||
{{ .csrfField }}
|
||||
<p>
|
||||
{{ tr "oauth2-authorize-client.template.form.greeting-paragraph" }} {{ coalesce .user.Name .user.Handle .user.Email }},
|
||||
</p>
|
||||
<p>
|
||||
<b>{{ .client.Name }}</b> {{ tr "oauth2-authorize-client.template.form.question-for-client" }}
|
||||
</p>
|
||||
|
||||
<p class="text-center">
|
||||
<button
|
||||
data-test-id="button-allow"
|
||||
type="submit"
|
||||
name="allow"
|
||||
{{ if .disabled }}disabled{{ end }}
|
||||
class="btn btn-{{ if .disabled }}secondary{{ else }}primary{{ end }} btn-lg m-2"
|
||||
style="width:250px;"
|
||||
>
|
||||
{{ tr "oauth2-authorize-client.template.form.buttons.allow" }}
|
||||
</button>
|
||||
<button
|
||||
data-test-id="button-deny"
|
||||
type="submit"
|
||||
name="deny"
|
||||
class="btn btn-danger btn-lg m-2"
|
||||
style="width:250px;"
|
||||
>
|
||||
{{ tr "oauth2-authorize-client.template.form.buttons.deny" }}
|
||||
</button>
|
||||
</p>
|
||||
<div class="text-center">
|
||||
{{ tr "oauth2-authorize-client.template.links.mistake" }}
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
@@ -0,0 +1,15 @@
|
||||
{{ template "inc_header.html.tpl" . }}
|
||||
<div class="card-body p-0">
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "password-reset-requested.template.title" }}</h4>
|
||||
<div
|
||||
data-test-id="div-reset-instructions"
|
||||
class="p-3"
|
||||
role="alert"
|
||||
>
|
||||
{{ tr "password-reset-requested.template.instructions" }}
|
||||
</div>
|
||||
<div class="text-center my-3">
|
||||
{{ tr "password-reset-requested.template.links" "signup" links.Signup "login" links.Login }}</a>
|
||||
</div>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
@@ -0,0 +1,11 @@
|
||||
{{ template "inc_header.html.tpl" . }}
|
||||
<div class="card-body p-0">
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "pending-email-confirmation.template.title" }}</h4>
|
||||
<div class="p-3" role="alert">
|
||||
{{ tr "pending-email-confirmation.template.instructions" }}
|
||||
</div>
|
||||
<div class="text-center my-3">
|
||||
{{ tr "pending-email-confirmation.template.links" "signup" links.Signup "login" links.Login }}</a>
|
||||
</div>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
146
server/auth/assets/templates/profile.html.tpl
Normal file
146
server/auth/assets/templates/profile.html.tpl
Normal file
@@ -0,0 +1,146 @@
|
||||
{{ template "inc_header.html.tpl" set . "activeNav" "profile" }}
|
||||
<div class="card-body p-0">
|
||||
<form
|
||||
method="POST"
|
||||
action="{{ links.Profile }}"
|
||||
enctype="multipart/form-data"
|
||||
class="p-3"
|
||||
>
|
||||
{{ .csrfField }}
|
||||
|
||||
{{ if .form.error }}
|
||||
<div
|
||||
data-test-id="error"
|
||||
class="text-danger mb-4 font-weight-bold"
|
||||
role="alert"
|
||||
>
|
||||
{{ .form.error }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="profileFormEmail">{{ tr "profile.template.form.email.label" }}</label>
|
||||
<input
|
||||
data-test-id="input-email"
|
||||
type="email"
|
||||
class="form-control"
|
||||
name="email"
|
||||
id="profileFormEmail"
|
||||
placeholder="email@domain.ltd"
|
||||
autocomplete="username"
|
||||
readonly
|
||||
value="{{ .form.email }}"
|
||||
aria-label="{{ tr "profile.template.form.email.label" }}"
|
||||
>
|
||||
<div>
|
||||
{{ if .emailConfirmationRequired }}
|
||||
<div class="form-text text-danger">
|
||||
{{ tr "profile.template.form.email.resend-confirmation-link" "link" links.PendingEmailConfirmation }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="profileFormName">{{ tr "profile.template.form.name.label" }}</label>
|
||||
<input
|
||||
data-test-id="input-name"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="name"
|
||||
id="profileFormName"
|
||||
placeholder="{{ tr "profile.template.form.name.placeholder" }}"
|
||||
value="{{ .form.name }}"
|
||||
autocomplete="name"
|
||||
aria-label="{{ tr "profile.template.form.name.label" }}"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="profileFormHandle">{{ tr "profile.template.form.handle.label" }}</label>
|
||||
<input
|
||||
data-test-id="input-handle"
|
||||
type="text"
|
||||
class="form-control handle-mask"
|
||||
name="handle"
|
||||
id="profileFormHandle"
|
||||
placeholder="{{ tr "profile.template.form.handle.placeholder" }}"
|
||||
value="{{ .form.handle }}"
|
||||
autocomplete="handle"
|
||||
aria-label="{{ tr "profile.template.form.handle.label" }}"
|
||||
>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="profileFormPreferredLanguage">{{ tr "profile.template.form.preferred-language.label" }}</label>
|
||||
<select
|
||||
data-test-id="select-language"
|
||||
class="form-control"
|
||||
name="preferredLanguage"
|
||||
id="profileFormPreferredLanguage"
|
||||
aria-label="{{ tr "profile.template.form.preferred-language.label" }}"
|
||||
value="{{ .form.preferredLanguage }}"
|
||||
>
|
||||
{{ $prefLang := .form.preferredLanguage }}
|
||||
{{ range .languages }}
|
||||
<option
|
||||
value="{{ .Tag }}"
|
||||
{{ if eq $prefLang .Tag.String }}selected{{ end }}
|
||||
>
|
||||
{{ .LocalizedName }} ({{ .Name }})
|
||||
</option>
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{ if .avatarEnabled }}
|
||||
<hr/>
|
||||
<div class="mb-3">
|
||||
<label for="profileFormHandle">{{ tr "profile.template.form.avatar.label" }}</label>
|
||||
<div class="d-block">
|
||||
<img style="height: 4rem; width: 4rem;" class="rounded-circle" src="{{ .form.avatarUrl }}" alt="Profile Photo">
|
||||
<div class="mt-3">
|
||||
<label for="avatar" class="p-2 bg-light text-dark rounded" style="cursor: pointer;">
|
||||
{{ tr "profile.template.form.avatar.upload" }}
|
||||
</label>
|
||||
<input id="avatar" name="avatar" value="avatar" type="file" class="sr-only" accept="image/*">
|
||||
|
||||
{{ if .isAvatar }}
|
||||
<button
|
||||
name="avatar-delete"
|
||||
value="avatar-delete"
|
||||
class="ml-2 btn btn-danger"
|
||||
>
|
||||
{{ tr "profile.template.form.avatar.delete" }}
|
||||
</button>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row mb-3">
|
||||
<div class="col">
|
||||
<label for="initialColor">{{ tr "profile.template.form.avatar-initial.color" }}</label>
|
||||
<input type="color" id="initialColor" class="form-control input-color" value="{{ .form.initialTextColor }}" name="initial-color">
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<label for="customColor">{{ tr "profile.template.form.avatar-initial.background-color" }}</label>
|
||||
<input type="color" id="customColor" class="form-control input-color" value="{{ .form.initialBgColor }}" name="initial-bg">
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div>
|
||||
<button
|
||||
data-test-id="button-submit"
|
||||
type="submit"
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
>
|
||||
{{ tr "profile.template.form.buttons.submit" }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
49
server/auth/assets/templates/request-password-reset.html.tpl
Normal file
49
server/auth/assets/templates/request-password-reset.html.tpl
Normal file
@@ -0,0 +1,49 @@
|
||||
{{ template "inc_header.html.tpl" . }}
|
||||
<div class="card-body p-0">
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "request-password-reset.template.title" }}</h4>
|
||||
<form
|
||||
method="POST"
|
||||
action="{{ links.RequestPasswordReset }}"
|
||||
class="p-3"
|
||||
>
|
||||
{{ .csrfField }}
|
||||
{{ if .form.error }}
|
||||
<div
|
||||
data-test-id="error"
|
||||
class="text-danger font-weight-bold mb-4"
|
||||
role="alert"
|
||||
>
|
||||
{{ .form.error }}
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "request-password-reset.template.form.email.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-email"
|
||||
type="email"
|
||||
class="form-control"
|
||||
name="email"
|
||||
required
|
||||
placeholder="{{ tr "request-password-reset.template.form.email.placeholder" }}"
|
||||
autocomplete="username"
|
||||
value="{{ if .form }}{{ .form.email }}{{ end }}"
|
||||
aria-label="{{ tr "request-password-reset.template.form.email.label" }}"
|
||||
>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<button
|
||||
data-test-id="button-password-reset"
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
type="submit"
|
||||
>
|
||||
{{ tr "request-password-reset.template.form.buttons.request" }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="text-center my-3">
|
||||
{{ tr "request-password-reset.template.links" "signup" links.Signup "login" links.Login }}</a>
|
||||
</div>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
56
server/auth/assets/templates/reset-password.html.tpl
Normal file
56
server/auth/assets/templates/reset-password.html.tpl
Normal file
@@ -0,0 +1,56 @@
|
||||
{{ template "inc_header.html.tpl" . }}
|
||||
<div class="card-body p-0">
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "reset-password.template.title" }}</h4>
|
||||
<form
|
||||
method="POST"
|
||||
action="{{ links.ResetPassword }}"
|
||||
class="p-3"
|
||||
>
|
||||
{{ .csrfField }}
|
||||
{{ if .form.error }}
|
||||
<div class="text-danger font-weight-bold p-3" role="alert">
|
||||
{{ .form.error }}
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "reset-password.template.form.email.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-email"
|
||||
type="email"
|
||||
class="form-control"
|
||||
name="email"
|
||||
readonly
|
||||
placeholder="{{ tr "reset-password.template.form.email.placeholder" }}"
|
||||
value="{{ .user.Email }}"
|
||||
aria-label="{{ tr "reset-password.template.form.emaillabel" }}"
|
||||
>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "reset-password.template.form.new-password.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-new-password"
|
||||
type="password"
|
||||
required
|
||||
class="form-control"
|
||||
name="password"
|
||||
autocomplete="new-password"
|
||||
placeholder="{{ tr "reset-password.template.form.new-password.placeholder" }}"
|
||||
aria-label="{{ tr "reset-password.template.form.new-passwordlabel" }}"
|
||||
>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<button
|
||||
data-test-id="button-change-password"
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
type="submit"
|
||||
>
|
||||
{{ tr "reset-password.template.form.buttons.change-password" }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
233
server/auth/assets/templates/scenarios.yaml
Normal file
233
server/auth/assets/templates/scenarios.yaml
Normal file
@@ -0,0 +1,233 @@
|
||||
# The following list of templates and scenarios describes
|
||||
# all possible views (hopefully).
|
||||
#
|
||||
# Please read auth/README.adoc for details
|
||||
|
||||
error-internal:
|
||||
Default:
|
||||
error: |-
|
||||
Lorem ipsum dolor sit...
|
||||
|
||||
login:
|
||||
All disabled: {}
|
||||
|
||||
All enabled:
|
||||
settings:
|
||||
LocalEnabled: true
|
||||
SignupEnabled: true
|
||||
PasswordResetEnabled: true
|
||||
ExternalEnabled: true
|
||||
providers:
|
||||
- { Label: Google, Handle: google, Icon: google }
|
||||
- { Label: Facebook, Handle: facebook, Icon: facebook }
|
||||
- { Label: GitHub, Handle: github, Icon: github }
|
||||
- { Label: Corteza, Handle: corteza, Icon: shield-lock }
|
||||
|
||||
Only external:
|
||||
settings:
|
||||
PasswordResetEnabled: true
|
||||
ExternalEnabled: true
|
||||
providers:
|
||||
- { Label: Google, Handle: google, Icon: google }
|
||||
- { Label: Facebook, Handle: facebook, Icon: facebook }
|
||||
- { Label: GitHub, Handle: github, Icon: github }
|
||||
- { Label: Corteza, Handle: corteza, Icon: shield-lock }
|
||||
|
||||
Without signup and pass reset:
|
||||
settings:
|
||||
LocalEnabled: true
|
||||
SignupEnabled: false
|
||||
PasswordResetEnabled: false
|
||||
|
||||
With Split credentials check / username:
|
||||
form:
|
||||
splitCredentialsCheck: true
|
||||
settings:
|
||||
LocalEnabled: true
|
||||
|
||||
With errors after submit:
|
||||
settings:
|
||||
LocalEnabled: true
|
||||
form:
|
||||
email: some.email@example.tld
|
||||
error: "There was an error..."
|
||||
|
||||
security:
|
||||
Default:
|
||||
user: { ID: 123, Name: John Doe }
|
||||
settings:
|
||||
LocalEnabled: true
|
||||
MFA enabled:
|
||||
user: { ID: 123, Name: John Doe }
|
||||
settings:
|
||||
LocalEnabled: true
|
||||
MultiFactor:
|
||||
TOTP: { Enabled: true }
|
||||
EmailOTP: { Enabled: true }
|
||||
MFA enforced by user:
|
||||
user: { ID: 123, Name: John Doe }
|
||||
totpEnforced: false
|
||||
emailOtpEnforced: true
|
||||
settings:
|
||||
LocalEnabled: true
|
||||
MultiFactor:
|
||||
TOTP: { Enabled: true }
|
||||
EmailOTP: { Enabled: true }
|
||||
|
||||
mfa:
|
||||
Default: {}
|
||||
MFA pending:
|
||||
emailOtpPending: true
|
||||
totpDisabled: true
|
||||
TOTP pending:
|
||||
totpPending: true
|
||||
With error:
|
||||
emailOtpPending: true
|
||||
form:
|
||||
emailOtpError: "There was an error..."
|
||||
With alerts (toast):
|
||||
alerts:
|
||||
- Text: booya
|
||||
- Text: Red top border for errors
|
||||
Type: danger
|
||||
- Text: Modi sociosqu quibusdam modi delectus ridiculus per potenti sollicitudin dicta porro cumque, gravida odio? Tempora! Molestia
|
||||
Type: danger
|
||||
- Text: Primary toast
|
||||
Type: primary
|
||||
|
||||
|
||||
mfa-totp:
|
||||
Default:
|
||||
devQRImage: https://awgsalesservices.com/wp-content/uploads/2019/02/QR-code-example.jpg
|
||||
TOTP enforced:
|
||||
enforced: true
|
||||
devQRImage: https://awgsalesservices.com/wp-content/uploads/2019/02/QR-code-example.jpg
|
||||
|
||||
mfa-totp-disable:
|
||||
Default: {}
|
||||
With error:
|
||||
form:
|
||||
error: "There was an error..."
|
||||
|
||||
logout:
|
||||
Default:
|
||||
link: '#'
|
||||
With error:
|
||||
form:
|
||||
error: "There was an error..."
|
||||
|
||||
signup:
|
||||
Default: {}
|
||||
With error:
|
||||
form:
|
||||
error: "There was an error..."
|
||||
|
||||
reset-password:
|
||||
Default: {}
|
||||
|
||||
request-password-reset:
|
||||
Default: {}
|
||||
With error:
|
||||
form:
|
||||
error: "There was an error..."
|
||||
|
||||
password-reset-requested:
|
||||
Default: {}
|
||||
|
||||
pending-email-confirmation:
|
||||
Default:
|
||||
|
||||
profile:
|
||||
Default:
|
||||
user:
|
||||
ID: 123
|
||||
Name: John Doe
|
||||
settings:
|
||||
ExternalEnabled: true
|
||||
LocalEnabled: true
|
||||
With errros:
|
||||
user:
|
||||
ID: 123
|
||||
Name: John Doe
|
||||
settings:
|
||||
ExternalEnabled: true
|
||||
LocalEnabled: true
|
||||
form:
|
||||
error: Profile change form submit error
|
||||
name: foo
|
||||
email: foo
|
||||
With unconfirmed email:
|
||||
user:
|
||||
ID: 123
|
||||
Name: John Doe
|
||||
settings:
|
||||
ExternalEnabled: true
|
||||
LocalEnabled: true
|
||||
form:
|
||||
error: Profile change form submit error
|
||||
name: foo
|
||||
email: foo
|
||||
emailConfirmationRequired: true
|
||||
In OAuth2 flow:
|
||||
user:
|
||||
ID: 123
|
||||
Name: John Doe
|
||||
settings:
|
||||
ExternalEnabled: true
|
||||
LocalEnabled: true
|
||||
client:
|
||||
Name: foo
|
||||
emailConfirmationRequired: true
|
||||
|
||||
change-password:
|
||||
Default: {}
|
||||
With error:
|
||||
form:
|
||||
error: "There was an error..."
|
||||
|
||||
create-password:
|
||||
Default: {}
|
||||
With error:
|
||||
form:
|
||||
error: "There was an error..."
|
||||
|
||||
authorized-clients:
|
||||
Empty: {}
|
||||
Full:
|
||||
authorizedClients:
|
||||
- Name: Corteza Web Applications
|
||||
- Name: Matrix Chat server
|
||||
- Name: Company's Wordpress
|
||||
|
||||
oauth2-authorize-client:
|
||||
Default:
|
||||
client:
|
||||
Name: name of the client
|
||||
user:
|
||||
Name: John Doe
|
||||
|
||||
Disabled:
|
||||
invalidUser: Some good reason why this authorization of client is disabled...
|
||||
disabled: true
|
||||
client:
|
||||
Name: name of the client
|
||||
user:
|
||||
Name: John Doe
|
||||
|
||||
sessions:
|
||||
Full:
|
||||
sessions:
|
||||
- Current: true
|
||||
ExpiresIn: 3
|
||||
RemoteAddr: 4.224.2.3
|
||||
UserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36
|
||||
- ExpiresIn: 2
|
||||
RemoteAddr: 4.224.2.3
|
||||
SameRemoteAddr: true
|
||||
UserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36
|
||||
- ExpiresIn: 1
|
||||
RemoteAddr: 4.224.2.3
|
||||
SameUserAgent: true
|
||||
UserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36
|
||||
- ExpiresIn: 0
|
||||
UserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36
|
||||
122
server/auth/assets/templates/security.html.tpl
Normal file
122
server/auth/assets/templates/security.html.tpl
Normal file
@@ -0,0 +1,122 @@
|
||||
{{ template "inc_header.html.tpl" set . "activeNav" "security" }}
|
||||
<div class="card-body p-0">
|
||||
<form
|
||||
method="POST"
|
||||
action="{{ links.Security }}"
|
||||
class="p-3"
|
||||
>
|
||||
|
||||
{{ if .settings.LocalEnabled }}
|
||||
<h5>{{ tr "security.template.password.title" }}</h5>
|
||||
<a
|
||||
data-test-id="link-change-password"
|
||||
href="{{ links.ChangePassword }}"
|
||||
>
|
||||
{{ tr "security.template.password.change-link" }}
|
||||
</a>
|
||||
{{ end }}
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
{{ .csrfField }}
|
||||
<h5 class="mb-3">{{ tr "security.template.mfa.title" }}</h5>
|
||||
{{ if or .settings.MultiFactor.TOTP.Enabled .settings.MultiFactor.EmailOTP.Enabled }}
|
||||
{{ if .settings.MultiFactor.TOTP.Enabled }}
|
||||
<div class="mb-4">
|
||||
<label class="text-primary">{{ tr "security.template.mfa.totp.title" }}</label>
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
{{ if .totpEnforced }}
|
||||
<i class="bi bi-check-circle text-success h5 mr-1"></i>
|
||||
{{ else }}
|
||||
<i class="bi bi-exclamation-circle-fill text-danger h5 mr-1"></i>
|
||||
{{ end }}
|
||||
{{ if .totpEnforced }}
|
||||
{{ tr "security.template.mfa.totp.enforced" }}
|
||||
{{ else }}
|
||||
{{ tr "security.template.mfa.totp.disabled" }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<div class="ml-auto">
|
||||
{{ if .totpEnforced }}
|
||||
{{ if not .settings.MultiFactor.TOTP.Enforced }}
|
||||
<button
|
||||
data-test-id="button-disable-totp"
|
||||
name="action"
|
||||
value="disableTOTP"
|
||||
class="btn btn-danger"
|
||||
>
|
||||
{{ tr "security.template.mfa.totp.disable" }}
|
||||
</button>
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
<button
|
||||
data-test-id="button-configure-totp"
|
||||
name="action"
|
||||
value="configureTOTP"
|
||||
class="btn btn-primary"
|
||||
>
|
||||
{{ tr "security.template.mfa.totp.configure" }}
|
||||
</button>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ if .settings.MultiFactor.EmailOTP.Enabled }}
|
||||
<div class="mb-3">
|
||||
<label class="text-primary">{{ tr "security.template.mfa.email.title" }}</label class="text-primary">
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
{{ if .emailOtpEnforced }}
|
||||
<i class="bi bi-check-circle text-success h5 mr-1"></i>
|
||||
{{ else }}
|
||||
<i class="bi bi-exclamation-circle-fill text-danger h5 mr-1"></i>
|
||||
{{ end }}
|
||||
|
||||
{{ if .emailOtpEnforced }}
|
||||
{{ tr "security.template.mfa.email.enforced" }}
|
||||
{{ else }}
|
||||
{{ tr "security.template.mfa.email.disabled" }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<div class="ml-auto">
|
||||
{{ if .emailOtpEnforced }}
|
||||
{{ if not .settings.MultiFactor.EmailOTP.Enforced }}
|
||||
<button
|
||||
data-test-id="button-disable-email-otp"
|
||||
name="action"
|
||||
value="disableEmailOTP"
|
||||
class="btn btn-danger"
|
||||
>
|
||||
{{ tr "security.template.mfa.email.disable" }}
|
||||
</button>
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
<button
|
||||
data-test-id="button-enable-email-otp"
|
||||
name="action"
|
||||
value="enableEmailOTP"
|
||||
class="btn btn-primary"
|
||||
>
|
||||
{{ tr "security.template.mfa.email.enable" }}
|
||||
</button>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
<div class="mb-1 font-italic" role="alert">
|
||||
{{ tr "security.template.mfa.all-disabled" }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
68
server/auth/assets/templates/sessions.html.tpl
Normal file
68
server/auth/assets/templates/sessions.html.tpl
Normal file
@@ -0,0 +1,68 @@
|
||||
{{ template "inc_header.html.tpl" set . "activeNav" "sessions" }}
|
||||
<div class="card-body p-0">
|
||||
<form
|
||||
method="POST"
|
||||
action="{{ links.Sessions }}"
|
||||
>
|
||||
{{ .csrfField }}
|
||||
{{- if and .sessions (gt (len .sessions) 1) }}
|
||||
<div class="mb-0 p-3 border-bottom">
|
||||
<h4 class="card-title d-inline">{{ tr "sessions.template.title" }}</h4>
|
||||
<button
|
||||
data-test-id="button-logout-from-everywhere"
|
||||
type="submit"
|
||||
name="delete-all-but-current"
|
||||
value="true"
|
||||
class="btn btn-sm btn-danger float-right"
|
||||
>
|
||||
{{ tr "sessions.template.delete-all" }}
|
||||
</button>
|
||||
</div>
|
||||
{{ end }}
|
||||
</form>
|
||||
<form
|
||||
method="POST"
|
||||
action="{{ links.Sessions }}"
|
||||
class="p-3"
|
||||
>
|
||||
{{ .csrfField }}
|
||||
|
||||
{{ range .sessions}}
|
||||
<div class="mb-2 border-bottom">
|
||||
{{ if .Current }}
|
||||
<h5>{{ tr "sessions.template.list.current" }}</h5>
|
||||
{{ end }}
|
||||
<label class="mb-0 d-block">{{ tr "sessions.template.list.authorized-on" }}</label>
|
||||
<p class="w-75 d-inline-block">
|
||||
<time datetime="{{ .CreatedAt }}">{{ .CreatedAt | date "Mon, 02 Jan 2006 15:04 MST" }}</time>
|
||||
</p>
|
||||
<label class="mb-0 d-block">{{ tr "sessions.template.list.ip-address" }}</label>
|
||||
<p class="w-75 d-inline-block">{{ .RemoteAddr }}</p>
|
||||
{{ if .SameRemoteAddr}}
|
||||
<span class="badge badge-light float-right">{{ tr "sessions.template.list.same-machine" }}</span>
|
||||
{{ end }}
|
||||
<label class="mb-0 d-block">{{ tr "sessions.template.list.expires" }}</label>
|
||||
<p class="w-75 d-inline-block">
|
||||
<time datetime="{{ .ExpiresAt }}">{{ .ExpiresAt | date "Mon, 02 Jan 2006 15:04 MST" }}</time>
|
||||
</p>
|
||||
{{ if .Expired }}
|
||||
<span class="badge badge-warning float-right">{{ tr "sessions.template.list.expired" }}</span>
|
||||
{{ else if eq .ExpiresIn 0 }}
|
||||
<span class="badge badge-warning float-right">{{ tr "sessions.template.list.today" }}</span>
|
||||
{{ else if eq .ExpiresIn 1 }}
|
||||
<span class="badge badge-light float-right">{{ tr "sessions.template.list.tomorrow" }}</span>
|
||||
{{ else }}
|
||||
<span class="badge badge-light float-right">{{ tr "sessions.template.list.soon" "days" .ExpiresIn }}</span>
|
||||
{{ end }}
|
||||
<label class="mb-0 d-block">{{ tr "sessions.template.list.browser" }}</label>
|
||||
<p class="small w-75 d-inline-block">
|
||||
{{ .UserAgent }}
|
||||
</p>
|
||||
{{ if .SameUserAgent}}
|
||||
<span class="badge badge-light float-right">{{ tr "sessions.template.list.same-browser" }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</form>
|
||||
</div>
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
77
server/auth/assets/templates/signup.html.tpl
Normal file
77
server/auth/assets/templates/signup.html.tpl
Normal file
@@ -0,0 +1,77 @@
|
||||
{{ template "inc_header.html.tpl" . }}
|
||||
<div class="card-body p-0">
|
||||
<h4 class="mb-0 p-3 border-bottom">{{ tr "signup.template.title" }}</h4>
|
||||
<form
|
||||
method="POST"
|
||||
action="{{ links.Signup }}"
|
||||
class="p-3"
|
||||
>
|
||||
{{ .csrfField }}
|
||||
{{ if .form.error }}
|
||||
<div
|
||||
data-test-id="error"
|
||||
class="text-danger font-weight-bold mb-3"
|
||||
role="alert"
|
||||
>
|
||||
{{ .form.error }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "signup.template.form.email.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-email"
|
||||
type="email"
|
||||
class="form-control"
|
||||
name="email"
|
||||
required
|
||||
placeholder="{{ tr "signup.template.form.email.placeholder" }}"
|
||||
autocomplete="username"
|
||||
value="{{ .form.email }}"
|
||||
aria-label="{{ tr "signup.template.form.email.label" }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "signup.template.form.password.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-password"
|
||||
type="password"
|
||||
class="form-control"
|
||||
name="password"
|
||||
required
|
||||
placeholder="{{ tr "signup.template.form.password.placeholder" }}"
|
||||
autocomplete="new-password"
|
||||
aria-label="{{ tr "signup.template.form.password.label" }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label>
|
||||
{{ tr "signup.template.form.name.label" }}
|
||||
</label>
|
||||
<input
|
||||
data-test-id="input-name"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="name"
|
||||
placeholder="{{ tr "signup.template.form.name.placeholder" }}"
|
||||
value="{{ .form.name }}"
|
||||
autocomplete="name"
|
||||
aria-label="{{ tr "signup.template.form.name.label" }}">
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
id="submit"
|
||||
data-test-id="button-submit"
|
||||
class="btn btn-primary btn-block btn-lg"
|
||||
type="submit"
|
||||
>{{ tr "signup.template.form.button.sign-up" }}</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="text-center mt-2 mb-3">
|
||||
{{ tr "signup.template.log-in" "link" links.Login }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ template "inc_footer.html.tpl" . }}
|
||||
53
server/auth/assets/templates/template-dev.html.tpl
Normal file
53
server/auth/assets/templates/template-dev.html.tpl
Normal file
@@ -0,0 +1,53 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script type="application/javascript">
|
||||
window.addEventListener('load', function() {
|
||||
document.getElementById('preview').src=location.hash.substring(1)
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
<body class="bg-dark text-light">
|
||||
<div class="container-fluid">
|
||||
<div class="row m-0 p-0">
|
||||
<div class="col-3 pl-0">
|
||||
<sidebar class="vh-100 position-fixed w-25 overflow-auto">
|
||||
{{ range .templates }}
|
||||
<div class="pt-2 w-75">
|
||||
<code>{{ .Template }}.html.tpl</code>
|
||||
<ul class="nav flex-column">
|
||||
{{ range .Scenes }}
|
||||
<li class="nav-item border-top">
|
||||
<a target="preview"
|
||||
class="nav-link text-light"
|
||||
href="/auth/dev/scenarios?template={{ .Template }}&scene={{ .Name }}"
|
||||
onclick="location.hash=this.href"
|
||||
>
|
||||
<div>
|
||||
{{ .Name }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
{{ end }}
|
||||
<sidebar>
|
||||
</div>
|
||||
<div class="col-9 m-0 p-0">
|
||||
<iframe
|
||||
name="preview"
|
||||
id="preview"
|
||||
class="w-100 border-0"
|
||||
style="height: 100vh;"
|
||||
src="about:blank"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user