import { templated } from 'atlibs/component/index.js' const Base = await templated(new URL('./marque-dns.html', import.meta.url)) const cell = (text) => Object.assign(document.createElement('td'), { textContent: text ?? '' }) const button = (text, onclick) => Object.assign(document.createElement('button'), { type: 'button', textContent: text, onclick }) // Markup in .html; this sends events up (login, logout, view, open, dns-change) and renders the cubit's state. customElements.define('marque-dns', class extends Base { connectedCallback() { super.connectedCallback() const $ = (selector) => this.querySelector(selector) this.send = (name, detail) => this.dispatchEvent(new CustomEvent(name, { bubbles: true, detail })) $('.login').onsubmit = (e) => (e.preventDefault(), this.send('login', e.target.elements.handle.value)) $('.view').onsubmit = (e) => (e.preventDefault(), this.send('view', e.target.elements.did.value.trim())) $('.logout').onclick = () => this.send('logout') $('.cancel').onclick = () => this.edit(null) $('.record').onsubmit = (e) => { e.preventDefault() const f = Object.fromEntries(new FormData(e.target)) const set = { ttl: f.ttl, priority: f.priority } if (f.entry === 'create_record') this.send('dns-change', { entry: f.entry, fields: { name: f.newName, type: f.newType, value: f.newValue, ...set } }) else this.send('dns-change', { entry: f.entry, fields: { name: f.name, type: f.type, value: f.value, newName: f.newName, newValue: f.newValue, ...set } }) } } // Fill the form to change a record, or (null) back to adding one. The type of a record stays its own. edit(record) { const form = this.querySelector('.record') const el = form.elements // not form.name: that is the form's own name attribute form.reset() el.entry.value = record ? 'update_record' : 'create_record' el.newType.disabled = !!record form.querySelector('h3').textContent = record ? `Change ${record.recordType} ${record.name}` : 'Add a record' form.querySelector('.save').textContent = record ? 'Save' : 'Add' form.querySelector('.cancel').hidden = !record if (!record) return el.name.value = el.newName.value = record.name el.type.value = el.newType.value = record.recordType el.value.value = el.newValue.value = record.value el.ttl.value = record.ttl ?? '' el.priority.value = record.priority ?? '' } render({ session, did, error, domains, domain, zone, change }) { const $ = (selector) => this.querySelector(selector) const signedIn = session === 'signed-in' $('.login').hidden = $('.view').hidden = session !== 'signed-out' $('.who').hidden = !signedIn $('.who span').textContent = signedIn ? `Signed in as ${did}` : '' $('.error').textContent = error ?? domains.error ?? zone.error ?? '' const list = $('.domains') list.replaceChildren(...(domains.result?.domains ?? []).map((d) => { const item = document.createElement('li') item.append(button(d.domain, () => this.send('open', d.domain)), ` ${d.status ?? ''}${d.expiresAt ? `, expires ${d.expiresAt.slice(0, 10)}` : ''}`) return item })) if (domains.status === 'done' && !list.childElementCount) list.textContent = 'No at.marque.domain records in this account. Register a domain at marque.at.' $('.zone').hidden = !domain $('.zone-name').textContent = domain ?? '' $('.record').hidden = !signedIn $('.record .save').disabled = change.status === 'busy' $('tbody').replaceChildren(...(zone.result?.records ?? []).map((r) => { const row = document.createElement('tr') const actions = document.createElement('td') if (signedIn) { actions.append( button('Edit', () => this.edit(r)), button('Remove', () => confirm(`Remove ${r.recordType} ${r.name} ${r.value}?`) && this.send('dns-change', { entry: 'delete_record', fields: { name: r.name, type: r.recordType, value: r.value } })), ) } row.append(cell(r.name), cell(r.recordType), cell(r.value), cell(String(r.ttl ?? '')), cell(r.priority === undefined ? '' : String(r.priority)), actions) return row })) if (change.status === 'done') this.edit(null) $('.out').textContent = change.error ?? (change.result ? `Saved: ${change.result.records} records, ${change.result.uri}` : '') } })