mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
refactor: rework async DomainDns
This commit is contained in:
parent
20bbdb7e86
commit
e99a50e5fc
2 changed files with 81 additions and 70 deletions
|
@ -216,3 +216,18 @@ export type Diagnosis = {
|
||||||
description: string
|
description: string
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DOMAINS
|
||||||
|
|
||||||
|
export type DNSRecord = {
|
||||||
|
name: string
|
||||||
|
type: string
|
||||||
|
managed_by_yunohost: boolean
|
||||||
|
old_content: string
|
||||||
|
content: string
|
||||||
|
spaces: string // Added when formating
|
||||||
|
}
|
||||||
|
export type DNSCategories = Record<
|
||||||
|
'create' | 'update' | 'delete' | 'unchanged',
|
||||||
|
DNSRecord[]
|
||||||
|
>
|
||||||
|
|
|
@ -4,8 +4,16 @@ import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { useAutoModal } from '@/composables/useAutoModal'
|
import { useAutoModal } from '@/composables/useAutoModal'
|
||||||
import { isEmptyValue } from '@/helpers/commons'
|
import type { Obj, StateVariant } from '@/types/commons'
|
||||||
import { useInitialQueries } from '@/composables/useInitialQueries'
|
import type { DNSCategories, DNSRecord } from '@/types/core/api'
|
||||||
|
|
||||||
|
type DNSChanges = {
|
||||||
|
action: 'create' | 'update' | 'delete'
|
||||||
|
icon: string
|
||||||
|
variant: string
|
||||||
|
records: DNSRecord[]
|
||||||
|
}
|
||||||
|
type DNSError = { icon: string; variant: StateVariant; message: string }
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
name: string
|
name: string
|
||||||
|
@ -13,79 +21,70 @@ const props = defineProps<{
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const modalConfirm = useAutoModal()
|
const modalConfirm = useAutoModal()
|
||||||
const { loading } = useInitialQueries(
|
|
||||||
[{ uri: `domains/${props.name}/dns/suggest` }],
|
const dnsConfig = await api.get<string>({
|
||||||
{ onQueriesResponse },
|
uri: `domains/${props.name}/dns/suggest`,
|
||||||
)
|
initial: true,
|
||||||
|
})
|
||||||
|
|
||||||
const showAutoConfigCard = ref(true)
|
const showAutoConfigCard = ref(true)
|
||||||
const showManualConfigCard = ref(false)
|
const showManualConfigCard = ref(false)
|
||||||
const dnsConfig = ref('')
|
const dnsChanges = ref<DNSChanges[] | null>(null)
|
||||||
const dnsChanges = ref(undefined)
|
const dnsErrors = ref<DNSError[]>([])
|
||||||
const dnsErrors = ref(undefined)
|
const dnsZone = ref<DNSRecord[] | null>(null)
|
||||||
const dnsZone = ref(undefined)
|
const force = ref<boolean | null>(null)
|
||||||
const force = ref(null)
|
|
||||||
|
|
||||||
getDnsChanges()
|
getDnsChanges()
|
||||||
|
// FIXME other Suspense? get types
|
||||||
function onQueriesResponse(suggestedConfig: any) {
|
|
||||||
dnsConfig.value = suggestedConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDnsChanges() {
|
function getDnsChanges() {
|
||||||
loading.value = true
|
|
||||||
|
|
||||||
return api
|
return api
|
||||||
.post({
|
.post({
|
||||||
uri: `domains/${props.name}/dns/push?dry_run`,
|
uri: `domains/${props.name}/dns/push?dry_run`,
|
||||||
showModal: false,
|
showModal: true,
|
||||||
websocket: false,
|
websocket: false,
|
||||||
})
|
})
|
||||||
.then((dnsChanges) => {
|
.then((dnsCategories: DNSCategories) => {
|
||||||
function getLongest(arr, key) {
|
let canForce = false
|
||||||
|
|
||||||
|
function getLongest(arr: Obj[], key: string) {
|
||||||
return arr.reduce((acc, obj) => {
|
return arr.reduce((acc, obj) => {
|
||||||
if (obj[key].length > acc) return obj[key].length
|
if (obj[key].length > acc) return obj[key].length
|
||||||
return acc
|
return acc
|
||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
const changes = []
|
function addSpace(str: string, len: number, prepend: boolean = false) {
|
||||||
let canForce = false
|
return (prepend ? str : '') + ' '.repeat(len - str.length + 1)
|
||||||
const categories = [
|
|
||||||
{ action: 'create', icon: 'plus', variant: 'success' },
|
|
||||||
{ action: 'update', icon: 'exchange', variant: 'warning' },
|
|
||||||
{ action: 'delete', icon: 'minus', variant: 'danger' },
|
|
||||||
]
|
|
||||||
categories.forEach((category) => {
|
|
||||||
const records = dnsChanges[category.action]
|
|
||||||
if (records && records.length > 0) {
|
|
||||||
const longestName = getLongest(records, 'name')
|
|
||||||
const longestType = getLongest(records, 'type')
|
|
||||||
records.forEach((record) => {
|
|
||||||
record.name =
|
|
||||||
record.name + ' '.repeat(longestName - record.name.length + 1)
|
|
||||||
record.spaces = ' '.repeat(longestType - record.type.length + 1)
|
|
||||||
if (record.managed_by_yunohost === false) canForce = true
|
|
||||||
})
|
|
||||||
changes.push({ ...category, records })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const unchanged = dnsChanges.unchanged
|
|
||||||
if (unchanged) {
|
|
||||||
const longestName = getLongest(unchanged, 'name')
|
|
||||||
const longestType = getLongest(unchanged, 'type')
|
|
||||||
unchanged.forEach((record) => {
|
|
||||||
record.name =
|
|
||||||
record.name + ' '.repeat(longestName - record.name.length + 1)
|
|
||||||
record.spaces = ' '.repeat(longestType - record.type.length + 1)
|
|
||||||
})
|
|
||||||
dnsZone.value = unchanged
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatRecords(records?: DNSRecord[]) {
|
||||||
|
if (!records) return null
|
||||||
|
const longestName = getLongest(records, 'name')
|
||||||
|
const longestType = getLongest(records, 'type')
|
||||||
|
return records.map((record) => {
|
||||||
|
record.name = addSpace(record.name, longestName, true)
|
||||||
|
record.spaces = addSpace(record.type, longestType)
|
||||||
|
if (record.managed_by_yunohost) canForce = true
|
||||||
|
return record
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const categories = [
|
||||||
|
{ action: 'create' as const, icon: 'plus', variant: 'success' },
|
||||||
|
{ action: 'update' as const, icon: 'exchange', variant: 'warning' },
|
||||||
|
{ action: 'delete' as const, icon: 'minus', variant: 'danger' },
|
||||||
|
]
|
||||||
|
const changes = categories
|
||||||
|
.map((category) => {
|
||||||
|
const records = formatRecords(dnsCategories[category.action])
|
||||||
|
if (!records) return null
|
||||||
|
return { ...category, records }
|
||||||
|
})
|
||||||
|
.filter((dnsChange) => dnsChange !== null) as DNSChanges[]
|
||||||
|
|
||||||
|
dnsZone.value = formatRecords(dnsCategories.unchanged)
|
||||||
dnsChanges.value = changes.length > 0 ? changes : null
|
dnsChanges.value = changes.length > 0 ? changes : null
|
||||||
force.value = canForce ? false : null
|
force.value = canForce ? false : null
|
||||||
loading.value = false
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if (err.name !== 'APIBadRequestError') throw err
|
if (err.name !== 'APIBadRequestError') throw err
|
||||||
|
@ -100,7 +99,6 @@ function getDnsChanges() {
|
||||||
showManualConfigCard.value = true
|
showManualConfigCard.value = true
|
||||||
showAutoConfigCard.value = false
|
showAutoConfigCard.value = false
|
||||||
}
|
}
|
||||||
loading.value = false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,24 +113,22 @@ async function pushDnsChanges() {
|
||||||
uri: `domains/${props.name}/dns/push${force.value ? '?force' : ''}`,
|
uri: `domains/${props.name}/dns/push${force.value ? '?force' : ''}`,
|
||||||
humanKey: { key: 'domains.push_dns_changes', name: props.name },
|
humanKey: { key: 'domains.push_dns_changes', name: props.name },
|
||||||
})
|
})
|
||||||
.then(async (responseData) => {
|
.then(async (responseData: Obj<string[]>) => {
|
||||||
await getDnsChanges()
|
await getDnsChanges()
|
||||||
if (!isEmptyValue(responseData)) {
|
dnsErrors.value = Object.keys(responseData).reduce((acc, key) => {
|
||||||
dnsErrors.value = Object.keys(responseData).reduce((acc, key) => {
|
const args =
|
||||||
const args =
|
key === 'warnings'
|
||||||
key === 'warnings'
|
? { icon: 'warning', variant: 'warning' as const }
|
||||||
? { icon: 'warning', variant: 'warning' }
|
: { icon: 'ban', variant: 'danger' as const }
|
||||||
: { icon: 'ban', variant: 'danger' }
|
responseData[key].forEach((message) => acc.push({ ...args, message }))
|
||||||
responseData[key].forEach((message) => acc.push({ ...args, message }))
|
return acc
|
||||||
return acc
|
}, [] as DNSError[])
|
||||||
}, [])
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ViewBase :loading="loading" skeleton="CardInfoSkeleton">
|
<div>
|
||||||
<section v-if="showAutoConfigCard" class="panel-section">
|
<section v-if="showAutoConfigCard" class="panel-section">
|
||||||
<BCardTitle title-tag="h3">
|
<BCardTitle title-tag="h3">
|
||||||
{{ $t('domain.dns.auto_config') }}
|
{{ $t('domain.dns.auto_config') }}
|
||||||
|
@ -176,7 +172,7 @@ async function pushDnsChanges() {
|
||||||
:title="
|
:title="
|
||||||
managed_by_yunohost === false && force !== true
|
managed_by_yunohost === false && force !== true
|
||||||
? $t('domain.dns.auto_config_ignored')
|
? $t('domain.dns.auto_config_ignored')
|
||||||
: null
|
: undefined
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<YIcon :iname="icon" :class="'text-' + variant" />
|
<YIcon :iname="icon" :class="'text-' + variant" />
|
||||||
|
@ -203,7 +199,7 @@ async function pushDnsChanges() {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- CONFIG ERROR ALERT -->
|
<!-- CONFIG ERROR ALERT -->
|
||||||
<template v-if="dnsErrors && dnsErrors.length">
|
<template v-if="dnsErrors.length">
|
||||||
<ReadOnlyAlertItem
|
<ReadOnlyAlertItem
|
||||||
v-for="({ variant, icon, message }, i) in dnsErrors"
|
v-for="({ variant, icon, message }, i) in dnsErrors"
|
||||||
:key="i"
|
:key="i"
|
||||||
|
@ -268,7 +264,7 @@ async function pushDnsChanges() {
|
||||||
|
|
||||||
<pre class="log">{{ dnsConfig }}</pre>
|
<pre class="log">{{ dnsConfig }}</pre>
|
||||||
</section>
|
</section>
|
||||||
</ViewBase>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
Loading…
Add table
Reference in a new issue