fix indentation
This commit is contained in:
parent
c04090adaf
commit
db82f8564c
7 changed files with 155 additions and 155 deletions
|
@ -2,21 +2,21 @@ const baseUrl = '/api/v1';
|
||||||
|
|
||||||
|
|
||||||
function apiGet(url) {
|
function apiGet(url) {
|
||||||
return fetch(`${baseUrl}/${url}`)
|
return fetch(`${baseUrl}/${url}`)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
// do something here
|
// do something here
|
||||||
throw new Error('Not ok');
|
throw new Error('Not ok');
|
||||||
}
|
}
|
||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getRecords(zone) {
|
function getRecords(zone) {
|
||||||
return apiGet(`zones/${zone}/records`)
|
return apiGet(`zones/${zone}/records`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getRecords,
|
getRecords,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,99 +2,99 @@ import { html, Component, render, createContext, useState, useEffect } from 'htt
|
||||||
import { getRecords } from './api.js';
|
import { getRecords } from './api.js';
|
||||||
|
|
||||||
const rdataInputProperties = {
|
const rdataInputProperties = {
|
||||||
Address: {label: 'adresse', type: 'text'},
|
Address: {label: 'adresse', type: 'text'},
|
||||||
Serial: {label: 'serial', type: 'number'},
|
Serial: {label: 'serial', type: 'number'},
|
||||||
Minimum: {label: 'minimum', type: 'number'},
|
Minimum: {label: 'minimum', type: 'number'},
|
||||||
Retry: {label: 'nouvelle tentative', type: 'number'},
|
Retry: {label: 'nouvelle tentative', type: 'number'},
|
||||||
Refresh: {label: 'actualisation', type: 'number'},
|
Refresh: {label: 'actualisation', type: 'number'},
|
||||||
MaintainerName: {label: 'contact', type: 'text'},
|
MaintainerName: {label: 'contact', type: 'text'},
|
||||||
MasterServerName: {label: 'serveur primaire', type: 'text'},
|
MasterServerName: {label: 'serveur primaire', type: 'text'},
|
||||||
Expire: {label: 'expiration', type: 'number'},
|
Expire: {label: 'expiration', type: 'number'},
|
||||||
Target: {label: 'cible', type: 'text'},
|
Target: {label: 'cible', type: 'text'},
|
||||||
}
|
}
|
||||||
|
|
||||||
const Editable = createContext(false);
|
const Editable = createContext(false);
|
||||||
|
|
||||||
|
|
||||||
function RDataInput({ name, value = '', index = 0 }) {
|
function RDataInput({ name, value = '', index = 0 }) {
|
||||||
const {label, type} = rdataInputProperties[name] || {label: name, type: 'text'};
|
const {label, type} = rdataInputProperties[name] || {label: name, type: 'text'};
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<${Editable.Consumer}>
|
<${Editable.Consumer}>
|
||||||
${
|
${
|
||||||
(editable) => {
|
(editable) => {
|
||||||
if (editable) {
|
if (editable) {
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div>
|
||||||
<label for=record_${index}_${name}>${label}:</label>
|
<label for=record_${index}_${name}>${label}:</label>
|
||||||
<input id=record_${index}_${name} type=${type} value=${value} />
|
<input id=record_${index}_${name} type=${type} value=${value} />
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div>
|
||||||
<span class=label>${label}:</span>
|
<span class=label>${label}:</span>
|
||||||
<span class=value>${value}</span>
|
<span class=value>${value}</span>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<//>
|
<//>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function RData({ rdata, index }) {
|
function RData({ rdata, index }) {
|
||||||
const { Address: address } = rdata;
|
const { Address: address } = rdata;
|
||||||
return Object.entries(rdata).map(([name, value]) => html`<${RDataInput} name=${name} value=${value} index=${index} />`);
|
return Object.entries(rdata).map(([name, value]) => html`<${RDataInput} name=${name} value=${value} index=${index} />`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function Record({name, ttl, type, rdata, index = 0}) {
|
function Record({name, ttl, type, rdata, index = 0}) {
|
||||||
return html`
|
return html`
|
||||||
<tr>
|
<tr>
|
||||||
<td class=domain>${name}</div>
|
<td class=domain>${name}</div>
|
||||||
<td class=type>${type}</div>
|
<td class=type>${type}</div>
|
||||||
<td class=ttl>${ttl}</div>
|
<td class=ttl>${ttl}</div>
|
||||||
<td class=rdata><${RData} rdata=${rdata} index=${index}/></div>
|
<td class=rdata><${RData} rdata=${rdata} index=${index}/></div>
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function RecordList({ zone }) {
|
function RecordList({ zone }) {
|
||||||
const [records, setRecords] = useState([]);
|
const [records, setRecords] = useState([]);
|
||||||
const [editable, setEditable] = useState(false);
|
const [editable, setEditable] = useState(false);
|
||||||
|
|
||||||
const toggleEdit = () => setEditable(!editable);
|
const toggleEdit = () => setEditable(!editable);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getRecords(zone)
|
getRecords(zone)
|
||||||
.then((res) => setRecords(res));
|
.then((res) => setRecords(res));
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<${Editable.Provider} value=${editable}>
|
<${Editable.Provider} value=${editable}>
|
||||||
<button onclick=${toggleEdit}>${ editable ? 'Save' : 'Edit'}</button>
|
<button onclick=${toggleEdit}>${ editable ? 'Save' : 'Edit'}</button>
|
||||||
<table class=record-list>
|
<table class=record-list>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Nom</th>
|
<th>Nom</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>TTL</th>
|
<th>TTL</th>
|
||||||
<th>Données</th>
|
<th>Données</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
${records.map(
|
${records.map(
|
||||||
({Name, Class, TTL, Type, ...rdata}, index) => {
|
({Name, Class, TTL, Type, ...rdata}, index) => {
|
||||||
return html`<${Record} name=${Name} ttl=${TTL} type=${Type} rdata=${rdata} index=${index}/>`
|
return html`<${Record} name=${Name} ttl=${TTL} type=${Type} rdata=${rdata} index=${index}/>`
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
</ul>
|
</ul>
|
||||||
<//>
|
<//>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { RecordList };
|
export { RecordList };
|
||||||
|
|
|
@ -1,41 +1,41 @@
|
||||||
body {
|
body {
|
||||||
color: #2e2033;
|
color: #2e2033;
|
||||||
}
|
}
|
||||||
.record-list {
|
.record-list {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
.record-list .rdata {
|
.record-list .rdata {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.record-list th, .record-list td {
|
.record-list th, .record-list td {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
padding: 0.25rem;
|
padding: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.record-list thead {
|
.record-list thead {
|
||||||
background: #ccb9ff;
|
background: #ccb9ff;
|
||||||
color: #39004d;
|
color: #39004d;
|
||||||
}
|
}
|
||||||
|
|
||||||
.record-list tbody tr:nth-child(even) td {
|
.record-list tbody tr:nth-child(even) td {
|
||||||
background: #ccb9ff3d;
|
background: #ccb9ff3d;
|
||||||
}
|
}
|
||||||
|
|
||||||
.record-list tbody tr .rdata span.label,
|
.record-list tbody tr .rdata span.label,
|
||||||
.record-list tbody tr .rdata label {
|
.record-list tbody tr .rdata label {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 0.1em 0.5em;
|
padding: 0.1em 0.5em;
|
||||||
background: #cecece;
|
background: #cecece;
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
margin-right: 0.1rem;
|
margin-right: 0.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.record-list tbody tr .rdata > div {
|
.record-list tbody tr .rdata > div {
|
||||||
margin: 0.1rem 0.5rem 0.1rem 0;
|
margin: 0.1rem 0.5rem 0.1rem 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,48 +10,48 @@ use tera::{Tera, Context};
|
||||||
|
|
||||||
|
|
||||||
pub struct TemplateState {
|
pub struct TemplateState {
|
||||||
tera: Tera,
|
tera: Tera,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TemplateState {
|
impl TemplateState {
|
||||||
pub fn new(template_directory: &Path) -> Self {
|
pub fn new(template_directory: &Path) -> Self {
|
||||||
let template_glob = template_directory.join("**").join("*");
|
let template_glob = template_directory.join("**").join("*");
|
||||||
match Tera::new(template_glob.to_str().expect("valid glob path string")) {
|
match Tera::new(template_glob.to_str().expect("valid glob path string")) {
|
||||||
Ok(tera) => TemplateState { tera },
|
Ok(tera) => TemplateState { tera },
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Loading templates failed: {}", e);
|
println!("Loading templates failed: {}", e);
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Template<'t, S: Serialize> {
|
pub struct Template<'t, S: Serialize> {
|
||||||
pub name: &'t str,
|
pub name: &'t str,
|
||||||
pub context: S,
|
pub context: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r, S: Serialize> Template<'r, S> {
|
impl<'r, S: Serialize> Template<'r, S> {
|
||||||
pub fn new(name: &'r str, context: S) -> Self {
|
pub fn new(name: &'r str, context: S) -> Self {
|
||||||
Template {
|
Template {
|
||||||
name,
|
name,
|
||||||
context
|
context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(self, tera: &Tera) -> Result<(ContentType, String), Status> {
|
fn render(self, tera: &Tera) -> Result<(ContentType, String), Status> {
|
||||||
let context = Context::from_serialize(self.context).map_err(|e| {
|
let context = Context::from_serialize(self.context).map_err(|e| {
|
||||||
error!("Failed to serialize context: {}", e);
|
error!("Failed to serialize context: {}", e);
|
||||||
Status::InternalServerError
|
Status::InternalServerError
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let content = tera.render(self.name, &context).map_err(|e| {
|
let content = tera.render(self.name, &context).map_err(|e| {
|
||||||
error!("Failed to render template `{}`: {}", self.name, e);
|
error!("Failed to render template `{}`: {}", self.name, e);
|
||||||
Status::InternalServerError
|
Status::InternalServerError
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok((ContentType::HTML, content))
|
Ok((ContentType::HTML, content))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r, 't, S: Serialize> Responder<'r, 'static> for Template<'t, S> {
|
impl<'r, 't, S: Serialize> Responder<'r, 'static> for Template<'t, S> {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>{% block title %}{% endblock title %}Nomilo</title>
|
<title>{% block title %}{% endblock title %}Nomilo</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/styles/main.css">
|
<link rel="stylesheet" type="text/css" href="/styles/main.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% block content %}{% endblock content %}
|
{% block content %}{% endblock content %}
|
||||||
{% block scripts %}{% endblock scripts %}
|
{% block scripts %}{% endblock scripts %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
{% block title %}Login ⋅ {% endblock title %}
|
{% block title %}Login ⋅ {% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main>
|
<main>
|
||||||
{% if error %}
|
{% if error %}
|
||||||
<p>
|
<p>
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<form method="POST" action="/login">
|
<form method="POST" action="/login">
|
||||||
<input type="text" name="username">
|
<input type="text" name="username">
|
||||||
<input type="password" name="password">
|
<input type="password" name="password">
|
||||||
<input type="submit" value="Se connecter">
|
<input type="submit" value="Se connecter">
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
{% block title %}{{ zone }} ⋅ Records ⋅ {% endblock title %}
|
{% block title %}{{ zone }} ⋅ Records ⋅ {% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main></main>
|
<main></main>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script type="module">
|
<script type="module">
|
||||||
const zoneName = "{{ zone }}";
|
const zoneName = "{{ zone }}";
|
||||||
|
|
||||||
import { RecordList } from '/scripts/records.js';
|
import { RecordList } from '/scripts/records.js';
|
||||||
import { html, render } from 'https://unpkg.com/htm/preact/standalone.mjs';
|
import { html, render } from 'https://unpkg.com/htm/preact/standalone.mjs';
|
||||||
|
|
||||||
render(html`<${RecordList} zone=${zoneName} />`, document.querySelector('main'));
|
render(html`<${RecordList} zone=${zoneName} />`, document.querySelector('main'));
|
||||||
</script>
|
</script>
|
||||||
{% endblock scripts %}
|
{% endblock scripts %}
|
||||||
|
|
Loading…
Reference in a new issue