diff --git a/routeros_device.go b/routeros_device.go
index 50c19d1..4c65e25 100644
--- a/routeros_device.go
+++ b/routeros_device.go
@@ -58,7 +58,7 @@ func (dev *RouterosDevice) Init() { // {{{
// query sends a RouterOS REST API query and returns the unparsed body.
func (dev RouterosDevice) query(method, path string, reqBody []byte) (body []byte, err error) { // {{{
- url := fmt.Sprintf("https://%s:%d/rest%s", dev.Host, dev.Port, path)
+ url := fmt.Sprintf("https://%s/rest%s", dev.Host, path)
logger.Info("URL", "method", method, "url", url)
var request *http.Request
@@ -150,19 +150,6 @@ func (dev *RouterosDevice) UpdateDNSEntry(record DNSEntry) (entry DNSEntry, err
err = json.Unmarshal(body, &entry)
return
}// }}}
-func (dev *RouterosDevice) DeleteDNSEntry(id string) (err error) {
- _, err = dev.query("DELETE", "/ip/dns/static/"+id, []byte{})
- if err != nil {
- rosError := struct{ Detail string }{}
- if jsonError := json.Unmarshal([]byte(err.Error()), &rosError); jsonError == nil {
- logger.Error("routeros", "error", jsonError)
- err = errors.New(rosError.Detail)
- return
- }
- return
- }
- return
-}
/*
// FillPeerDetails retrieves RouterOS resource ID, allowed-address and comment from the router
diff --git a/static/css/index.css b/static/css/index.css
index ba6c2a1..6957ab1 100644
--- a/static/css/index.css
+++ b/static/css/index.css
@@ -2,6 +2,9 @@
--line-color: #ccc;
--line-color-record: #eee;
+ --type-background: #ddd;
+ --type-foreground: #000;
+
--label-first: #800033;
--label-rest: #666;
@@ -9,18 +12,6 @@
--label-border: #ccc;
--copy-color: #d48700;
-
- --header-line: #d0d0d0;
-
- --record-A: #89a02c;
- --record-AAAA: #2f4858;
- --record-CNAME: #f6ae2d;
- --record-FWD: #f26419;
- --record-TXT: #86bbd8;
- --record-NXDOMAIN: #aa0000;
- --record-other: #888;
-
- --record-hover: #fffff4;
}
html {
@@ -106,10 +97,6 @@ button {
cursor: pointer;
}
-#search {
- margin-bottom: 16px;
-}
-
#records-tree {
white-space: nowrap;
@@ -120,10 +107,6 @@ button {
padding-left: 0px;
}
- &.no-domain > .label {
- font-style: italic;
- }
-
&.open {
&>.label>img.open {
display: block;
@@ -146,7 +129,7 @@ button {
&>.label {
display: grid;
- grid-template-columns: repeat(4, min-content);
+ grid-template-columns: min-content min-content 1fr;
align-items: center;
padding: 5px 0px;
cursor: pointer;
@@ -157,18 +140,6 @@ button {
margin-right: 6px;
display: none;
}
-
- img.create {
- display: none;
- height: 16px;
- margin-left: 8px;
- }
-
- &:hover {
- img.create {
- display: block;
- }
- }
}
&>.subfolders {
@@ -178,51 +149,17 @@ button {
&>.records {
padding-left: 30px;
- padding-top: 8px;
- padding-bottom: 8px;
-
margin-left: 10px;
display: grid;
- grid-template-columns: repeat(6, min-content);
- width: min-content;
+ grid-template-columns: repeat(3, min-content) 1fr;
+ grid-gap: 4px 10px;
align-items: center;
border-left: 1px solid var(--line-color);
- .header {
- font-weight: bold;
- font-size: 0.75em;
- background: #eee;
- padding: 4px 8px;
- border-left: 1px solid var(--header-line);
- border-top: 1px solid var(--header-line);
- border-bottom: 1px solid var(--header-line);
-
- &:first-child {
- grid-column: 1 / 3;
- border-top-left-radius: 4px;
- }
-
- &.last {
- border-right: 1px solid var(--header-line);
- border-top-right-radius: 4px;
- }
- }
-
- &>:not(.header) {
- height: 40px;
- }
-
- &>.record-icon {
- border-left: 1px solid var(--header-line);
- align-content: center;
- padding-left: 8px;
- border-bottom: 1px solid var(--header-line);
-
- img {
- display: block;
- padding-left: 4px;
- }
+ &>img {
+ display: block;
+ padding-left: 4px;
}
.copy {
@@ -237,14 +174,6 @@ button {
cursor: pointer;
user-select: none;
display: flex;
- padding: 0 16px 0 8px;
- border-bottom: 1px solid var(--header-line);
- height: 100%;
- align-items: center;
-
- &.mouse-over {
- background-color: var(--record-hover);
- }
&.created {
* {
@@ -269,107 +198,34 @@ button {
.rest-label {
color: var(--label-rest);
-
- &.no-domain {
- font-style: italic;
- }
}
}
.type {
- padding: 2px 8px;
- border-bottom: 1px solid var(--header-line);
- border-left: 1px solid var(--header-line);
- align-content: center;
- cursor: pointer;
-
- &.mouse-over {
- background-color: var(--record-hover);
- }
-
- div {
- background-color: var(--record-other);
- color: #fff;
-
- padding: 4px 8px;
- border-radius: 4px;
- width: min-content;
- height: min-content;
- font-weight: bold;
- font-size: 0.85em;
- }
-
- &.A div {
- background-color: var(--record-A);
- }
-
- &.AAAA div {
- background-color: var(--record-AAAA);
- }
-
- &.CNAME div {
- background-color: var(--record-CNAME);
- color: #000;
- }
-
- &.FWD div {
- background-color: var(--record-FWD);
- }
-
- &.TXT div {
- background-color: var(--record-TXT);
- color: #000;
- }
-
- &.NXDOMAIN div {
- background-color: var(--record-NXDOMAIN);
- }
+ background-color: var(--type-background);
+ color: var(--type-foreground);
+ padding: 4px 8px;
+ border-radius: 4px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ width: min-content;
+ font-weight: bold;
+ font-size: 0.85em;
}
.value {
cursor: pointer;
user-select: none;
- border-left: 1px solid var(--header-line);
- border-bottom: 1px solid var(--header-line);
- padding: 0px 8px;
- height: 100%;
- align-content: center;
+ }
- &.mouse-over {
- background-color: var(--record-hover);
+ .separator {
+ grid-column: 1 / -1;
+
+ &:not(:last-child) {
+ border-bottom: 1px solid var(--line-color-record);
}
}
- .ttl {
- cursor: pointer;
- border-left: 1px solid var(--header-line);
- border-bottom: 1px solid var(--header-line);
- padding: 0px 8px;
- height: 100%;
- align-content: center;
-
- &.mouse-over {
- background-color: var(--record-hover);
- }
- }
-
- .actions {
- border-left: 1px solid var(--header-line);
- border-right: 1px solid var(--header-line);
- border-bottom: 1px solid var(--header-line);
- padding: 0px 8px;
- height: 100%;
- align-content: center;
-
- &.mouse-over {
- background-color: var(--record-hover);
- }
-
- img {
- display: block;
- cursor: pointer;
- }
- }
}
}
diff --git a/static/images/icon_delete.svg b/static/images/icon_delete.svg
deleted file mode 100644
index 0bc82d4..0000000
--- a/static/images/icon_delete.svg
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
diff --git a/static/js/dns.mjs b/static/js/dns.mjs
index 8f9195d..431521c 100644
--- a/static/js/dns.mjs
+++ b/static/js/dns.mjs
@@ -8,22 +8,10 @@ export class Application {
this.topFolder = new Folder(this, null, 'root')
this.recordsTree = null
this.settingsIcon = null
- this.createIcon = null
-
- this.searchFor = ''
this.renderFolders()
this.render()
}// }}}
- filteredRecords() {// {{{
- if (this.searchFor === '')
- return this.records
-
- const records = this.records.filter(r => {
- return (r.name().includes(this.searchFor))
- })
- return records
- }// }}}
parseRecords(recordsData) {// {{{
const records = recordsData.map(d => new Record(d))
return records
@@ -41,24 +29,14 @@ export class Application {
this.cleanFolders(folder)
})
}// }}}
- deleteRecord(id) {// {{{
- const i = this.records.findIndex(rec => rec.id() == id)
- this.records.splice(i, 1)
- }// }}}
renderFolders() {// {{{
- const records = this.filteredRecords()
- records.sort(this.sortRecords)
+ this.records.sort(this.sortRecords)
- for (const rec of records) {
- // It felt wrong when records for the base domain (e.g. google.com) was put in the top level domain (.com).
- // While technically correct, the first label (com) is grouped together with the second label (google).
- // Labels are counted reversely since the top domain is most significant.
- //
- // The `if` here is the exception for records that only has the two first labels. It would otherwise just
- // be an empty array of labels and thus discarded.
- let labels = rec.labels().reverse().slice(0, -1)
- if (rec.labels().length == 1)
- labels = rec.labels()
+
+ // rec: for example www.google.com
+ for (const rec of this.records) {
+ // com.google (reverse and remove wwww)
+ const labels = rec.labels().reverse().slice(0, -1)
// Start each record from the top and iterate through all its labels
// except the first one since that would be the actual record.
@@ -115,7 +93,10 @@ export class Application {
return 0
}// }}}
render() {// {{{
- if (this.createIcon === null) {
+ if (this.recordsTree == null) {
+ this.recordsTree = document.createElement('div')
+ this.recordsTree.id = 'records-tree'
+
this.createIcon = document.createElement('img')
this.createIcon.id = 'create-icon'
this.createIcon.src = `/images/${_VERSION}/icon_create.svg`
@@ -126,36 +107,13 @@ export class Application {
this.settingsIcon.src = `/images/${_VERSION}/icon_settings.svg`
this.settingsIcon.addEventListener('click', () => new SettingsDialog(this).show())
- const searchEl = document.createElement('div')
- searchEl.id = 'search'
- searchEl.innerHTML = `
-
-
- `
- this.searchField = searchEl.querySelector('.search-for')
- this.searchField.addEventListener('keydown', event => {
- if (event.key == 'Enter')
- this.search()
- })
- const search = searchEl.querySelector('button.search')
- search.addEventListener('click', () => this.search())
-
+ document.body.appendChild(this.recordsTree)
document.body.appendChild(this.settingsIcon)
document.body.appendChild(this.createIcon)
- document.body.appendChild(searchEl)
document.body.addEventListener('keydown', event => this.handlerKeys(event))
}
- // The recordstree is deleted when making a search and is therefore
- // not created along with icons and search above.
- if (this.recordsTree === null) {
- this.recordsTree = document.createElement('div')
- this.recordsTree.id = 'records-tree'
-
- document.body.appendChild(this.recordsTree)
- }
-
// Top root folder doesn't have to be shown.
const folders = Array.from(this.topFolder.subfolders.values())
folders.sort(this.sortFolders)
@@ -163,31 +121,11 @@ export class Application {
for (const folder of folders)
this.recordsTree.append(folder.render())
- this.removeEmptyFolders()
-
// Subscribe to settings update since the elements they will change
// exists now.
_mbus.subscribe('settings_updated', event => this.handlerSettingsUpdated(event.detail))
this.setBoxedFolders(this.settings.get('boxed_folders'))
- }// }}}
- removeEmptyFolders(folder) {// {{{
- if (folder === undefined)
- folder = this.topFolder
- folder.subfolders.forEach((folder, _label) => {
- this.removeEmptyFolders(folder)
- })
-
- // This is a leaf folder in the tree.
- // It has to be removed from the parent as well, since that could be up for
- // removal as well, all the way up the chain.
- if (folder.subfolders.size === 0 && folder.records.length === 0) {
- if (folder.parentFolder) {
- folder.parentFolder.subfolders.delete(folder.labels()[0])
- }
-
- folder.div?.remove()
- }
}// }}}
handlerKeys(event) {// {{{
let handled = true
@@ -205,10 +143,6 @@ export class Application {
new RecordDialog(new Record()).show()
break
- case 'f':
- this.searchField.focus()
- break
-
default:
handled = false
}
@@ -229,16 +163,6 @@ export class Application {
else
document.body.classList.remove('boxed-folders')
}// }}}
- search() {// {{{
- this.searchFor = this.searchField.value.trim().toLowerCase()
- this.recordsTree.remove()
- this.topFolder = new Folder(this, null, 'root')
- this.recordsTree = null
-
- this.cleanFolders()
- this.renderFolders()
- this.render()
- }// }}}
}
class Folder {
@@ -260,18 +184,7 @@ class Folder {
return this.folderName.toLowerCase()
}// }}}
labels() {// {{{
- let labels = this.name().split('.')
-
- // It is very uncommon to see just the top level domain.
- // We're much more used to google.com than com and then google.
- // First level is therefore the two most significant labels concatenated.
- if (labels.length > 1) {
- labels.reverse()
- labels = [`${labels[1]}.${labels[0]}`].concat(labels.slice(2))
- labels.reverse()
- }
-
- return labels
+ return this.name().split('.')
}// }}}
addRecord(rec) {// {{{
this.records.push(rec)
@@ -317,27 +230,14 @@ class Folder {
${firstLabel}${restLabels != '' ? '.' + restLabels : ''}
-