diff --git a/public/scripts/records.js b/public/scripts/records.js
index 3339e40..3e65d50 100644
--- a/public/scripts/records.js
+++ b/public/scripts/records.js
@@ -1,117 +1,178 @@
-import { html, Component, render, createContext, useState, useEffect } from './vendor/preact/standalone.js';
+import { html, render, useState, useEffect } from './vendor/preact/standalone.js';
import { getRecords } from './api.js';
const rdataInputProperties = {
- Address: {label: 'adresse', type: 'text'},
- Serial: {label: 'serial', type: 'number'},
- Minimum: {label: 'minimum', type: 'number'},
- Retry: {label: 'nouvelle tentative', type: 'number'},
- Refresh: {label: 'actualisation', type: 'number'},
- MaintainerName: {label: 'contact', type: 'text'},
- MasterServerName: {label: 'serveur primaire', type: 'text'},
- Expire: {label: 'expiration', type: 'number'},
- Target: {label: 'cible', type: 'text'},
+ Address: {label: 'adresse :', type: 'text'},
+ Serial: {label: 'serial :', type: 'number'},
+ Minimum: {label: 'minimum :', type: 'number'},
+ Retry: {label: 'nouvelle tentative :', type: 'number'},
+ Refresh: {label: 'actualisation :', type: 'number'},
+ MaintainerName: {label: 'contact :', type: 'text'},
+ MasterServerName: {label: 'serveur primaire :', type: 'text'},
+ Expire: {label: 'expiration :', type: 'number'},
+ Target: {label: 'cible :', type: 'text'},
};
-const Editable = createContext(false);
+const recordTypes = {
+ 'A': 'address',
+ 'AAAA': 'address',
+ 'SRV': 'service',
+ 'CNAME': 'alias',
+ 'NS': 'name_server',
+ 'SOA': 'soa',
+};
-
-function RDataInput({ name, value = '', index = 0 }) {
- const {label, type} = rdataInputProperties[name] || {label: name, type: 'text'};
-
- return html`
- <${Editable.Consumer}>
- ${
- (editable) => {
- if (editable) {
- return html`
-
-
-
-
- `;
- } else {
- return html`
-
-
${label}:
- ${value}
-
- `;
- }
- }
- }
- />
- `;
+const recordTypeNames = {
+ 'address': 'Adresse IP',
+ 'service': 'Service',
+ 'alias': 'Alias',
+ 'name_server': 'Serveur de nom',
+ 'soa': 'SOA',
}
-function RData({ rdata, index }) {
- const { Address: address } = rdata;
- return Object.entries(rdata).map(([name, value]) => html`<${RDataInput} name=${name} value=${value} index=${index} />`);
+function getNameForRecord(name, type) {
+ return name;
}
+function getTypeForRecord(name, type) {
+ return recordTypes[type];
+}
-function Record({name, ttl, type, rdata, index = 0}) {
+function processRecords(records) {
+ return records.reduce((acc, record) => {
+ let name = getNameForRecord(record.Name, record.Type);
+ let type = getTypeForRecord(record.Name, record.Type);
+ if (!(name in acc)) {
+ acc[name] = {};
+ }
+ if (!(type in acc[name])) {
+ acc[name][type] = [];
+ }
+ acc[name][type].push(record);
+ return acc;
+ }, {});
+}
+const recordsKeys = {
+ 'address': (record) => { return [[ 'Address', record.Address ]] },
+ 'service': (record) => { /* TODO */ },
+ 'alias': (record) => { return [[ 'Target', record.Target ]] },
+ 'name_server': (record) => { return [[ 'Target', record.Target ]] },
+ 'soa': (record) => {
+ return [
+ [ 'MasterServerName', record.MasterServerName ],
+ [ 'MaintainerName', record.MaintainerName ],
+ [ 'Refresh', record.Refresh ],
+ [ 'Retry', record.Retry ],
+ [ 'Expire', record.Expire ],
+ [ 'Minimum', record.Minimum ],
+ [ 'Serial', record.Serial ],
+ ]
+ },
+}
+
+function FriendlyRecord({type, record}) {
+ let keys = recordsKeys[type](record);
+ if (keys.length == 1) {
+ return html`${keys[0][1]}`;
+ } else {
+ return html`
+
+ ${keys.map(([name, value]) => {return html`- ${rdataInputProperties[name].label}
- ${value}
`})}
+
+ `;
+ }
+}
+
+function RecordsByName({ name, recordSets }) {
return html`
-
- ${name}
- | ${type}
- | ${ttl}
- |
- <${Editable.Consumer}>
- ${
- (editable) => {
- if (editable) {
- return html`<${RData} rdata=${rdata} index=${index}/>`
- } else {
- return html`<${RData} rdata=${rdata} index=${index}/> `
- }
- }
+
+ ${name}
+
+ ${Object.entries(recordSets).map(
+ ([type, records]) => {
+ return html`
+
+ ${recordTypeNames[type]}
+
+ ${records.map(record => html`- <${FriendlyRecord} type=${type} record=${record}/>
`)}
+
+
+ `;
}
-
- />
+ )}
- |
+
`;
}
-function RecordList({ zone }) {
- const [records, setRecords] = useState([]);
- const [editable, setEditable] = useState(false);
- const toggleEdit = () => setEditable(!editable);
+
+function RecordListFriendly({ zone }) {
+ const [records, setRecords] = useState({});
+ const [editable, setEditable] = useState(false);
useEffect(() => {
getRecords(zone)
- .then((res) => setRecords(res));
- }, []);
-
+ .then((res) => setRecords(processRecords(res)));
+ }, [zone]);
return html`
- <${Editable.Provider} value=${editable}>
-
-
-
-
- Nom |
- Type |
- TTL |
- Données |
-
-
-
- ${records.map(
- ({Name, Class, TTL, Type, ...rdata}, index) => {
- return html`<${Record} name=${Name} ttl=${TTL} type=${Type} rdata=${rdata} index=${index}/>`
- }
- )}
-
-
- />
+ ${Object.entries(records).map(
+ ([name, recordSets]) => {
+ return html`
+
+ <${RecordsByName} name=${name} recordSets=${recordSets}/>
+ `;
+ }
+ )}
+ `;
+}
+
+function NewRecordFormFriendly({ zone }) {
+ return html`
+
+ `;
+}
+
+function ZoneRecords({ zone }) {
+ const [addNewRecord, setAddNewRecord] = useState(false);
+ const [newRecords, setNewRecords] = useState([]);
+
+ return html`
+
+ Enregistrements
+
+
+
+ ${newRecords}
+ <${RecordListFriendly} zone=${zone} />
`;
}
export default function(element, { zone }) {
- render(html`<${RecordList} zone=${zone} />`, element);
+ render(html`<${ZoneRecords} zone=${zone} />`, element);
};
diff --git a/public/styles/main.css b/public/styles/main.css
index 4c80f59..eb1e819 100644
--- a/public/styles/main.css
+++ b/public/styles/main.css
@@ -3,12 +3,13 @@ body {
min-height: 100vh;
min-width: 100vw;
margin: 0;
+ font-family: sans-serif;
}
:root {
- --color-primary: #712da0;
- --color-hightlight-1: #ffbac6;
- --color-hightlight-2: #f560f5;
+ --color-primary: #5e0c97;
+ --color-hightlight-1: #ffd4ba;
+ --color-hightlight-2: #dd39dd;
--color-contrast: white;
}
@@ -23,6 +24,10 @@ h1 {
margin-bottom: 1rem;
}
+a {
+ color: var(--color-primary)
+}
+
p.feedback {
padding: .35rem;
margin: 0;
@@ -33,13 +38,14 @@ p.feedback.error {
color: #710000;
}
+button,
input {
padding: .35rem .35rem;
font-size: 1rem;
}
+button,
input[type="submit"] {
- margin-top: 2rem;
background: var(--color-primary);
color: var(--color-contrast);
border-left: 5px solid var(--color-hightlight-1);
@@ -48,12 +54,21 @@ input[type="submit"] {
border-bottom: 5px solid var(--color-hightlight-2);
}
+button:hover,
input[type="submit"]:hover {
background: #7a43a1;
}
+button:active ,
input[type="submit"]:active {
- background: #875ba6;
+ border-left: 5px solid var(--color-hightlight-2);
+ border-top: 5px solid var(--color-hightlight-2);
+ border-right: 5px solid var(--color-hightlight-1);
+ border-bottom: 5px solid var(--color-hightlight-1);
+}
+
+form input[type="submit"] {
+ margin-top: 2rem;
}
form label {
@@ -71,7 +86,7 @@ nav.main {
display: flex;
flex: 0;
padding: 1rem;
- border-right: 5px solid var(--color-hightlight-1);
+ border-right: 5px solid var(--color-hightlight-2);
}
nav.main a {
diff --git a/public/styles/zone.css b/public/styles/zone.css
index 1486cb3..7414673 100644
--- a/public/styles/zone.css
+++ b/public/styles/zone.css
@@ -12,3 +12,105 @@ nav.secondary li {
main {
flex-direction: column;
}
+
+main > section {
+ max-width: 120ch;
+}
+
+header {
+ display: flex;
+ margin: 1rem 0;
+}
+
+h2 {
+ margin: 0;
+ flex-grow: 1;
+}
+header > :not(:last-of-type) {
+ margin-right: 2ch;
+}
+
+zone-content h3, zone-content h4 {
+ margin: 0;
+ font-weight: normal;
+ font-size: 1rem;
+ width: 30%;
+}
+
+zone-content article {
+ display: flex;
+}
+
+zone-content > article > div {
+ flex-grow: 1;
+}
+
+zone-content > article {
+ margin: .5rem 0;
+ position: relative;
+}
+
+zone-content > article:not(:last-of-type) {
+ border-bottom: 2px solid var(--color-hightlight-2);
+}
+
+zone-content article > *{
+ margin-right: 2ch;
+}
+
+zone-content article ul {
+ padding: 0;
+ margin: 0;
+ list-style-type: none;
+}
+
+zone-content article dl {
+ display: grid;
+ grid-template: auto / max-content 1fr;
+}
+
+zone-content article dd {
+ margin: 0;
+}
+
+zone-content article dt span {
+ display: inline-block;
+ background-color: var(--color-hightlight-1);
+ padding: 0.1em 0.5em;
+ border-radius: 0.5em;
+ margin-right: 0.1rem;
+ font-size: .7rem;
+}
+
+form.new-record {
+ display: flex;
+ flex-direction: row;
+}
+
+form.new-record > div {
+ display: flex;
+ flex-direction: column;
+ margin-right: 2ch;
+}
+
+form.new-record > div:first-child {
+ width: 30%;
+}
+
+form.new-record > div:first-child span {
+ flex-grow: 1;
+ font-size: .8rem;
+}
+
+form.new-record > div:nth-child(2) {
+ width: calc( .3 * (70% - 4ch));
+}
+
+
+form.new-record > div:nth-child(2) select {
+ flex-grow: 1;
+}
+
+form.new-record > div:nth-child(3) {
+ flex: 1;
+}
diff --git a/src/controllers.rs b/src/controllers.rs
index 1a27199..577a4c0 100644
--- a/src/controllers.rs
+++ b/src/controllers.rs
@@ -13,7 +13,7 @@ pub async fn do_login(
auth_request: models::AuthTokenRequest,
cookies: &CookieJar<'_>
) -> Result {
- let session_duration = config.web_app.token_duration;
+ let session_duration = config.web_app.token_duration;
let session = conn.run(move |c| {
let user_info = models::LocalUser::get_user_by_creds(
diff --git a/templates/bases/app.html b/templates/bases/app.html
index f03a505..e36c1b1 100644
--- a/templates/bases/app.html
+++ b/templates/bases/app.html
@@ -4,7 +4,7 @@
{% block content %}