Rewrite dns record format

This commit is contained in:
Melon 2024-08-02 15:14:02 +01:00
parent f992ce6575
commit e2615861b0
Signed by: melon
GPG Key ID: 6C9D970C50D26A25
18 changed files with 323 additions and 429 deletions

View File

@ -1,8 +1,8 @@
<script lang="ts">
import {DnsTypeA, DnsTypeAAAA, type AaaaRecord, type ARecord} from "../../types/records";
import {DnsTypeA, DnsTypeAAAA, type AaaaValue, type ApiRecordFormat, type AValue} from "../../types/records";
import {IPv4, IPv6, parse as parseAddr} from "ipaddr.js";
export let editItem: ARecord | AaaaRecord;
export let editItem: ApiRecordFormat<AValue | AaaaValue>;
export let editMode: boolean;
let value: string = "";
@ -11,14 +11,14 @@
try {
let addr = parseAddr(value);
if (addr instanceof IPv4) {
(editItem as ARecord).A = addr.toString();
editItem.Hdr.Rrtype = DnsTypeA;
(editItem as ApiRecordFormat<AValue>).value = addr.toString();
editItem.type = DnsTypeA;
} else if (addr instanceof IPv6) {
(editItem as AaaaRecord).AAAA = addr.toString();
editItem.Hdr.Rrtype = DnsTypeAAAA;
(editItem as ApiRecordFormat<AaaaValue>).value = addr.toString();
editItem.type = DnsTypeAAAA;
}
} catch {
editItem.Hdr.Rrtype = 0;
editItem.type = 0;
console.error("Invalid IP address:", value);
}
}
@ -26,15 +26,15 @@
<div>Name</div>
{#if editMode}
<div class="code-font">{editItem.Hdr.Name}</div>
<div class="code-font">{editItem.name}</div>
{:else}
<div><input type="text" class="code-font" bind:value={editItem.Hdr.Name} size={Math.max(20, editItem.Hdr.Name.length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.name} size={Math.max(20, editItem.name.length + 2)} /></div>
{/if}
<div>IP Address</div>
<div><input type="text" class="code-font" bind:value on:keyup={onChange} size={Math.max(20, value.length + 2)} /></div>
{#if editItem.Hdr.Rrtype === DnsTypeA}
{#if editItem.type === DnsTypeA}
<div>IP address is IPv4</div>
{:else if editItem.Hdr.Rrtype === DnsTypeAAAA}
{:else if editItem.type === DnsTypeAAAA}
<div>IP address is IPv6</div>
{/if}

View File

@ -1,17 +1,17 @@
<script lang="ts">
import type {CaaRecord} from "../../types/records";
import type {ApiRecordFormat, CaaValue} from "../../types/records";
export let editItem: CaaRecord;
export let editItem: ApiRecordFormat<CaaValue>;
export let editMode: boolean;
</script>
<div>Name</div>
{#if editMode}
<div class="code-font">{editItem.Hdr.Name}</div>
<div class="code-font">{editItem.name}</div>
{:else}
<div><input type="text" class="code-font" bind:value={editItem.Hdr.Name} size={Math.max(20, editItem.Hdr.Name.length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.name} size={Math.max(20, editItem.name.length + 2)} /></div>
{/if}
<div>Tag</div>
<div><input type="text" class="code-font" bind:value={editItem.Tag} size={Math.max(20, editItem.Tag.length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.value.tag} size={Math.max(20, editItem.value.tag.length + 2)} /></div>
<div>Value</div>
<div><input type="text" class="code-font" bind:value={editItem.Value} size={Math.max(20, editItem.Value.length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.value.value} size={Math.max(20, editItem.value.value.length + 2)} /></div>

View File

@ -1,15 +1,15 @@
<script lang="ts">
import type {CnameRecord} from "../../types/records";
import type {ApiRecordFormat, CnameValue} from "../../types/records";
export let editItem: CnameRecord;
export let editItem: ApiRecordFormat<CnameValue>;
export let editMode: boolean;
</script>
<div>Name</div>
{#if editMode}
<div class="code-font">{editItem.Hdr.Name}</div>
<div class="code-font">{editItem.name}</div>
{:else}
<div><input type="text" class="code-font" bind:value={editItem.Hdr.Name} size={Math.max(20, editItem.Hdr.Name.length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.name} size={Math.max(20, editItem.name.length + 2)} /></div>
{/if}
<div>Target</div>
<div><input type="text" class="code-font" bind:value={editItem.Target} size={Math.max(20, editItem.Target.length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.value} size={Math.max(20, editItem.value.length + 2)} /></div>

View File

@ -1,17 +1,17 @@
<script lang="ts">
import type {MxRecord} from "../../types/records";
import type {ApiRecordFormat, MxValue} from "../../types/records";
export let editItem: MxRecord;
export let editItem: ApiRecordFormat<MxValue>;
export let editMode: boolean;
</script>
<div>Name</div>
{#if editMode}
<div class="code-font">{editItem.Hdr.Name}</div>
<div class="code-font">{editItem.name}</div>
{:else}
<div><input type="text" class="code-font" bind:value={editItem.Hdr.Name} size={Math.max(20, editItem.Hdr.Name.length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.name} size={Math.max(20, editItem.name.length + 2)} /></div>
{/if}
<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><input type="text" class="code-font" bind:value={editItem.value.mx} size={Math.max(20, editItem.value.mx.length + 2)} /></div>
<div>Preference</div>
<div><input type="number" class="code-font" bind:value={editItem.Preference} /></div>
<div><input type="number" class="code-font" bind:value={editItem.value.preference} /></div>

View File

@ -1,15 +1,15 @@
<script lang="ts">
import type {NsRecord} from "../../types/records";
import type {ApiRecordFormat, NsValue} from "../../types/records";
export let editItem: NsRecord;
export let editItem: ApiRecordFormat<NsValue>;
export let editMode: boolean;
</script>
<div>Name</div>
{#if editMode}
<div class="code-font">{editItem.Hdr.Name}</div>
<div class="code-font">{editItem.name}</div>
{:else}
<div><input type="text" class="code-font" bind:value={editItem.Hdr.Name} size={Math.max(20, editItem.Hdr.Name.length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.name} size={Math.max(20, editItem.name.length + 2)} /></div>
{/if}
<div>Nameserver</div>
<div><input type="text" class="code-font" bind:value={editItem.Ns} size={Math.max(20, editItem.Ns.length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.value} size={Math.max(20, editItem.value.length + 2)} /></div>

View File

@ -1,21 +1,21 @@
<script lang="ts">
import type {SrvRecord} from "../../types/records";
import type {ApiRecordFormat, SrvValue} from "../../types/records";
export let editItem: SrvRecord;
export let editItem: ApiRecordFormat<SrvValue>;
export let editMode: boolean;
</script>
<div>Name</div>
{#if editMode}
<div class="code-font">{editItem.Hdr.Name}</div>
<div class="code-font">{editItem.name}</div>
{:else}
<div><input type="text" class="code-font" bind:value={editItem.Hdr.Name} size={Math.max(20, editItem.Hdr.Name.length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.name} size={Math.max(20, editItem.name.length + 2)} /></div>
{/if}
<div>Priority</div>
<div><input type="number" class="code-font" bind:value={editItem.Priority} /></div>
<div><input type="number" class="code-font" bind:value={editItem.value.priority} /></div>
<div>Weight</div>
<div><input type="number" class="code-font" bind:value={editItem.Weight} /></div>
<div><input type="number" class="code-font" bind:value={editItem.value.weight} /></div>
<div>Port</div>
<div><input type="number" class="code-font" bind:value={editItem.Port} /></div>
<div><input type="number" class="code-font" bind:value={editItem.value.port} /></div>
<div>Target</div>
<div><input type="text" class="code-font" bind:value={editItem.Target} size={Math.max(20, editItem.Target.length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.value.target} size={Math.max(20, editItem.value.target.length + 2)} /></div>

View File

@ -1,7 +1,7 @@
<script lang="ts">
import type {TxtRecord} from "../../types/records";
import type {ApiRecordFormat, TxtValue} from "../../types/records";
export let editItem: TxtRecord;
export let editItem: ApiRecordFormat<TxtValue>;
export let editMode: boolean;
function constrain(min: number, max: number, value: number) {
@ -11,9 +11,9 @@
<div>Name</div>
{#if editMode}
<div class="code-font">{editItem.Hdr.Name}</div>
<div class="code-font">{editItem.name}</div>
{:else}
<div><input type="text" class="code-font" bind:value={editItem.Hdr.Name} size={Math.max(20, editItem.Hdr.Name.length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.name} size={Math.max(20, editItem.name.length + 2)} /></div>
{/if}
<div>Value</div>
<div><input type="text" class="code-font" bind:value={editItem.Txt[0]} size={constrain(20, 100, editItem.Txt[0].length + 2)} /></div>
<div><input type="text" class="code-font" bind:value={editItem.value} size={constrain(20, 100, editItem.value.length + 2)} /></div>

View File

@ -1,44 +1,40 @@
<script lang="ts">
import {isAaaaRecord, isARecord, type AaaaRecord, type ARecord} from "../../types/records";
import {isAaaaRecord, isARecord, type AaaaValue, type ApiRecordFormat, type AValue} from "../../types/records";
import type {RestItem} from "../../utils/rest-table";
import ActionMenu from "../ActionMenu.svelte";
import ActionPopup from "../ActionPopup.svelte";
import ACreate from "../create-domains/ACreate.svelte";
export let value: RestItem<ARecord | AaaaRecord>;
let editItem: ARecord & AaaaRecord = {
Hdr: {
Name: "",
Rrtype: 0,
Class: 0,
Ttl: 0,
},
A: "",
AAAA: "",
export let item: RestItem<ApiRecordFormat<AValue | AaaaValue>>;
let editItem: ApiRecordFormat<AValue & AaaaValue> = {
name: item.data.name,
type: item.data.type,
ttl: item.data.ttl,
value: "",
};
let editPopup: boolean = false;
function save() {
value.update(editItem);
item.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 class="code-font">{value.data.Hdr.Ttl}</td>
<td class="code-font">{item.data.name}</td>
<td class="code-font">{item.data.value}</td>
<td class="code-font">{item.data.ttl}</td>
<td>
<ActionMenu
data={value}
data={item}
edit={() => {
editItem = JSON.parse(JSON.stringify(value.data));
editItem = JSON.parse(JSON.stringify(item.data));
editPopup = true;
}}
remove={() => value.remove()}
remove={() => item.remove()}
/>
<ActionPopup name="Edit {isARecord(value.data) ? 'A' : 'AAAA'} Record" bind:show={editPopup} on:save={save}>
<ActionPopup name="Edit {isARecord(item.data) ? 'A' : 'AAAA'} Record" bind:show={editPopup} on:save={save}>
<ACreate bind:editItem editMode={true} />
</ActionPopup>
</td>

View File

@ -1,43 +1,42 @@
<script lang="ts">
import type {CaaRecord} from "../../types/records";
import type {ApiRecordFormat, CaaValue} from "../../types/records";
import type {RestItem} from "../../utils/rest-table";
import ActionMenu from "../ActionMenu.svelte";
import ActionPopup from "../ActionPopup.svelte";
import CaaCreate from "../create-domains/CaaCreate.svelte";
export let value: RestItem<CaaRecord>;
let editItem: CaaRecord = {
Hdr: {
Name: "",
Rrtype: 0,
Class: 0,
Ttl: 0,
export let item: RestItem<ApiRecordFormat<CaaValue>>;
let editItem: ApiRecordFormat<CaaValue> = {
name: item.data.name,
type: item.data.type,
ttl: item.data.ttl,
value: {
flag: 0,
tag: "",
value: "",
},
Flag: 0,
Tag: "",
Value: "",
};
let editPopup: boolean = false;
function save() {
value.update(editItem);
item.update(editItem);
}
</script>
<tr>
<td class="code-font">{value.data.Hdr.Name}</td>
<td class="code-font">{value.data.Tag}</td>
<td class="code-font">{value.data.Value}</td>
<td class="code-font">{value.data.Hdr.Ttl}</td>
<td class="code-font">{item.data.name}</td>
<td class="code-font">{item.data.value.tag}</td>
<td class="code-font">{item.data.value.value}</td>
<td class="code-font">{item.data.ttl}</td>
<td>
<ActionMenu
data={value}
data={item}
edit={() => {
editItem = JSON.parse(JSON.stringify(value.data));
editItem = JSON.parse(JSON.stringify(item.data));
editPopup = true;
}}
remove={() => value.remove()}
remove={() => item.remove()}
/>
<ActionPopup name="Edit CAA Record" bind:show={editPopup} on:save={save}>

View File

@ -1,40 +1,37 @@
<script lang="ts">
import type {CnameRecord} from "../../types/records";
import type {ApiRecordFormat, CnameValue} from "../../types/records";
import type {RestItem} from "../../utils/rest-table";
import ActionMenu from "../ActionMenu.svelte";
import ActionPopup from "../ActionPopup.svelte";
import CnameCreate from "../create-domains/CnameCreate.svelte";
export let value: RestItem<CnameRecord>;
let editItem: CnameRecord = {
Hdr: {
Name: "",
Rrtype: 0,
Class: 0,
Ttl: 0,
},
Target: "",
export let item: RestItem<ApiRecordFormat<CnameValue>>;
let editItem: ApiRecordFormat<CnameValue> = {
name: item.data.name,
type: item.data.type,
ttl: item.data.ttl,
value: "",
};
let editPopup: boolean = false;
function save() {
value.update(editItem);
item.update(editItem);
}
</script>
<tr>
<td class="code-font">{value.data.Hdr.Name}</td>
<td class="code-font">{value.data.Target}</td>
<td class="code-font">{value.data.Hdr.Ttl}</td>
<td class="code-font">{item.data.name}</td>
<td class="code-font">{item.data.value}</td>
<td class="code-font">{item.data.ttl}</td>
<td>
<ActionMenu
data={value}
data={item}
edit={() => {
editItem = JSON.parse(JSON.stringify(value.data));
editItem = JSON.parse(JSON.stringify(item.data));
editPopup = true;
}}
remove={() => value.remove()}
remove={() => item.remove()}
/>
<ActionPopup name="Edit CNAME Record" bind:show={editPopup} on:save={save}>

View File

@ -1,42 +1,41 @@
<script lang="ts">
import type {MxRecord} from "../../types/records";
import type {ApiRecordFormat, MxValue} from "../../types/records";
import type {RestItem} from "../../utils/rest-table";
import ActionMenu from "../ActionMenu.svelte";
import ActionPopup from "../ActionPopup.svelte";
import MxCreate from "../create-domains/MxCreate.svelte";
export let value: RestItem<MxRecord>;
let editItem: MxRecord = {
Hdr: {
Name: "",
Rrtype: 0,
Class: 0,
Ttl: 0,
export let item: RestItem<ApiRecordFormat<MxValue>>;
let editItem: ApiRecordFormat<MxValue> = {
name: item.data.name,
type: item.data.type,
ttl: item.data.ttl,
value: {
mx: "",
preference: 0,
},
Mx: "",
Preference: 0,
};
let editPopup: boolean = false;
function save() {
value.update(editItem);
item.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 class="code-font">{value.data.Hdr.Ttl}</td>
<td class="code-font">{item.data.name}</td>
<td class="code-font">{item.data.value.mx}</td>
<td class="code-font">{item.data.value.preference}</td>
<td class="code-font">{item.data.ttl}</td>
<td>
<ActionMenu
data={value}
data={item}
edit={() => {
editItem = JSON.parse(JSON.stringify(value.data));
editItem = JSON.parse(JSON.stringify(item.data));
editPopup = true;
}}
remove={() => value.remove()}
remove={() => item.remove()}
/>
<ActionPopup name="Edit MX Record" bind:show={editPopup} on:save={save}>

View File

@ -1,42 +1,39 @@
<script lang="ts">
import type {NsRecord} from "../../types/records";
import type {ApiRecordFormat, NsValue} from "../../types/records";
import type {RestItem} from "../../utils/rest-table";
import ActionMenu from "../ActionMenu.svelte";
import ActionPopup from "../ActionPopup.svelte";
import NsCreate from "../create-domains/NsCreate.svelte";
export let value: RestItem<NsRecord>;
let editItem: NsRecord = {
Hdr: {
Name: "",
Rrtype: 0,
Class: 0,
Ttl: 0,
},
Ns: "",
export let item: RestItem<ApiRecordFormat<NsValue>>;
let editItem: ApiRecordFormat<NsValue> = {
name: item.data.name,
type: item.data.type,
ttl: item.data.ttl,
value: "",
};
let editPopup: boolean = false;
export let locked: boolean = false;
function save() {
value.update(editItem);
item.update(editItem);
}
</script>
<tr>
<td class="code-font">{value.data.Hdr.Name}</td>
<td class="code-font">{value.data.Ns}</td>
<td class="code-font">{value.data.Hdr.Ttl}</td>
<td class="code-font">{item.data.name}</td>
<td class="code-font">{item.data.value}</td>
<td class="code-font">{item.data.ttl}</td>
<td>
{#if !locked}
<ActionMenu
data={value}
data={item}
edit={() => {
editItem = JSON.parse(JSON.stringify(value.data));
editItem = JSON.parse(JSON.stringify(item.data));
editPopup = true;
}}
remove={() => value.remove()}
remove={() => item.remove()}
/>
{/if}

View File

@ -1,66 +1,69 @@
<script lang="ts">
import type {SoaRecord} from "../../types/records";
import type {ApiRecordFormat, SoaValue} from "../../types/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,
export let item: RestItem<ApiRecordFormat<SoaValue>>;
let editItem: ApiRecordFormat<SoaValue> = {
name: item.data.name,
type: item.data.type,
ttl: item.data.ttl,
value: {
ns: "",
mbox: "",
serial: 0,
refresh: 0,
retry: 0,
expire: 0,
minttl: 0,
},
Ns: "",
Mbox: "",
Serial: 0,
Refresh: 0,
Retry: 0,
Expire: 0,
Minttl: 0,
};
let editPopup: boolean = false;
export let locked: boolean = false;
function save() {
value.update(editItem);
item.update(editItem);
}
function numLength(n: number) {
return n.toString().length + 2;
}
</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 class="code-font">{item.data.name}</td>
<td class="code-font">{item.data.value.mbox}</td>
<td class="code-font">{item.data.value.minttl}</td>
<td class="code-font">{item.data.value.refresh}</td>
<td class="code-font">{item.data.value.retry}</td>
<td class="code-font">{item.data.value.expire}</td>
<td>
{#if !locked}
<ActionMenu
data={value}
data={item}
edit={() => {
editItem = JSON.parse(JSON.stringify(value.data));
editItem = JSON.parse(JSON.stringify(item.data));
editPopup = true;
}}
remove={() => value.remove()}
remove={() => item.remove()}
/>
{/if}
<ActionPopup name="Edit SOA Record" bind:show={editPopup} on:save={save}>
<div>Name</div>
<div class="code-font">{editItem.Hdr.Name}</div>
<div class="code-font">{item.data.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><input type="text" class="code-font" bind:value={editItem.value.mbox} size={Math.max(20, editItem.value.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><input type="number" class="code-font" bind:value={editItem.value.minttl} size={Math.max(20, numLength(editItem.value.minttl))} /></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><input type="number" class="code-font" bind:value={editItem.value.refresh} size={Math.max(20, numLength(editItem.value.refresh))} /></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><input type="number" class="code-font" bind:value={editItem.value.retry} size={Math.max(20, numLength(editItem.value.retry))} /></div>
<div>Expire</div>
<div><input type="number" class="code-font" bind:value={editItem.Expire} size={Math.max(20, editItem.Expire.length + 2)} /></div>
<div><input type="number" class="code-font" bind:value={editItem.value.expire} size={Math.max(20, numLength(editItem.value.expire))} /></div>
</ActionPopup>
</td>
</tr>

View File

@ -1,46 +1,45 @@
<script lang="ts">
import type {SrvRecord} from "../../types/records";
import type {ApiRecordFormat, SrvValue} from "../../types/records";
import type {RestItem} from "../../utils/rest-table";
import ActionMenu from "../ActionMenu.svelte";
import ActionPopup from "../ActionPopup.svelte";
import SrvCreate from "../create-domains/SrvCreate.svelte";
export let value: RestItem<SrvRecord>;
let editItem: SrvRecord = {
Hdr: {
Name: "",
Rrtype: 0,
Class: 0,
Ttl: 0,
export let item: RestItem<ApiRecordFormat<SrvValue>>;
let editItem: ApiRecordFormat<SrvValue> = {
name: item.data.name,
type: item.data.type,
ttl: item.data.ttl,
value: {
priority: 0,
weight: 0,
port: 0,
target: "",
},
Priority: 0,
Weight: 0,
Port: 0,
Target: "",
};
let editPopup: boolean = false;
function save() {
value.update(editItem);
item.update(editItem);
}
</script>
<tr>
<td class="code-font">{value.data.Hdr.Name}</td>
<td class="code-font">{value.data.Priority}</td>
<td class="code-font">{value.data.Weight}</td>
<td class="code-font">{value.data.Port}</td>
<td class="code-font">{value.data.Target}</td>
<td class="code-font">{value.data.Hdr.Ttl}</td>
<td class="code-font">{item.data.name}</td>
<td class="code-font">{item.data.value.priority}</td>
<td class="code-font">{item.data.value.weight}</td>
<td class="code-font">{item.data.value.port}</td>
<td class="code-font">{item.data.value.target}</td>
<td class="code-font">{item.data.ttl}</td>
<td>
<ActionMenu
data={value}
data={item}
edit={() => {
editItem = JSON.parse(JSON.stringify(value.data));
editItem = JSON.parse(JSON.stringify(item.data));
editPopup = true;
}}
remove={() => value.remove()}
remove={() => item.remove()}
/>
<ActionPopup name="Edit CNAME Record" bind:show={editPopup} on:save={save}>

View File

@ -1,41 +1,38 @@
<script lang="ts">
import type {TxtRecord} from "../../types/records";
import type {ApiRecordFormat, TxtValue} from "../../types/records";
import type {RestItem} from "../../utils/rest-table";
import ActionMenu from "../ActionMenu.svelte";
import ActionPopup from "../ActionPopup.svelte";
import TxtCreate from "../create-domains/TxtCreate.svelte";
import TdCutOff from "../CutOffTd.svelte";
export let value: RestItem<TxtRecord>;
let editItem: TxtRecord = {
Hdr: {
Name: "",
Rrtype: 0,
Class: 0,
Ttl: 0,
},
Txt: [""],
export let item: RestItem<ApiRecordFormat<TxtValue>>;
let editItem: ApiRecordFormat<TxtValue> = {
name: item.data.name,
type: item.data.type,
ttl: item.data.ttl,
value: "",
};
let editPopup: boolean = false;
function save() {
value.update(editItem);
item.update(editItem);
}
</script>
<tr>
<td class="code-font">{value.data.Hdr.Name}</td>
<TdCutOff class="code-font">{value.data.Txt.join("\n")}</TdCutOff>
<td class="code-font">{value.data.Hdr.Ttl}</td>
<td class="code-font">{item.data.name}</td>
<TdCutOff class="code-font">{item.data.value}</TdCutOff>
<td class="code-font">{item.data.ttl}</td>
<td>
<ActionMenu
data={value}
data={item}
edit={() => {
editItem = JSON.parse(JSON.stringify(value.data));
editItem = JSON.parse(JSON.stringify(item.data));
editPopup = true;
}}
remove={() => value.remove()}
remove={() => item.remove()}
/>
<ActionPopup name="Edit TXT Record" bind:show={editPopup} on:save={save}>

View File

@ -1,3 +1,5 @@
import type {IPv4, IPv6} from "ipaddr.js";
export const DnsTypeSOA = 6;
export const DnsTypeNS = 2;
export const DnsTypeMX = 15;
@ -8,105 +10,86 @@ export const DnsTypeTXT = 16;
export const DnsTypeSRV = 33;
export const DnsTypeCAA = 257;
export type AllRecords = SoaRecord | NsRecord | MxRecord | ARecord | AaaaRecord | CnameRecord | TxtRecord | SrvRecord | CaaRecord;
export type AnyValue = SoaValue | NsValue | MxValue | AValue | AaaaValue | CnameValue | TxtValue | SrvValue | CaaValue;
export type AnyRecord = ApiRecordFormat<AnyValue>;
export interface ApiRecordFormat {
export interface ApiRecordFormat<T> {
name: string;
type: number;
value: any;
ttl: number | null;
value: T;
}
export interface RecordHeader {
Name: string;
Rrtype: number;
Class: number;
Ttl: number;
export interface SoaValue {
ns: string;
mbox: string;
serial: number;
refresh: number;
retry: number;
expire: number;
minttl: number;
}
export interface UnknownRecord {
Hdr: RecordHeader;
export function isSoaRecord(x: AnyRecord): x is ApiRecordFormat<SoaValue> {
return x.type === DnsTypeSOA;
}
export interface SoaRecord extends UnknownRecord {
Ns: string;
Mbox: string;
Serial: number;
Refresh: number;
Retry: number;
Expire: number;
Minttl: number;
export type NsValue = string;
export function isNsRecord(x: AnyRecord): x is ApiRecordFormat<NsValue> {
return x.type === DnsTypeNS;
}
export function isSoaRecord(x: UnknownRecord): x is SoaRecord {
return x.Hdr.Rrtype === DnsTypeSOA;
export interface MxValue {
preference: number;
mx: string;
}
export interface NsRecord extends UnknownRecord {
Ns: string;
export function isMxRecord(x: AnyRecord): x is ApiRecordFormat<MxValue> {
return x.type === DnsTypeMX;
}
export function isNsRecord(x: UnknownRecord): x is NsRecord {
return x.Hdr.Rrtype === DnsTypeNS;
export type AValue = string;
export function isARecord(x: AnyRecord): x is ApiRecordFormat<AValue> {
return x.type === DnsTypeA;
}
export interface MxRecord extends UnknownRecord {
Preference: number;
Mx: string;
export type AaaaValue = string;
export function isAaaaRecord(x: AnyRecord): x is ApiRecordFormat<AaaaValue> {
return x.type === DnsTypeAAAA;
}
export function isMxRecord(x: UnknownRecord): x is MxRecord {
return x.Hdr.Rrtype === DnsTypeMX;
export type CnameValue = string;
export function isCnameRecord(x: AnyRecord): x is ApiRecordFormat<CnameValue> {
return x.type === DnsTypeCNAME;
}
export interface ARecord extends UnknownRecord {
A: string;
export type TxtValue = string;
export function isTxtRecord(x: AnyRecord): x is ApiRecordFormat<TxtValue> {
return x.type === DnsTypeTXT;
}
export function isARecord(x: UnknownRecord): x is ARecord {
return x.Hdr.Rrtype === DnsTypeA;
export interface SrvValue {
priority: number;
weight: number;
port: number;
target: string;
}
export interface AaaaRecord extends UnknownRecord {
AAAA: string;
export function isSrvRecord(x: AnyRecord): x is ApiRecordFormat<SrvValue> {
return x.type === DnsTypeSRV;
}
export function isAaaaRecord(x: UnknownRecord): x is AaaaRecord {
return x.Hdr.Rrtype === DnsTypeAAAA;
export interface CaaValue {
flag: number;
tag: string;
value: string;
}
export interface CnameRecord extends UnknownRecord {
Target: string;
}
export function isCnameRecord(x: UnknownRecord): x is CnameRecord {
return x.Hdr.Rrtype === DnsTypeCNAME;
}
export interface TxtRecord extends UnknownRecord {
Txt: Array<string>;
}
export function isTxtRecord(x: UnknownRecord): x is TxtRecord {
return x.Hdr.Rrtype === DnsTypeTXT;
}
export interface SrvRecord extends UnknownRecord {
Priority: number;
Weight: number;
Port: number;
Target: string;
}
export function isSrvRecord(x: UnknownRecord): x is SrvRecord {
return x.Hdr.Rrtype === DnsTypeSRV;
}
export interface CaaRecord extends UnknownRecord {
Flag: number;
Tag: string;
Value: string;
}
export function isCaaRecord(x: UnknownRecord): x is CaaRecord {
return x.Hdr.Rrtype === DnsTypeCAA;
export function isCaaRecord(x: AnyRecord): x is ApiRecordFormat<CaaValue> {
return x.type === DnsTypeCAA;
}

View File

@ -3,24 +3,27 @@
import type {RestItem, RestTable} from "../utils/rest-table";
import PromiseTable from "../components/PromiseTable.svelte";
import PromiseLike from "../components/PromiseLike.svelte";
import type {AllRecords, ApiRecordFormat, UnknownRecord} from "../types/records";
import type {AnyRecord, AnyValue, ApiRecordFormat} from "../types/records";
import ActionPopup from "../components/ActionPopup.svelte";
type T = $$Generic<UnknownRecord>;
type T = $$Generic<AnyValue>;
export let recordName: string;
export let table: RestTable<AllRecords>;
export let emptyRecord: (() => any) | null;
export let convert: (t: T) => ApiRecordFormat;
export let rowOrdering: (rows: RestItem<AllRecords>[], domain: string, isTRecord: (t: UnknownRecord) => t is T) => RestItem<T>[];
export let isTRecord: (t: UnknownRecord) => t is T;
export let table: RestTable<AnyRecord>;
export let emptyRecord: (() => ApiRecordFormat<T>) | null;
export let rowOrdering: (
rows: RestItem<AnyRecord>[],
domain: string,
isTRecord: (t: AnyRecord) => t is ApiRecordFormat<T>,
) => RestItem<ApiRecordFormat<T>>[];
export let isTRecord: (t: AnyRecord) => t is ApiRecordFormat<T>;
let createItem: T | null = emptyRecord == null ? null : emptyRecord();
let createItem: ApiRecordFormat<T> | null = emptyRecord == null ? null : emptyRecord();
let createPopup: boolean = false;
function createRecord() {
if (createItem == null) return;
table.addItem(convert(createItem) as any);
table.addItem(createItem);
}
</script>

View File

@ -6,7 +6,6 @@
DnsTypeCNAME,
DnsTypeMX,
DnsTypeNS,
DnsTypeSOA,
DnsTypeSRV,
DnsTypeTXT,
isARecord,
@ -18,21 +17,20 @@
isSoaRecord,
isSrvRecord,
isTxtRecord,
type ARecord,
type AaaaRecord,
type AllRecords,
type AValue,
type AaaaValue,
type AnyRecord,
type AnyValue,
type ApiRecordFormat,
type CaaRecord,
type CnameRecord,
type MxRecord,
type NsRecord,
type SoaRecord,
type SrvRecord,
type TxtRecord,
type UnknownRecord,
type CaaValue,
type CnameValue,
type MxValue,
type NsValue,
type SoaValue,
type SrvValue,
type TxtValue,
} from "../types/records";
import {RestItem, RestTable} from "../utils/rest-table";
import PromiseLike from "../components/PromiseLike.svelte";
import SoaRow from "../components/domains/SoaRow.svelte";
import NsRow from "../components/domains/NsRow.svelte";
import MxRow from "../components/domains/MxRow.svelte";
@ -42,28 +40,26 @@
import CaaRow from "../components/domains/CaaRow.svelte";
import SrvRow from "../components/domains/SrvRow.svelte";
import DomainTableView from "./DomainTableView.svelte";
import ActionPopup from "../components/ActionPopup.svelte";
import NsCreate from "../components/create-domains/NsCreate.svelte";
import MxCreate from "../components/create-domains/MxCreate.svelte";
import ACreate from "../components/create-domains/ACreate.svelte";
import CnameCreate from "../components/create-domains/CnameCreate.svelte";
import CaaCreate from "../components/create-domains/CaaCreate.svelte";
import TxtCreate from "../components/create-domains/TxtCreate.svelte";
import PromiseTable from "../components/PromiseTable.svelte";
const apiAzalea = import.meta.env.VITE_API_AZALEA;
const table = new RestTable<AllRecords>(apiAzalea + "/domains/" + $domainOption + "/records", (item: AllRecords) => item.Hdr.Name);
const table = new RestTable<AnyRecord>(apiAzalea + "/domains/" + $domainOption + "/records", (item: AnyRecord) => item.name);
function rowOrdering<T extends UnknownRecord>(
rows: RestItem<AllRecords>[],
function rowOrdering<T extends AnyValue>(
rows: RestItem<AnyRecord>[],
domain: string,
isTRecord: (t: UnknownRecord) => t is T,
): RestItem<T>[] {
isTRecord: (t: AnyRecord) => t is ApiRecordFormat<T>,
): RestItem<ApiRecordFormat<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>[];
.filter(x => domainFilter(x.data.name, domain))
.sort((a, b) => a.data.name.localeCompare(b.data.name)) as unknown as RestItem<ApiRecordFormat<T>>[];
}
function domainFilter(src: string, domain: string) {
@ -91,7 +87,7 @@
}
let domainTitle: string = "";
$: (domainTitle = table.rows.length === 0 ? "Unknown" : getTitleDomain(table.rows[0].data.Hdr.Name)), $table;
$: (domainTitle = table.rows.length === 0 ? "Unknown" : getTitleDomain(table.rows[0].data.name)), $table;
let zoneFileUrl: string;
zoneFileUrl = domainTitle ? `${import.meta.env.VITE_API_AZALEA}/domains/${domainTitle}/zone-file` : "";
@ -105,11 +101,6 @@
create: null,
save: null,
empty: null,
convert: (t: SoaRecord): ApiRecordFormat => ({
name: t.Hdr.Name,
type: t.Hdr.Rrtype,
value: "",
}),
},
{
name: "NS",
@ -118,19 +109,11 @@
filter: isNsRecord,
render: NsRow,
create: NsCreate,
empty: (): NsRecord => ({
Hdr: {
Name: "",
Rrtype: DnsTypeNS,
Class: 1,
Ttl: 0,
},
Ns: "",
}),
convert: (t: NsRecord): ApiRecordFormat => ({
name: t.Hdr.Name,
type: t.Hdr.Rrtype,
value: t.Ns,
empty: (): ApiRecordFormat<NsValue> => ({
name: "",
type: DnsTypeNS,
ttl: null,
value: "",
}),
},
{
@ -140,22 +123,13 @@
filter: isMxRecord,
render: MxRow,
create: MxCreate,
empty: (): MxRecord => ({
Hdr: {
Name: "",
Rrtype: DnsTypeMX,
Class: 1,
Ttl: 0,
},
Mx: "",
Preference: 0,
}),
convert: (t: MxRecord): ApiRecordFormat => ({
name: t.Hdr.Name,
type: t.Hdr.Rrtype,
empty: (): ApiRecordFormat<MxValue> => ({
name: "",
type: DnsTypeMX,
ttl: null,
value: {
mx: t.Mx,
preference: t.Preference,
mx: "",
preference: 0,
},
}),
},
@ -163,23 +137,14 @@
name: "A/AAAA",
headers: ["Hostname", "IP Address", "TTL"],
locked: false,
filter: (t: UnknownRecord) => isARecord(t) || isAaaaRecord(t),
filter: (t: AnyRecord) => isARecord(t) || isAaaaRecord(t),
render: ARow,
create: ACreate,
empty: (): ARecord | AaaaRecord => ({
Hdr: {
Name: "",
Rrtype: 0, // this is on purpose
Class: 1,
Ttl: 0,
},
A: "",
AAAA: "",
}),
convert: (t: ARecord | AaaaRecord): ApiRecordFormat => ({
name: t.Hdr.Name,
type: t.Hdr.Rrtype,
value: isARecord(t) ? t.A : isAaaaRecord(t) ? t.AAAA : "",
empty: (): ApiRecordFormat<AValue | AaaaValue> => ({
name: "",
type: 0, // this is on purpose
ttl: null,
value: "",
}),
},
{
@ -189,19 +154,11 @@
filter: isCnameRecord,
render: CnameRow,
create: CnameCreate,
empty: (): CnameRecord => ({
Hdr: {
Name: "",
Rrtype: DnsTypeCNAME,
Class: 1,
Ttl: 0,
},
Target: "",
}),
convert: (t: CnameRecord): ApiRecordFormat => ({
name: t.Hdr.Name,
type: t.Hdr.Rrtype,
value: t.Target,
empty: (): ApiRecordFormat<CnameValue> => ({
name: "",
type: DnsTypeCNAME,
ttl: null,
value: "",
}),
},
{
@ -211,19 +168,11 @@
filter: isTxtRecord,
render: TxtRow,
create: TxtCreate,
empty: (): TxtRecord => ({
Hdr: {
Name: "",
Rrtype: DnsTypeTXT,
Class: 1,
Ttl: 0,
},
Txt: [""],
}),
convert: (t: TxtRecord): ApiRecordFormat => ({
name: t.Hdr.Name,
type: t.Hdr.Rrtype,
value: t.Txt.join("\n"),
empty: (): ApiRecordFormat<TxtValue> => ({
name: "",
type: DnsTypeTXT,
ttl: null,
value: "",
}),
},
{
@ -233,26 +182,15 @@
filter: isSrvRecord,
render: SrvRow,
create: null,
empty: (): SrvRecord => ({
Hdr: {
Name: "",
Rrtype: DnsTypeSRV,
Class: 1,
Ttl: 0,
},
Priority: 0,
Weight: 0,
Port: 0,
Target: "",
}),
convert: (t: SrvRecord): ApiRecordFormat => ({
name: t.Hdr.Name,
type: t.Hdr.Rrtype,
empty: (): ApiRecordFormat<SrvValue> => ({
name: "",
type: DnsTypeSRV,
ttl: null,
value: {
priority: t.Priority,
weight: t.Weight,
port: t.Port,
target: t.Target,
priority: 0,
weight: 0,
port: 0,
target: "",
},
}),
},
@ -263,24 +201,14 @@
filter: isCaaRecord,
render: CaaRow,
create: CaaCreate,
empty: (): CaaRecord => ({
Hdr: {
Name: "",
Rrtype: DnsTypeCAA,
Class: 1,
Ttl: 0,
},
Flag: 0,
Tag: "",
Value: "",
}),
convert: (t: CaaRecord): ApiRecordFormat => ({
name: t.Hdr.Name,
type: t.Hdr.Rrtype,
empty: (): ApiRecordFormat<CaaValue> => ({
name: "",
type: DnsTypeCAA,
ttl: null,
value: {
flag: t.Flag,
tag: t.Tag,
value: t.Value,
flag: 0,
tag: "",
value: "",
},
}),
},
@ -301,14 +229,7 @@
{/if}
{#each recordTypes as recordType}
<DomainTableView
recordName={recordType.name}
{table}
emptyRecord={recordType.empty}
convert={recordType.convert}
{rowOrdering}
isTRecord={recordType.filter}
>
<DomainTableView recordName={recordType.name} {table} emptyRecord={recordType.empty} {rowOrdering} isTRecord={recordType.filter}>
<tr slot="headers">
{#each recordType.headers as header}
<th>{header}</th>
@ -322,7 +243,7 @@
{/if}
</svelte:fragment>
<svelte:component this={recordType.render} slot="row" let:value {value} locked={recordType.locked} />
<svelte:component this={recordType.render} slot="row" let:value item={value} locked={recordType.locked} />
</DomainTableView>
{/each}