ui: Can group domains by user preference
This commit is contained in:
parent
8ee8b07ce3
commit
84458c0b48
|
@ -52,6 +52,7 @@ func declareDomainsRoutes(cfg *config.Options, router *gin.RouterGroup) {
|
|||
apiDomainsRoutes.Use(DomainHandler)
|
||||
|
||||
apiDomainsRoutes.GET("", GetDomain)
|
||||
apiDomainsRoutes.PUT("", UpdateDomain)
|
||||
apiDomainsRoutes.DELETE("", delDomain)
|
||||
|
||||
declareZonesRoutes(cfg, apiDomainsRoutes)
|
||||
|
@ -156,6 +157,7 @@ type apiDomain struct {
|
|||
IdProvider int64 `json:"id_provider"`
|
||||
DomainName string `json:"domain"`
|
||||
ZoneHistory []happydns.ZoneMeta `json:"zone_history"`
|
||||
Group string `json:"group,omitempty"`
|
||||
}
|
||||
|
||||
func GetDomain(c *gin.Context) {
|
||||
|
@ -166,6 +168,7 @@ func GetDomain(c *gin.Context) {
|
|||
IdProvider: domain.IdProvider,
|
||||
DomainName: domain.DomainName,
|
||||
ZoneHistory: []happydns.ZoneMeta{},
|
||||
Group: domain.Group,
|
||||
}
|
||||
|
||||
for _, zm := range domain.ZoneHistory {
|
||||
|
@ -181,6 +184,33 @@ func GetDomain(c *gin.Context) {
|
|||
c.JSON(http.StatusOK, ret)
|
||||
}
|
||||
|
||||
func UpdateDomain(c *gin.Context) {
|
||||
old := c.MustGet("domain").(*happydns.Domain)
|
||||
|
||||
var domain apiDomain
|
||||
err := c.ShouldBindJSON(&domain)
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if old.Id != domain.Id {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "You cannot change the domain reserved ID"})
|
||||
return
|
||||
}
|
||||
|
||||
old.Group = domain.Group
|
||||
|
||||
err = storage.MainStore.UpdateDomain(old)
|
||||
if err != nil {
|
||||
log.Printf("%s: Unable to UpdateDomain in UpdateDomain: %s", c.ClientIP(), err.Error())
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Sorry, we are currently unable to update your domain. Please retry later."})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, old)
|
||||
}
|
||||
|
||||
func delDomain(c *gin.Context) {
|
||||
if err := storage.MainStore.DeleteDomain(c.MustGet("domain").(*happydns.Domain)); err != nil {
|
||||
log.Printf("%s was unable to DeleteDomain: %s", c.ClientIP(), err.Error())
|
||||
|
|
|
@ -51,7 +51,7 @@ type Domain struct {
|
|||
DomainName string `json:"domain"`
|
||||
|
||||
// Group is a hint string aims to group domains.
|
||||
Group string `json:"group"`
|
||||
Group string `json:"group,omitempty"`
|
||||
|
||||
// ZoneHistory are the identifiers to the Zone attached to the current
|
||||
// Domain.
|
||||
|
|
|
@ -42,5 +42,9 @@ export default {
|
|||
|
||||
listDomains () {
|
||||
return Api().get('/api/domains')
|
||||
},
|
||||
|
||||
updateDomain (domain) {
|
||||
return Api().put('/api/domains/' + encodeURIComponent(domain.domain), { id: domain.id, id_owner: domain.id_owner, id_provider: domain.id_provider, domain: domain.domain, group: domain.group })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,9 +37,12 @@
|
|||
<b-spinner variant="primary" :label="$t('common.spinning')" class="my-2 mr-3" /> <i18n :path="loadingStr" />
|
||||
</div>
|
||||
<slot v-else-if="domains.length === 0" name="no-domain" />
|
||||
<div v-else v-for="(domains, group) in groups" :key="group" :class="Object.keys(groups).length != 1?'border-top':''">
|
||||
<div v-else v-for="(domains, group) in groups" :key="group" :class="Object.keys(groups).length != 1?'border-top':''" style="margin-top: 1.4em">
|
||||
<div v-if="Object.keys(groups).length != 1" class="text-center" style="height: 1em">
|
||||
<h3 class="d-inline-block px-1" style="background: white; position: relative; top: -.65em">{{ group }}</h3>
|
||||
<h3 class="d-inline-block px-1" style="background: white; position: relative; top: -.65em">
|
||||
<i18n v-if="group === 'undefined'" path="domaingroups.no-group" />
|
||||
<span v-else>{{ group }}</span>
|
||||
</h3>
|
||||
</div>
|
||||
<h-list
|
||||
:items="domains"
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: 'hDomaingroupList',
|
||||
name: 'HDomaingroupList',
|
||||
|
||||
components: {
|
||||
hList: () => import('@/components/hList')
|
||||
|
@ -76,7 +76,7 @@ export default {
|
|||
}
|
||||
})
|
||||
|
||||
return Object.keys(groups)
|
||||
return Object.keys(groups).sort()
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
<!--
|
||||
Copyright or © or Copr. happyDNS (2021)
|
||||
|
||||
contact@happydns.org
|
||||
|
||||
This software is a computer program whose purpose is to provide a modern
|
||||
interface to interact with DNS systems.
|
||||
|
||||
This software is governed by the CeCILL license under French law and abiding
|
||||
by the rules of distribution of free software. You can use, modify and/or
|
||||
redistribute the software under the terms of the CeCILL license as
|
||||
circulated by CEA, CNRS and INRIA at the following URL
|
||||
"http://www.cecill.info".
|
||||
|
||||
As a counterpart to the access to the source code and rights to copy, modify
|
||||
and redistribute granted by the license, users are provided only with a
|
||||
limited warranty and the software's author, the holder of the economic
|
||||
rights, and the successive licensors have only limited liability.
|
||||
|
||||
In this respect, the user's attention is drawn to the risks associated with
|
||||
loading, using, modifying and/or developing or reproducing the software by
|
||||
the user in light of its specific status of free software, that may mean
|
||||
that it is complicated to manipulate, and that also therefore means that it
|
||||
is reserved for developers and experienced professionals having in-depth
|
||||
computer knowledge. Users are therefore encouraged to load and test the
|
||||
software's suitability as regards their requirements in conditions enabling
|
||||
the security of their systems and/or data to be ensured and, more generally,
|
||||
to use and operate it in the same conditions as regards security.
|
||||
|
||||
The fact that you are presently reading this means that you have had
|
||||
knowledge of the CeCILL license and that you accept its terms.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<b-modal
|
||||
id="modal-manageDnGroups"
|
||||
scrollable
|
||||
size="lg"
|
||||
:title="$t('domaingroups.manage')"
|
||||
@cancel="handleModalCancel"
|
||||
@ok="handleModalOk"
|
||||
>
|
||||
<b-form
|
||||
class="float-right"
|
||||
inline
|
||||
@submit="addGroup"
|
||||
>
|
||||
<b-form-input
|
||||
id="newgroup"
|
||||
v-model="newgroup"
|
||||
:placeholder="$t('domaingroups.new')"
|
||||
required
|
||||
/>
|
||||
<b-button
|
||||
type="submit"
|
||||
variant="primary"
|
||||
>
|
||||
<i18n path="common.add" />
|
||||
</b-button>
|
||||
</b-form>
|
||||
<div class="clearfix mb-2" />
|
||||
<h-zone-list
|
||||
:domains="sortedDomains"
|
||||
>
|
||||
<template #badges="{ domain }">
|
||||
<div class="float-right">
|
||||
<b-form-select
|
||||
v-model="domain.group"
|
||||
:options="groups"
|
||||
@change="groupChanged($event, domain)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</h-zone-list>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'HDomaingroupModal',
|
||||
|
||||
components: {
|
||||
hZoneList: () => import('@/components/ZoneList')
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
diff: { },
|
||||
groups: [],
|
||||
newgroup: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters('domains', ['sortedDomains'])
|
||||
},
|
||||
|
||||
mounted () {
|
||||
const groups = { }
|
||||
|
||||
this.sortedDomains.forEach((domain, index) => {
|
||||
if (groups[domain.group] === undefined) {
|
||||
groups[domain.group] = []
|
||||
}
|
||||
|
||||
groups[domain.group].push(domain)
|
||||
})
|
||||
|
||||
const g = []
|
||||
Object.keys(groups).forEach((d) => {
|
||||
g.push({ text: d === 'undefined' ? this.$t('domaingroups.no-group') : d, value: d })
|
||||
})
|
||||
this.groups = g
|
||||
},
|
||||
|
||||
methods: {
|
||||
addGroup (e) {
|
||||
e.preventDefault()
|
||||
this.groups.push(this.newgroup)
|
||||
this.newgroup = ''
|
||||
},
|
||||
|
||||
groupChanged (gr, domain) {
|
||||
this.diff[domain.id] = () => {
|
||||
this.$store.dispatch('domains/updateDomain', domain)
|
||||
}
|
||||
},
|
||||
|
||||
handleModalCancel () {
|
||||
this.$store.dispatch('domains/getAllMyDomains')
|
||||
},
|
||||
|
||||
handleModalOk () {
|
||||
Object.keys(this.diff).forEach((k) => this.diff[k]())
|
||||
this.$store.dispatch('domains/getAllMyDomains')
|
||||
},
|
||||
|
||||
show () {
|
||||
this.$bvModal.show('modal-manageDnGroups')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -56,7 +56,7 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: 'hList',
|
||||
name: 'HList',
|
||||
|
||||
props: {
|
||||
button: {
|
||||
|
|
|
@ -116,7 +116,8 @@
|
|||
},
|
||||
"domaingroups": {
|
||||
"manage": "Manage your domain's groups",
|
||||
"no-group": "Ungroupped",
|
||||
"new": "New group",
|
||||
"no-group": "Miscellaneous",
|
||||
"title": "Your groups"
|
||||
},
|
||||
"email": {
|
||||
|
|
|
@ -70,6 +70,16 @@ export default {
|
|||
}
|
||||
)
|
||||
// TODO: handle errors here
|
||||
},
|
||||
|
||||
updateDomain ({ commit }, domain) {
|
||||
DomainsApi.updateDomain(domain)
|
||||
.then(
|
||||
response => {
|
||||
const details = response.data
|
||||
commit('setDomainDetailed', { domain: domain.domain, details })
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
</router-link>
|
||||
</b-col>
|
||||
<b-col class="pl-0">
|
||||
<b-form-select :value="domain.domain" :options="sortedDomains" value-field="domain" text-field="domain" @input="changeDomain($event)" />
|
||||
<b-form-select :value="domain.domain" :options="sortedDomainsByGroup" value-field="domain" text-field="domain" @input="changeDomain($event)" />
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
|
@ -237,6 +237,32 @@ export default {
|
|||
return this.selectedDiff.filter((msg) => (/^MODIFY/.test(msg)))
|
||||
},
|
||||
|
||||
sortedDomainsByGroup () {
|
||||
if (!this.sortedDomains) {
|
||||
return this.sortedDomains
|
||||
}
|
||||
|
||||
const groups = {}
|
||||
this.sortedDomains.forEach((domain) => {
|
||||
if (!groups[domain.group]) {
|
||||
groups[domain.group] = []
|
||||
}
|
||||
|
||||
groups[domain.group].push(domain)
|
||||
})
|
||||
|
||||
const options = []
|
||||
for (const g in groups) {
|
||||
if (g === 'undefined') {
|
||||
options.push(...groups[g])
|
||||
} else {
|
||||
options.push({ label: g, options: groups[g] })
|
||||
}
|
||||
}
|
||||
|
||||
return options
|
||||
},
|
||||
|
||||
zoneDiffAnalyzed () {
|
||||
if (!this.zoneDiff) {
|
||||
return null
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
<h-zone-list
|
||||
ref="zlist"
|
||||
button
|
||||
display-by-groups
|
||||
:domains="filteredDomains"
|
||||
@click="showDomain($event)"
|
||||
>
|
||||
|
@ -136,6 +137,7 @@
|
|||
:selected-group="filteredGroup"
|
||||
@group-selected="filteredGroup = $event"
|
||||
/>
|
||||
<h-domaingroup-modal ref="dgModal" />
|
||||
</b-card>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
@ -149,6 +151,7 @@ export default {
|
|||
|
||||
components: {
|
||||
hDomaingroupList: () => import('@/components/hDomaingroupList'),
|
||||
hDomaingroupModal: () => import('@/components/hDomaingroupModal'),
|
||||
hListGroupInputNewDomain: () => import('@/components/hListGroupInputNewDomain'),
|
||||
hProviderListDomains: () => import('@/components/hProviderListDomains'),
|
||||
hProviderList: () => import('@/components/providerList'),
|
||||
|
@ -201,6 +204,10 @@ export default {
|
|||
|
||||
showDomain (domain) {
|
||||
this.$router.push('/domains/' + encodeURIComponent(domain.domain))
|
||||
},
|
||||
|
||||
showGroupModal () {
|
||||
this.$refs.dgModal.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue