mirror of
https://github.com/1f349/admin.1f349.com.git
synced 2024-11-12 14:41:34 +00:00
Start working on domain management tab
This commit is contained in:
parent
f55e6c798a
commit
2f6d043b63
53
src/components/domains/ARow.svelte
Normal file
53
src/components/domains/ARow.svelte
Normal file
@ -0,0 +1,53 @@
|
||||
<script lang="ts">
|
||||
import {isAaaaRecord, isARecord, type AaaaRecord, type ARecord} from "../../stores/records";
|
||||
import type {RestItem} from "../../utils/rest-table";
|
||||
import ActionMenu from "../ActionMenu.svelte";
|
||||
import ActionPopup from "../ActionPopup.svelte";
|
||||
|
||||
export let value: RestItem<ARecord | AaaaRecord>;
|
||||
let editItem: ARecord & AaaaRecord = {
|
||||
Hdr: {
|
||||
Name: "",
|
||||
Rrtype: 0,
|
||||
Class: 0,
|
||||
Ttl: 0,
|
||||
},
|
||||
A: "",
|
||||
AAAA: "",
|
||||
};
|
||||
|
||||
let editPopup: boolean = false;
|
||||
|
||||
function save() {
|
||||
value.update(editItem);
|
||||
}
|
||||
</script>
|
||||
|
||||
<tr>
|
||||
<td class="code-font">{value.data.Hdr.Name}</td>
|
||||
<td class="code-font">{isARecord(value.data) ? value.data.A : isAaaaRecord(value.data) ? value.data.AAAA : ""}</td>
|
||||
<td>
|
||||
<ActionMenu
|
||||
data={value}
|
||||
edit={() => {
|
||||
editItem = JSON.parse(JSON.stringify(value.data));
|
||||
editPopup = true;
|
||||
}}
|
||||
remove={() => value.remove()}
|
||||
/>
|
||||
|
||||
<ActionPopup name="Edit {isARecord(value.data) ? 'A' : 'AAAA'} Record" bind:show={editPopup} on:save={save}>
|
||||
<div>Name</div>
|
||||
<div class="code-font">{editItem.Hdr.Name}</div>
|
||||
{#if isARecord(value.data)}
|
||||
<div>IPv4 Address</div>
|
||||
<div><input type="text" class="code-font" bind:value={editItem.A} size={Math.max(20, editItem.A.length + 2)} /></div>
|
||||
{:else if isAaaaRecord(value.data)}
|
||||
<div>IPv6 Address</div>
|
||||
<div><input type="text" class="code-font" bind:value={editItem.AAAA} size={Math.max(20, editItem.AAAA.length + 2)} /></div>
|
||||
{:else}
|
||||
<div>Pretty sure something is broken. WOMP WOMP!!</div>
|
||||
{/if}
|
||||
</ActionPopup>
|
||||
</td>
|
||||
</tr>
|
45
src/components/domains/CnameRow.svelte
Normal file
45
src/components/domains/CnameRow.svelte
Normal file
@ -0,0 +1,45 @@
|
||||
<script lang="ts">
|
||||
import type {CnameRecord} from "../../stores/records";
|
||||
import type {RestItem} from "../../utils/rest-table";
|
||||
import ActionMenu from "../ActionMenu.svelte";
|
||||
import ActionPopup from "../ActionPopup.svelte";
|
||||
|
||||
export let value: RestItem<CnameRecord>;
|
||||
let editItem: CnameRecord = {
|
||||
Hdr: {
|
||||
Name: "",
|
||||
Rrtype: 0,
|
||||
Class: 0,
|
||||
Ttl: 0,
|
||||
},
|
||||
Target: "",
|
||||
};
|
||||
|
||||
let editPopup: boolean = false;
|
||||
|
||||
function save() {
|
||||
value.update(editItem);
|
||||
}
|
||||
</script>
|
||||
|
||||
<tr>
|
||||
<td class="code-font">{value.data.Hdr.Name}</td>
|
||||
<td class="code-font">{value.data.Target}</td>
|
||||
<td>
|
||||
<ActionMenu
|
||||
data={value}
|
||||
edit={() => {
|
||||
editItem = JSON.parse(JSON.stringify(value.data));
|
||||
editPopup = true;
|
||||
}}
|
||||
remove={() => value.remove()}
|
||||
/>
|
||||
|
||||
<ActionPopup name="Edit CNAME Record" bind:show={editPopup} on:save={save}>
|
||||
<div>Name</div>
|
||||
<div class="code-font">{editItem.Hdr.Name}</div>
|
||||
<div>Target</div>
|
||||
<div><input type="text" class="code-font" bind:value={editItem.Target} size={Math.max(20, editItem.Target.length + 2)} /></div>
|
||||
</ActionPopup>
|
||||
</td>
|
||||
</tr>
|
49
src/components/domains/MxRow.svelte
Normal file
49
src/components/domains/MxRow.svelte
Normal file
@ -0,0 +1,49 @@
|
||||
<script lang="ts">
|
||||
import type {MxRecord} from "../../stores/records";
|
||||
import type {RestItem} from "../../utils/rest-table";
|
||||
import ActionMenu from "../ActionMenu.svelte";
|
||||
import ActionPopup from "../ActionPopup.svelte";
|
||||
|
||||
export let value: RestItem<MxRecord>;
|
||||
let editItem: MxRecord = {
|
||||
Hdr: {
|
||||
Name: "",
|
||||
Rrtype: 0,
|
||||
Class: 0,
|
||||
Ttl: 0,
|
||||
},
|
||||
Mx: "",
|
||||
Preference: 0,
|
||||
};
|
||||
|
||||
let editPopup: boolean = false;
|
||||
|
||||
function save() {
|
||||
value.update(editItem);
|
||||
}
|
||||
</script>
|
||||
|
||||
<tr>
|
||||
<td class="code-font">{value.data.Hdr.Name}</td>
|
||||
<td class="code-font">{value.data.Mx}</td>
|
||||
<td class="code-font">{value.data.Preference}</td>
|
||||
<td>
|
||||
<ActionMenu
|
||||
data={value}
|
||||
edit={() => {
|
||||
editItem = JSON.parse(JSON.stringify(value.data));
|
||||
editPopup = true;
|
||||
}}
|
||||
remove={() => value.remove()}
|
||||
/>
|
||||
|
||||
<ActionPopup name="Edit SOA Record" bind:show={editPopup} on:save={save}>
|
||||
<div>Name</div>
|
||||
<div class="code-font">{editItem.Hdr.Name}</div>
|
||||
<div>Mail Server</div>
|
||||
<div><input type="text" class="code-font" bind:value={editItem.Mx} size={Math.max(20, editItem.Mx.length + 2)} /></div>
|
||||
<div>Preference</div>
|
||||
<div><input type="text" class="code-font" bind:value={editItem.Preference} size={Math.max(20, editItem.Preference.length + 2)} /></div>
|
||||
</ActionPopup>
|
||||
</td>
|
||||
</tr>
|
45
src/components/domains/NsRow.svelte
Normal file
45
src/components/domains/NsRow.svelte
Normal file
@ -0,0 +1,45 @@
|
||||
<script lang="ts">
|
||||
import type {NsRecord} from "../../stores/records";
|
||||
import type {RestItem} from "../../utils/rest-table";
|
||||
import ActionMenu from "../ActionMenu.svelte";
|
||||
import ActionPopup from "../ActionPopup.svelte";
|
||||
|
||||
export let value: RestItem<NsRecord>;
|
||||
let editItem: NsRecord = {
|
||||
Hdr: {
|
||||
Name: "",
|
||||
Rrtype: 0,
|
||||
Class: 0,
|
||||
Ttl: 0,
|
||||
},
|
||||
Ns: "",
|
||||
};
|
||||
|
||||
let editPopup: boolean = false;
|
||||
|
||||
function save() {
|
||||
value.update(editItem);
|
||||
}
|
||||
</script>
|
||||
|
||||
<tr>
|
||||
<td class="code-font">{value.data.Hdr.Name}</td>
|
||||
<td class="code-font">{value.data.Ns}</td>
|
||||
<td>
|
||||
<ActionMenu
|
||||
data={value}
|
||||
edit={() => {
|
||||
editItem = JSON.parse(JSON.stringify(value.data));
|
||||
editPopup = true;
|
||||
}}
|
||||
remove={() => value.remove()}
|
||||
/>
|
||||
|
||||
<ActionPopup name="Edit SOA Record" bind:show={editPopup} on:save={save}>
|
||||
<div>Name</div>
|
||||
<div class="code-font">{editItem.Hdr.Name}</div>
|
||||
<div>Nameserver</div>
|
||||
<div><input type="text" class="code-font" bind:value={editItem.Ns} size={Math.max(20, editItem.Ns.length + 2)} /></div>
|
||||
</ActionPopup>
|
||||
</td>
|
||||
</tr>
|
63
src/components/domains/SoaRow.svelte
Normal file
63
src/components/domains/SoaRow.svelte
Normal file
@ -0,0 +1,63 @@
|
||||
<script lang="ts">
|
||||
import type {SoaRecord} from "../../stores/records";
|
||||
import type {RestItem} from "../../utils/rest-table";
|
||||
import ActionMenu from "../ActionMenu.svelte";
|
||||
import ActionPopup from "../ActionPopup.svelte";
|
||||
|
||||
export let value: RestItem<SoaRecord>;
|
||||
let editItem: SoaRecord = {
|
||||
Hdr: {
|
||||
Name: "",
|
||||
Rrtype: 0,
|
||||
Class: 0,
|
||||
Ttl: 0,
|
||||
},
|
||||
Ns: "",
|
||||
Mbox: "",
|
||||
Serial: 0,
|
||||
Refresh: 0,
|
||||
Retry: 0,
|
||||
Expire: 0,
|
||||
Minttl: 0,
|
||||
};
|
||||
|
||||
let editPopup: boolean = false;
|
||||
|
||||
function save() {
|
||||
value.update(editItem);
|
||||
}
|
||||
</script>
|
||||
|
||||
<tr>
|
||||
<td class="code-font">{value.data.Hdr.Name}</td>
|
||||
<td class="code-font">{value.data.Mbox}</td>
|
||||
<td class="code-font">{value.data.Minttl}</td>
|
||||
<td class="code-font">{value.data.Refresh}</td>
|
||||
<td class="code-font">{value.data.Retry}</td>
|
||||
<td class="code-font">{value.data.Expire}</td>
|
||||
<td>
|
||||
<ActionMenu
|
||||
data={value}
|
||||
edit={() => {
|
||||
editItem = JSON.parse(JSON.stringify(value.data));
|
||||
editPopup = true;
|
||||
}}
|
||||
remove={() => value.remove()}
|
||||
/>
|
||||
|
||||
<ActionPopup name="Edit SOA Record" bind:show={editPopup} on:save={save}>
|
||||
<div>Name</div>
|
||||
<div class="code-font">{editItem.Hdr.Name}</div>
|
||||
<div>Mailbox</div>
|
||||
<div><input type="text" class="code-font" bind:value={editItem.Mbox} size={Math.max(20, editItem.Mbox.length + 2)} /></div>
|
||||
<div>Minimum Time-to-Live</div>
|
||||
<div><input type="number" class="code-font" bind:value={editItem.Minttl} size={Math.max(20, editItem.Minttl.length + 2)} /></div>
|
||||
<div>Refresh</div>
|
||||
<div><input type="number" class="code-font" bind:value={editItem.Refresh} size={Math.max(20, editItem.Refresh.length + 2)} /></div>
|
||||
<div>Retry</div>
|
||||
<div><input type="number" class="code-font" bind:value={editItem.Retry} size={Math.max(20, editItem.Retry.length + 2)} /></div>
|
||||
<div>Expire</div>
|
||||
<div><input type="number" class="code-font" bind:value={editItem.Expire} size={Math.max(20, editItem.Expire.length + 2)} /></div>
|
||||
</ActionPopup>
|
||||
</td>
|
||||
</tr>
|
47
src/components/domains/TxtRow.svelte
Normal file
47
src/components/domains/TxtRow.svelte
Normal file
@ -0,0 +1,47 @@
|
||||
<script lang="ts">
|
||||
import type {TxtRecord} from "../../stores/records";
|
||||
import type {RestItem} from "../../utils/rest-table";
|
||||
import ActionMenu from "../ActionMenu.svelte";
|
||||
import ActionPopup from "../ActionPopup.svelte";
|
||||
|
||||
export let value: RestItem<TxtRecord>;
|
||||
let editItem: TxtRecord = {
|
||||
Hdr: {
|
||||
Name: "",
|
||||
Rrtype: 0,
|
||||
Class: 0,
|
||||
Ttl: 0,
|
||||
},
|
||||
Txt: [""],
|
||||
};
|
||||
|
||||
let editPopup: boolean = false;
|
||||
|
||||
function save() {
|
||||
value.update(editItem);
|
||||
}
|
||||
</script>
|
||||
|
||||
<tr>
|
||||
<td class="code-font">{value.data.Hdr.Name}</td>
|
||||
<td class="code-font">
|
||||
<span class="cutoff">{value.data.Txt.join("\n")}</span>
|
||||
</td>
|
||||
<td>
|
||||
<ActionMenu
|
||||
data={value}
|
||||
edit={() => {
|
||||
editItem = JSON.parse(JSON.stringify(value.data));
|
||||
editPopup = true;
|
||||
}}
|
||||
remove={() => value.remove()}
|
||||
/>
|
||||
|
||||
<ActionPopup name="Edit TXT Record" bind:show={editPopup} on:save={save}>
|
||||
<div>Name</div>
|
||||
<div class="code-font">{editItem.Hdr.Name}</div>
|
||||
<div>Value</div>
|
||||
<div><input type="text" class="code-font" bind:value={editItem.Txt[0]} size={Math.max(20, editItem.Txt[0].length + 2)} /></div>
|
||||
</ActionPopup>
|
||||
</td>
|
||||
</tr>
|
@ -1,4 +1,12 @@
|
||||
import {writable} from "svelte/store";
|
||||
export const DnsTypeSOA = 6;
|
||||
export const DnsTypeNS = 2;
|
||||
export const DnsTypeMX = 15;
|
||||
export const DnsTypeA = 1;
|
||||
export const DnsTypeAAAA = 28;
|
||||
export const DnsTypeCNAME = 5;
|
||||
export const DnsTypeTXT = 16;
|
||||
export const DnsTypeSRV = 33;
|
||||
export const DnsTypeCAA = 257;
|
||||
|
||||
export interface RecordHeader {
|
||||
Name: string;
|
||||
@ -22,72 +30,58 @@ export interface SoaRecord extends UnknownRecord {
|
||||
}
|
||||
|
||||
export function isSoaRecord(x: UnknownRecord): x is SoaRecord {
|
||||
return x.Hdr.Rrtype === 6;
|
||||
return x.Hdr.Rrtype === DnsTypeSOA;
|
||||
}
|
||||
|
||||
export const soaRecords = writable<Array<SoaRecord>>([]);
|
||||
|
||||
export interface NsRecord extends UnknownRecord {
|
||||
Ns: string;
|
||||
}
|
||||
|
||||
export function isNsRecord(x: UnknownRecord): x is NsRecord {
|
||||
return x.Hdr.Rrtype === 2;
|
||||
return x.Hdr.Rrtype === DnsTypeNS;
|
||||
}
|
||||
|
||||
export const nsRecords = writable<Array<NsRecord>>([]);
|
||||
|
||||
export interface MxRecord extends UnknownRecord {
|
||||
Preference: number;
|
||||
Mx: string;
|
||||
}
|
||||
|
||||
export function isMxRecord(x: UnknownRecord): x is MxRecord {
|
||||
return x.Hdr.Rrtype === 15;
|
||||
return x.Hdr.Rrtype === DnsTypeMX;
|
||||
}
|
||||
|
||||
export const mxRecords = writable<Array<MxRecord>>([]);
|
||||
|
||||
export interface ARecord extends UnknownRecord {
|
||||
A: string;
|
||||
}
|
||||
|
||||
export function isARecord(x: UnknownRecord): x is ARecord {
|
||||
return x.Hdr.Rrtype === 1;
|
||||
return x.Hdr.Rrtype === DnsTypeA;
|
||||
}
|
||||
|
||||
export const aRecords = writable<Array<ARecord>>([]);
|
||||
|
||||
export interface AaaaRecord extends UnknownRecord {
|
||||
AAAA: string;
|
||||
}
|
||||
|
||||
export function isAaaaRecord(x: UnknownRecord): x is AaaaRecord {
|
||||
return x.Hdr.Rrtype === 28;
|
||||
return x.Hdr.Rrtype === DnsTypeAAAA;
|
||||
}
|
||||
|
||||
export const aaaaRecords = writable<Array<AaaaRecord>>([]);
|
||||
|
||||
export interface CnameRecord extends UnknownRecord {
|
||||
Target: string;
|
||||
}
|
||||
|
||||
export function isCnameRecord(x: UnknownRecord): x is CnameRecord {
|
||||
return x.Hdr.Rrtype === 5;
|
||||
return x.Hdr.Rrtype === DnsTypeCNAME;
|
||||
}
|
||||
|
||||
export const cnameRecords = writable<Array<CnameRecord>>([]);
|
||||
|
||||
export interface TxtRecord extends UnknownRecord {
|
||||
Txt: Array<string>;
|
||||
}
|
||||
|
||||
export function isTxtRecord(x: UnknownRecord): x is TxtRecord {
|
||||
return x.Hdr.Rrtype === 16;
|
||||
return x.Hdr.Rrtype === DnsTypeTXT;
|
||||
}
|
||||
|
||||
export const txtRecords = writable<Array<TxtRecord>>([]);
|
||||
|
||||
export interface SrvRecord extends UnknownRecord {
|
||||
Priority: number;
|
||||
Weight: number;
|
||||
@ -96,11 +90,9 @@ export interface SrvRecord extends UnknownRecord {
|
||||
}
|
||||
|
||||
export function isSrvRecord(x: UnknownRecord): x is SrvRecord {
|
||||
return x.Hdr.Rrtype === 33;
|
||||
return x.Hdr.Rrtype === DnsTypeSRV;
|
||||
}
|
||||
|
||||
export const srvRecords = writable<Array<SrvRecord>>([]);
|
||||
|
||||
export interface CaaRecord extends UnknownRecord {
|
||||
Flag: number;
|
||||
Tag: string;
|
||||
@ -108,7 +100,5 @@ export interface CaaRecord extends UnknownRecord {
|
||||
}
|
||||
|
||||
export function isCaaRecord(x: UnknownRecord): x is CaaRecord {
|
||||
return x.Hdr.Rrtype === 257;
|
||||
return x.Hdr.Rrtype === DnsTypeCAA;
|
||||
}
|
||||
|
||||
export const caaRecords = writable<Array<CaaRecord>>([]);
|
||||
|
@ -2,10 +2,7 @@
|
||||
import {LOGIN} from "../utils/login";
|
||||
import {domainOption} from "../stores/domain-option";
|
||||
import {
|
||||
aRecords,
|
||||
aaaaRecords,
|
||||
caaRecords,
|
||||
cnameRecords,
|
||||
DnsTypeSOA,
|
||||
isARecord,
|
||||
isAaaaRecord,
|
||||
isCaaRecord,
|
||||
@ -15,38 +12,50 @@
|
||||
isSoaRecord,
|
||||
isSrvRecord,
|
||||
isTxtRecord,
|
||||
mxRecords,
|
||||
nsRecords,
|
||||
soaRecords,
|
||||
srvRecords,
|
||||
txtRecords,
|
||||
type ARecord,
|
||||
type AaaaRecord,
|
||||
type CaaRecord,
|
||||
type CnameRecord,
|
||||
type MxRecord,
|
||||
type NsRecord,
|
||||
type SoaRecord,
|
||||
type SrvRecord,
|
||||
type TxtRecord,
|
||||
type UnknownRecord,
|
||||
} from "../stores/records";
|
||||
import ActionMenu from "../components/ActionMenu.svelte";
|
||||
import PromiseTable from "../components/PromiseTable.svelte";
|
||||
import {RestItem, RestTable} from "../utils/rest-table";
|
||||
import PromiseLike from "../components/PromiseLike.svelte";
|
||||
import SoaRow from "../components/domains/SoaRow.svelte";
|
||||
|
||||
const apiAzalea = import.meta.env.VITE_API_AZALEA;
|
||||
|
||||
let promiseForTable: Promise<void> = reloadTable();
|
||||
type AllRecords = SoaRecord | NsRecord | MxRecord | ARecord | AaaaRecord | CnameRecord | TxtRecord | SrvRecord | CaaRecord;
|
||||
|
||||
async function reloadTable(): Promise<void> {
|
||||
let f = await LOGIN.clientRequest(apiAzalea + "/domains/" + $domainOption + "/records", {});
|
||||
if (f.status != 200) throw new Error("Unexpected status code: " + f.status);
|
||||
let fJson = await f.json();
|
||||
let rows = fJson as Array<UnknownRecord>;
|
||||
$soaRecords = rows.filter(isSoaRecord);
|
||||
$nsRecords = rows.filter(isNsRecord);
|
||||
$mxRecords = rows.filter(isMxRecord);
|
||||
$aRecords = rows.filter(isARecord);
|
||||
$aaaaRecords = rows.filter(isAaaaRecord);
|
||||
$cnameRecords = rows.filter(isCnameRecord);
|
||||
$txtRecords = rows.filter(isTxtRecord);
|
||||
$srvRecords = rows.filter(isSrvRecord);
|
||||
$caaRecords = rows.filter(isCaaRecord);
|
||||
const table = new RestTable<AllRecords>(apiAzalea + "/domains/" + $domainOption + "/records", (item: AllRecords) => item.Hdr.Name);
|
||||
|
||||
function rowOrdering<T extends UnknownRecord>(
|
||||
rows: RestItem<UnknownRecord>[],
|
||||
domain: string,
|
||||
isTRecord: (t: UnknownRecord) => t is T,
|
||||
): RestItem<T>[] {
|
||||
return rows
|
||||
.filter(x => isTRecord(x.data))
|
||||
.filter(x => domainFilter(x.data.Hdr.Name, domain))
|
||||
.sort((a, b) => a.data.Hdr.Name.localeCompare(b.data.Hdr.Name)) as unknown as RestItem<T>[];
|
||||
}
|
||||
|
||||
domainOption.subscribe(x => {
|
||||
promiseForTable = reloadTable();
|
||||
});
|
||||
function domainFilter(src: string, domain: string) {
|
||||
if (domain == "*") return true;
|
||||
let n = src.indexOf("/");
|
||||
if (n == -1) n = src.length;
|
||||
let p = src.slice(0, n);
|
||||
if (p == domain) return true;
|
||||
return p.endsWith(domain);
|
||||
}
|
||||
|
||||
domainOption.subscribe(() => table.reload());
|
||||
|
||||
function getTitleDomain(name: string): string {
|
||||
if (name.endsWith(".")) {
|
||||
@ -54,266 +63,309 @@
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
let soaRecords: SoaRecord[] = [
|
||||
{
|
||||
Hdr: {
|
||||
Name: "example.com.",
|
||||
Rrtype: DnsTypeSOA,
|
||||
Class: 1,
|
||||
Ttl: 300,
|
||||
},
|
||||
Ns: "ns1.example.com.",
|
||||
Mbox: "postmaster.example.com.",
|
||||
Serial: 0,
|
||||
Refresh: 0,
|
||||
Retry: 0,
|
||||
Expire: 0,
|
||||
Minttl: 0,
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
{#await promiseForTable}
|
||||
<div class="text-padding">
|
||||
<div>Loading...</div>
|
||||
{#if soaRecords.length >= 1}
|
||||
<div class="title-row">
|
||||
<h1>Domains / {getTitleDomain(soaRecords[0].Hdr.Name)}</h1>
|
||||
<a
|
||||
class="zone-download"
|
||||
href="{import.meta.env.VITE_API_AZALEA}/domains/{getTitleDomain($soaRecords[0].Hdr.Name)}/zone-file"
|
||||
download="{getTitleDomain($soaRecords[0].Hdr.Name)}.zone"
|
||||
>
|
||||
Download DNS Zone File
|
||||
</a>
|
||||
</div>
|
||||
{:then}
|
||||
{#if $soaRecords.length >= 1}
|
||||
<div class="title-row">
|
||||
<h1>Domains / {getTitleDomain($soaRecords[0].Hdr.Name)}</h1>
|
||||
<a
|
||||
class="zone-download"
|
||||
href="{import.meta.env.VITE_API_AZALEA}/domains/{getTitleDomain($soaRecords[0].Hdr.Name)}/zone-file"
|
||||
download="{getTitleDomain($soaRecords[0].Hdr.Name)}.zone"
|
||||
>
|
||||
Download DNS Zone File
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<h2>SOA Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains SOA Record">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Primary Domain</th>
|
||||
<th>Email</th>
|
||||
<th>Default TTL</th>
|
||||
<th>Refresh Rate</th>
|
||||
<th>Retry Rate</th>
|
||||
<th>Expire Time</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $soaRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $soaRecords as record}
|
||||
<tr>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Mbox}</td>
|
||||
<td>{record.Minttl}</td>
|
||||
<td>{record.Refresh}</td>
|
||||
<td>{record.Retry}</td>
|
||||
<td>{record.Expire}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={null} />
|
||||
<h2>SOA Record</h2>
|
||||
<PromiseTable value={table}>
|
||||
<tr slot="headers">
|
||||
<th>Primary Domain</th>
|
||||
<th>Email</th>
|
||||
<th>Default TTL</th>
|
||||
<th>Refresh Rate</th>
|
||||
<th>Retry Rate</th>
|
||||
<th>Expire Time</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
||||
<svelte:fragment slot="rows" let:value>
|
||||
{#each rowOrdering(value.rows, $domainOption, DnsTypeSOA) as item}
|
||||
<PromiseLike value={item}>
|
||||
<tr slot="loading" class="empty-row">
|
||||
<td colspan="100">
|
||||
<div>Loading...</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>NS Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains NS Record">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name Server</th>
|
||||
<th>Subdomain</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $nsRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $nsRecords as record}
|
||||
<tr>
|
||||
<td>{record.Ns}</td>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td></td>
|
||||
<tr slot="error" let:reason class="empty-row">
|
||||
<td colspan="100">Error loading row for {item.data.Hdr.Name}: {reason}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>MX Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains MX Record">
|
||||
<thead>
|
||||
<SoaRow slot="ok" let:value {value} />
|
||||
</PromiseLike>
|
||||
{/each}
|
||||
</svelte:fragment>
|
||||
</PromiseTable>
|
||||
<table class="action-table" aria-label="List of Domains SOA Record">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Primary Domain</th>
|
||||
<th>Email</th>
|
||||
<th>Default TTL</th>
|
||||
<th>Refresh Rate</th>
|
||||
<th>Retry Rate</th>
|
||||
<th>Expire Time</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $soaRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $soaRecords as record}
|
||||
<tr>
|
||||
<th>Mail Server</th>
|
||||
<th>Preference</th>
|
||||
<th>Subdomain</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Mbox}</td>
|
||||
<td>{record.Minttl}</td>
|
||||
<td>{record.Refresh}</td>
|
||||
<td>{record.Retry}</td>
|
||||
<td>{record.Expire}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={null} />
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $mxRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $mxRecords as record}
|
||||
<tr>
|
||||
<td>{record.Mx}</td>
|
||||
<td>{record.Preference}</td>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>A/AAAA Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains A/AAAA Record">
|
||||
<thead>
|
||||
<h2>NS Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains NS Record">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name Server</th>
|
||||
<th>Subdomain</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $nsRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $nsRecords as record}
|
||||
<tr>
|
||||
<th>Hostname</th>
|
||||
<th>IP Address</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
<td>{record.Ns}</td>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $aRecords.length === 0 && $aaaaRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $aRecords as record}
|
||||
<tr>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.A}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
{#each $aaaaRecords as record}
|
||||
<tr>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.AAAA}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>CNAME Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains CNAME Record">
|
||||
<thead>
|
||||
<h2>MX Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains MX Record">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Mail Server</th>
|
||||
<th>Preference</th>
|
||||
<th>Subdomain</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $mxRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $mxRecords as record}
|
||||
<tr>
|
||||
<th>Hostname</th>
|
||||
<th>Aliases to</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
<td>{record.Mx}</td>
|
||||
<td>{record.Preference}</td>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $cnameRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $cnameRecords as record}
|
||||
<tr>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Target}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>TXT Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains TXT Record">
|
||||
<thead>
|
||||
<h2>A/AAAA Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains A/AAAA Record">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hostname</th>
|
||||
<th>IP Address</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $aRecords.length === 0 && $aaaaRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $aRecords as record}
|
||||
<tr>
|
||||
<th>Hostname</th>
|
||||
<th>Value</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.A}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $txtRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $txtRecords as record}
|
||||
<tr>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Txt.join("\n")}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{/each}
|
||||
{#each $aaaaRecords as record}
|
||||
<tr>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.AAAA}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>SRV Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains SRV Record">
|
||||
<thead>
|
||||
<h2>CNAME Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains CNAME Record">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hostname</th>
|
||||
<th>Aliases to</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $cnameRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $cnameRecords as record}
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Priority</th>
|
||||
<th>Weight</th>
|
||||
<th>Port</th>
|
||||
<th>Target</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Target}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $srvRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $srvRecords as record}
|
||||
<tr>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Priority}</td>
|
||||
<td>{record.Weight}</td>
|
||||
<td>{record.Port}</td>
|
||||
<td>{record.Target}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>CAA Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains CAA Record">
|
||||
<thead>
|
||||
<h2>TXT Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains TXT Record">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hostname</th>
|
||||
<th>Value</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $txtRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $txtRecords as record}
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Tag</th>
|
||||
<th>Value</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>
|
||||
<span class="cutoff">{record.Txt.join("\n")}</span>
|
||||
</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $caaRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $caaRecords as record}
|
||||
<tr>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Tag}</td>
|
||||
<td>{record.Value}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{/await}
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>SRV Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains SRV Record">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Priority</th>
|
||||
<th>Weight</th>
|
||||
<th>Port</th>
|
||||
<th>Target</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $srvRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $srvRecords as record}
|
||||
<tr>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Priority}</td>
|
||||
<td>{record.Weight}</td>
|
||||
<td>{record.Port}</td>
|
||||
<td>{record.Target}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>CAA Record</h2>
|
||||
<table class="action-table" aria-label="List of Domains CAA Record">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Tag</th>
|
||||
<th>Value</th>
|
||||
<th>TTL</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if $caaRecords.length === 0}
|
||||
<tr class="empty-row"><td colspan="7">No items to display</td></tr>
|
||||
{/if}
|
||||
{#each $caaRecords as record}
|
||||
<tr>
|
||||
<td>{record.Hdr.Name}</td>
|
||||
<td>{record.Tag}</td>
|
||||
<td>{record.Value}</td>
|
||||
<td>{record.Hdr.Ttl}</td>
|
||||
<td>
|
||||
<ActionMenu data={record} edit={t => console.log(t)} remove={t => console.log(t)} />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../values.scss";
|
||||
@ -322,8 +374,29 @@
|
||||
@include button-green-highlight;
|
||||
}
|
||||
|
||||
table tbody tr.empty-row td {
|
||||
text-align: center;
|
||||
table tbody tr {
|
||||
td {
|
||||
position: relative;
|
||||
|
||||
span.cutoff {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow: hidden;
|
||||
text-wrap: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
margin-inline: 15px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
line-height: 1rem;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
&.empty-row td {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.title-row {
|
||||
|
@ -52,6 +52,7 @@ func ssoServer(signer mjwt.Signer) {
|
||||
ps := claims.NewPermStorage()
|
||||
ps.Set("violet:route")
|
||||
ps.Set("violet:redirect")
|
||||
ps.Set("azalea:domains")
|
||||
ps.Set("domain:owns=example.com")
|
||||
ps.Set("domain:owns=example.org")
|
||||
accessToken, err := signer.GenerateJwt("81b99bd7-bf74-4cc2-9133-80ed2393dfe6", uuid.NewString(), jwt.ClaimStrings{"b5a9a8df-827c-4925-b1c1-1940abcf356b"}, 15*time.Minute, auth.AccessTokenClaims{
|
||||
|
Loading…
Reference in New Issue
Block a user