wip frontend
This commit is contained in:
parent
db82f8564c
commit
756c31bad7
13 changed files with 193 additions and 49 deletions
|
@ -9,12 +9,12 @@ function apiGet(url) {
|
|||
throw new Error('Not ok');
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function getRecords(zone) {
|
||||
return apiGet(`zones/${zone}/records`)
|
||||
return apiGet(`zones/${zone}/records`);
|
||||
}
|
||||
|
||||
export {
|
||||
|
|
|
@ -11,7 +11,7 @@ const rdataInputProperties = {
|
|||
MasterServerName: {label: 'serveur primaire', type: 'text'},
|
||||
Expire: {label: 'expiration', type: 'number'},
|
||||
Target: {label: 'cible', type: 'text'},
|
||||
}
|
||||
};
|
||||
|
||||
const Editable = createContext(false);
|
||||
|
||||
|
@ -33,10 +33,10 @@ function RDataInput({ name, value = '', index = 0 }) {
|
|||
} else {
|
||||
return html`
|
||||
<div>
|
||||
<span class=label>${label}:</span>
|
||||
<span class=value>${value}</span>
|
||||
<dt>${label}:</dt>
|
||||
<dd>${value}</dd>
|
||||
</div>
|
||||
`
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,20 @@ function Record({name, ttl, type, rdata, index = 0}) {
|
|||
<td class=domain>${name}</div>
|
||||
<td class=type>${type}</div>
|
||||
<td class=ttl>${ttl}</div>
|
||||
<td class=rdata><${RData} rdata=${rdata} index=${index}/></div>
|
||||
<td class=rdata>
|
||||
<${Editable.Consumer}>
|
||||
${
|
||||
(editable) => {
|
||||
if (editable) {
|
||||
return html`<${RData} rdata=${rdata} index=${index}/>`
|
||||
} else {
|
||||
return html`<dl><${RData} rdata=${rdata} index=${index}/></dl>`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<//>
|
||||
</div>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
|
@ -70,13 +83,13 @@ function RecordList({ zone }) {
|
|||
useEffect(() => {
|
||||
getRecords(zone)
|
||||
.then((res) => setRecords(res));
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
|
||||
return html`
|
||||
<${Editable.Provider} value=${editable}>
|
||||
<button onclick=${toggleEdit}>${ editable ? 'Save' : 'Edit'}</button>
|
||||
<table class=record-list>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nom</th>
|
||||
|
|
|
@ -1,33 +1,43 @@
|
|||
body {
|
||||
color: #2e2033;
|
||||
}
|
||||
.record-list {
|
||||
border-collapse: collapse;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.record-list .rdata {
|
||||
main {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
zone-content table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
zone-content .rdata {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.record-list th, .record-list td {
|
||||
zone-content th, .zone-content td {
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.record-list thead {
|
||||
zone-content thead {
|
||||
background: #ccb9ff;
|
||||
color: #39004d;
|
||||
}
|
||||
|
||||
.record-list tbody tr:nth-child(even) td {
|
||||
zone-content tbody tr:nth-child(even) td {
|
||||
background: #ccb9ff3d;
|
||||
}
|
||||
|
||||
.record-list tbody tr .rdata span.label,
|
||||
.record-list tbody tr .rdata label {
|
||||
zone-content tbody tr .rdata dt,
|
||||
zone-content tbody tr .rdata label {
|
||||
display: inline-block;
|
||||
padding: 0.1em 0.5em;
|
||||
background: #cecece;
|
||||
|
@ -35,7 +45,18 @@ body {
|
|||
border-radius: 0.5em;
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
|
||||
.record-list tbody tr .rdata > div {
|
||||
margin: 0.1rem 0.5rem 0.1rem 0;
|
||||
zone-content tbody tr .rdata dd {
|
||||
margin: 0;
|
||||
}
|
||||
zone-content tbody tr .rdata dl {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
zone-content tbody tr .rdata div {
|
||||
margin: 0.1rem 0.5rem 0.1rem 0;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@ impl NomiloCommand for RunServerCommand {
|
|||
.mount("/", routes![
|
||||
ui::get_login_page,
|
||||
ui::post_login_page,
|
||||
ui::get_zones_page,
|
||||
ui::get_zone_records_page,
|
||||
])
|
||||
.mount("/", static_files)
|
||||
|
|
|
@ -18,7 +18,7 @@ pub struct LoginPage {
|
|||
|
||||
#[get("/login")]
|
||||
pub async fn get_login_page() -> Template<'static, LoginPage> {
|
||||
Template::new("login.html", LoginPage { error: None })
|
||||
Template::new("pages/login.html", LoginPage { error: None })
|
||||
}
|
||||
|
||||
#[post("/login", data = "<auth_request>")]
|
||||
|
@ -38,7 +38,7 @@ pub async fn post_login_page(
|
|||
match res {
|
||||
Ok(_) => Ok(Redirect::to(uri!("/zones"))),
|
||||
Err(models::UserError::BadCreds) => Err(Either::Left(Template::new(
|
||||
"login.html",
|
||||
"pages/login.html",
|
||||
LoginPage {
|
||||
error: Some("Identifants incorrects".to_string())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use serde_json::{Value, json};
|
||||
use serde::Serialize;
|
||||
use rocket::http::{Status};
|
||||
use rocket::http::uri::Origin;
|
||||
|
||||
use crate::template::Template;
|
||||
use crate::models;
|
||||
|
@ -11,20 +13,52 @@ pub struct RecordsPage {
|
|||
zone: String
|
||||
}
|
||||
|
||||
|
||||
// TODO: Check if origin changes if application mounted on different path
|
||||
#[get("/zone/<zone>/records")]
|
||||
pub async fn get_zone_records_page(user_info: models::UserInfo, zone: models::AbsoluteName, conn: DbConn) -> Result<Template<'static, RecordsPage>, Status> {
|
||||
pub async fn get_zone_records_page(user_info: models::UserInfo, zone: models::AbsoluteName, conn: DbConn, origin: &Origin<'_>) -> Result<Template<'static, Value>, Status> {
|
||||
let zone_name = zone.to_utf8();
|
||||
|
||||
conn.run(move |c| {
|
||||
let zones = conn.run(move |c| {
|
||||
if user_info.is_admin() {
|
||||
models::Zone::get_by_name(c, &zone_name)
|
||||
models::Zone::get_by_name(c, &zone_name)?;
|
||||
models::Zone::get_all(c)
|
||||
} else {
|
||||
user_info.get_zone(c, &zone_name)
|
||||
user_info.get_zone(c, &zone_name)?;
|
||||
user_info.get_zones(c)
|
||||
|
||||
}
|
||||
}).await.map_err(|e| models::ErrorResponse::from(e).status)?;
|
||||
|
||||
|
||||
Ok(Template::new("zone/records.html", RecordsPage {
|
||||
zone: zone.to_utf8(),
|
||||
}))
|
||||
Ok(Template::new(
|
||||
"pages/zone/records.html",
|
||||
json!({
|
||||
"current_zone": zone.to_utf8(),
|
||||
"zones": zones,
|
||||
"nav_page": origin.clone().into_normalized().path().as_str(),
|
||||
"nav_sections": vec!["zones", zone.to_utf8().as_str()],
|
||||
})
|
||||
))
|
||||
}
|
||||
|
||||
#[get("/zones")]
|
||||
pub async fn get_zones_page(user_info: models::UserInfo, conn: DbConn, origin: &Origin<'_>) -> Result<Template<'static, Value>, Status> {
|
||||
let zones = conn.run(move |c| {
|
||||
if user_info.is_admin() {
|
||||
models::Zone::get_all(c)
|
||||
} else {
|
||||
user_info.get_zones(c)
|
||||
}
|
||||
}).await.map_err(|e| models::ErrorResponse::from(e).status)?;
|
||||
|
||||
|
||||
Ok(Template::new(
|
||||
"pages/zones.html",
|
||||
json!({
|
||||
"zones": zones,
|
||||
"nav_page": origin.clone().into_normalized().path().as_str(),
|
||||
"nav_sections": vec!["zones"],
|
||||
})
|
||||
))
|
||||
}
|
||||
|
|
34
templates/bases/app.html
Normal file
34
templates/bases/app.html
Normal file
|
@ -0,0 +1,34 @@
|
|||
{% extends "bases/base.html" %}
|
||||
{% import "macros.html" as macros %}
|
||||
|
||||
{% block content %}
|
||||
<nav aria-label="Principal">
|
||||
<ul>
|
||||
<li><a href="/profil">Mon profile</a></li>
|
||||
<li>
|
||||
{{ macros::nav_link(
|
||||
content="Mes zones",
|
||||
href="/zones",
|
||||
current_page=nav_page,
|
||||
section="zones",
|
||||
current_sections=nav_sections,
|
||||
) }}
|
||||
<ul>
|
||||
{% for zone in zones %}
|
||||
<li>
|
||||
{{ macros::nav_link(
|
||||
content=zone.name,
|
||||
href="/zone/" ~ zone.name,
|
||||
current_page=nav_page,
|
||||
section=zone.name,
|
||||
current_sections=nav_sections,
|
||||
) }}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<main>
|
||||
{% block main %}{% endblock main %}
|
||||
</main>
|
||||
{% endblock content %}
|
11
templates/macros.html
Normal file
11
templates/macros.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
{% macro nav_link(content, href, current_page, section=False, current_sections=False, props='') %}
|
||||
<a
|
||||
href="{{ href }}"
|
||||
{{ props }}
|
||||
{% if current_page == href %}
|
||||
aria-current="page"
|
||||
{% elif section and section in current_sections %}
|
||||
aria-current="location"
|
||||
{% endif %}
|
||||
>{{ content }}</a>
|
||||
{% endmacro nav_link %}
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base.html" %}
|
||||
{% extends "bases/base.html" %}
|
||||
|
||||
{% block title %}Login ⋅ {% endblock title %}
|
||||
|
45
templates/pages/zone/records.html
Normal file
45
templates/pages/zone/records.html
Normal file
|
@ -0,0 +1,45 @@
|
|||
{% extends "bases/app.html" %}
|
||||
{% import "macros.html" as macros %}
|
||||
|
||||
{% block title %}{{ current_zone }} ⋅ Records ⋅ {% endblock title %}
|
||||
|
||||
{% block main %}
|
||||
<h1>Gestion la zone {{ current_zone }}</h1>
|
||||
<nav aria-label="Secondaire">
|
||||
<ul>
|
||||
<li>
|
||||
{{ macros::nav_link(
|
||||
content="Enregistrements",
|
||||
href="/zone/" ~ current_zone ~ "/records",
|
||||
current_page=nav_page,
|
||||
) }}
|
||||
</li>
|
||||
<li>
|
||||
{{ macros::nav_link(
|
||||
content="Membres",
|
||||
href="/zone/" ~ current_zone ~ "/members",
|
||||
current_page=nav_page,
|
||||
) }}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<section>
|
||||
<h2>Enregistrements</h2>
|
||||
<zone-content>
|
||||
</zone-content>
|
||||
</section>
|
||||
<aside>
|
||||
<h2>Aide</h2>
|
||||
</aside>
|
||||
{% endblock main %}
|
||||
|
||||
{% block scripts %}
|
||||
<script type="module">
|
||||
const zoneName = '{{ current_zone }}';
|
||||
|
||||
import { RecordList } from '/scripts/records.js';
|
||||
import { html, render } from 'https://unpkg.com/htm/preact/standalone.mjs';
|
||||
|
||||
render(html`<${RecordList} zone=${zoneName} />`, document.querySelector('zone-content'));
|
||||
</script>
|
||||
{% endblock scripts %}
|
3
templates/pages/zones.html
Normal file
3
templates/pages/zones.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
{% extends "bases/app.html" %}
|
||||
|
||||
{% block title %}Zones ⋅ {% endblock title %}
|
|
@ -1,18 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ zone }} ⋅ Records ⋅ {% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<main></main>
|
||||
{% endblock content %}
|
||||
|
||||
{% block scripts %}
|
||||
<script type="module">
|
||||
const zoneName = "{{ zone }}";
|
||||
|
||||
import { RecordList } from '/scripts/records.js';
|
||||
import { html, render } from 'https://unpkg.com/htm/preact/standalone.mjs';
|
||||
|
||||
render(html`<${RecordList} zone=${zoneName} />`, document.querySelector('main'));
|
||||
</script>
|
||||
{% endblock scripts %}
|
Loading…
Reference in a new issue