Propagate services values through components

This commit is contained in:
nemunaire 2020-06-11 00:09:33 +02:00
parent d41a073fc3
commit 23311495ce
14 changed files with 240 additions and 66 deletions

View File

@ -50,7 +50,7 @@
</template> </template>
<script> <script>
import ServicesApi from '@/services/ServicesApi' import ServiceSpecsApi from '@/services/ServiceSpecsApi'
export default { export default {
name: 'HDomainService', name: 'HDomainService',
@ -60,9 +60,17 @@ export default {
}, },
props: { props: {
origin: {
type: String,
required: true
},
service: { service: {
type: Object, type: Object,
required: true required: true
},
zoneMeta: {
type: Object,
required: true
} }
}, },
@ -80,7 +88,7 @@ export default {
}, },
created () { created () {
ServicesApi.getServices() ServiceSpecsApi.getServiceSpecs()
.then( .then(
(response) => (this.services = response.data) (response) => (this.services = response.data)
) )

View File

@ -32,7 +32,7 @@
--> -->
<template> <template>
<component :is="itemComponent" v-model="value" :edit="edit" :edit-toolbar="editToolbar" :index="index" :services="services" :specs="specs" :type="type" /> <component :is="itemComponent" :value="value" @input="$emit('input', $event)" :edit="edit" :edit-toolbar="editToolbar" :index="index" :services="services" :specs="specs" :type="type" @saveService="$emit('saveService')" />
</template> </template>
<script> <script>

View File

@ -38,7 +38,7 @@
<label v-if="specs.label" :for="'spec-' + index" :title="specs.label" class="col-md-4 col-form-label text-truncate text-md-right text-primary">{{ specs.label }}</label> <label v-if="specs.label" :for="'spec-' + index" :title="specs.label" class="col-md-4 col-form-label text-truncate text-md-right text-primary">{{ specs.label }}</label>
<label v-else :for="'spec-' + index" :title="specs.label" class="col-md-4 col-form-label text-truncate text-md-right text-primary">{{ specs.id }}</label> <label v-else :for="'spec-' + index" :title="specs.label" class="col-md-4 col-form-label text-truncate text-md-right text-primary">{{ specs.id }}</label>
<b-col md="8"> <b-col md="8">
<h-resource-value-input-raw v-model="value" :edit="edit" :index="index" :specs="specs" /> <h-resource-value-input-raw v-model="val" :edit="edit" :index="index" :specs="specs" />
<p v-if="specs.description" class="text-justify" style="line-height: 1.1"> <p v-if="specs.description" class="text-justify" style="line-height: 1.1">
<small class="text-muted">{{ specs.description }}</small> <small class="text-muted">{{ specs.description }}</small>
</p> </p>
@ -71,6 +71,17 @@ export default {
value: { value: {
required: true required: true
} }
},
computed: {
val: {
get () {
return this.value
},
set (val) {
this.$emit('input', val)
}
}
} }
} }
</script> </script>

View File

@ -33,36 +33,50 @@
<template> <template>
<div ng-if="!isLoading()"> <div ng-if="!isLoading()">
<div class="text-right"> <div v-for="(val,key) in value" :key="key">
<b-button v-if="!edit" type="button" size="sm" variant="outline-primary" class="mx-1" @click="toogleServiceEdit()"> <b-row>
<b-icon icon="pencil" /> <b-col>
Edit <h3>
</b-button> <span v-if="!editKeys[key]">{{ key }}</span>
<b-button v-else type="button" size="sm" variant="primary" class="mx-1" @click="submitService(index, idx)"> <b-input-group v-else>
<b-form-input v-model="newKeys[key]" />
<template v-slot:append>
<b-button v-if="editKeys[key]" type="button" size="sm" variant="primary" @click="rename(key)">
<b-icon icon="check" /> <b-icon icon="check" />
Save those modifications Rename
</b-button> </b-button>
<b-button type="button" size="sm" variant="outline-danger" class="mx-1"> </template>
</b-input-group>
<b-button v-if="!editKeys[key]" type="button" size="sm" variant="link" @click="toogleKeyEdit(key)">
<b-icon icon="pencil" />
</b-button>
</h3>
</b-col>
<b-col sm="auto">
<b-button type="button" size="sm" variant="outline-danger" class="mx-1 float-right">
<b-icon icon="trash" /> <b-icon icon="trash" />
Delete Delete
</b-button> </b-button>
</div> </b-col>
<div v-for="(val,key) in value" :key="key"> </b-row>
<h3>{{ key }}</h3>
<h-resource-value <h-resource-value
v-model="value[key]" v-model="value[key]"
:edit="edit"
:services="services" :services="services"
:specs="service_specs" :specs="service_specs"
:type="main_type" :type="main_type"
@saveService="$emit('saveService')"
/> />
<hr> <hr>
</div> </div>
<b-button>
Add new {{ specs.id }}
</b-button>
</div> </div>
</template> </template>
<script> <script>
import ServicesApi from '@/services/ServicesApi' import ServiceSpecsApi from '@/services/ServiceSpecsApi'
import Vue from 'vue'
export default { export default {
name: 'HResourceValueMap', name: 'HResourceValueMap',
@ -72,10 +86,6 @@ export default {
}, },
props: { props: {
edit: {
type: Boolean,
default: false
},
services: { services: {
type: Object, type: Object,
required: true required: true
@ -96,6 +106,8 @@ export default {
data: function () { data: function () {
return { return {
editKeys: {},
newKeys: {},
key_type: '', key_type: '',
main_type: '', main_type: '',
service_specs: null service_specs: null
@ -136,7 +148,7 @@ export default {
methods: { methods: {
pullServiceSpecs () { pullServiceSpecs () {
ServicesApi.getServiceSpecs(this.main_type) ServiceSpecsApi.getServiceSpecs(this.main_type)
.then( .then(
(response) => { (response) => {
this.service_specs = response.data this.service_specs = response.data
@ -144,8 +156,17 @@ export default {
) )
}, },
toogleServiceEdit () { rename (key) {
this.edit = !this.edit if (key !== this.newKeys[key]) {
Vue.set(this.value, this.newKeys[key], this.value[key])
Vue.delete(this.value, key)
}
Vue.delete(this.editKeys, key)
},
toogleKeyEdit (key) {
Vue.set(this.newKeys, key, key)
Vue.set(this.editKeys, key, !this.editKeys[key])
} }
} }
} }

View File

@ -52,6 +52,7 @@
:services="services" :services="services"
:specs="spec" :specs="spec"
:type="spec.type" :type="spec.type"
@saveService="$emit('saveService')"
/> />
<b-button v-else> <b-button v-else>
Create {{ spec.id }} Create {{ spec.id }}
@ -64,7 +65,7 @@
<b-icon icon="pencil" /> <b-icon icon="pencil" />
Edit Edit
</b-button> </b-button>
<b-button v-else type="button" size="sm" variant="primary" class="mx-1" @click="submitService(index, idx)"> <b-button v-else type="button" size="sm" variant="primary" class="mx-1" @click="$emit('saveService')">
<b-icon icon="check" /> <b-icon icon="check" />
Save those modifications Save those modifications
</b-button> </b-button>
@ -81,13 +82,14 @@
:services="services" :services="services"
:specs="spec" :specs="spec"
:type="spec.type" :type="spec.type"
@saveService="$emit('saveService')"
/> />
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import ServicesApi from '@/services/ServicesApi' import ServiceSpecsApi from '@/services/ServiceSpecsApi'
export default { export default {
name: 'HResourceValueObject', name: 'HResourceValueObject',
@ -150,7 +152,7 @@ export default {
methods: { methods: {
pullServiceSpecs () { pullServiceSpecs () {
ServicesApi.getServiceSpecs(this.type) ServiceSpecsApi.getServiceSpecs(this.type)
.then( .then(
(response) => { (response) => {
this.service_specs = response.data this.service_specs = response.data

View File

@ -40,14 +40,14 @@
</b-button> </b-button>
</template> </template>
<template v-slot:cell()="row"> <template v-slot:cell()="row">
<h-resource-value v-if="service_specs.fields" v-model="row.item[row.field.key]" :edit="edit_row.indexOf(row.index) >= 0" :index="row.index" :services="services" :specs="service_specs.fields[row.field.index]" :type="service_specs.fields[row.field.index].type" no-decorate /> <h-resource-value v-if="service_specs.fields" v-model="row.item[row.field.key]" :edit="edit_row.indexOf(row.index) >= 0" :index="row.index" :services="services" :specs="service_specs.fields[row.field.index]" :type="service_specs.fields[row.field.index].type" no-decorate @saveService="$emit('saveService')" />
<h-resource-value v-else v-model="row.item" :edit="edit_row.indexOf(row.index) >= 0" :index="row.index" :services="services" :specs="specs" :type="row_type" no-decorate /> <h-resource-value v-else v-model="row.item" :edit="edit_row.indexOf(row.index) >= 0" :index="row.index" :services="services" :specs="specs" :type="row_type" no-decorate @saveService="$emit('saveService')" />
</template> </template>
<template v-slot:cell(_actions)="row"> <template v-slot:cell(_actions)="row">
<b-button v-if="edit_row.indexOf(row.index) < 0" size="sm" title="Edit" variant="outline-primary" class="mx-1" @click="editService(row)"> <b-button v-if="edit_row.indexOf(row.index) < 0" size="sm" title="Edit" variant="outline-primary" class="mx-1" @click="editService(row)">
<b-icon icon="pencil" /> <b-icon icon="pencil" />
</b-button> </b-button>
<b-button v-else type="button" title="Save the modifications" size="sm" variant="primary" class="mx-1" @click="submitService(row.item)"> <b-button v-else type="button" title="Save the modifications" size="sm" variant="primary" class="mx-1" @click="$emit('saveService')">
<b-icon icon="check" /> <b-icon icon="check" />
</b-button> </b-button>
<b-button type="button" title="Delete" size="sm" variant="outline-danger" class="mx-1" @click="deleteService(row.item)"> <b-button type="button" title="Delete" size="sm" variant="outline-danger" class="mx-1" @click="deleteService(row.item)">
@ -59,7 +59,7 @@
</template> </template>
<script> <script>
import ServicesApi from '@/services/ServicesApi' import ServiceSpecsApi from '@/services/ServiceSpecsApi'
export default { export default {
name: 'HResourceValueTable', name: 'HResourceValueTable',
@ -147,7 +147,7 @@ export default {
if (this.row_type === 'string') { if (this.row_type === 'string') {
this.service_specs = {} this.service_specs = {}
} else { } else {
ServicesApi.getServiceSpecs(this.row_type) ServiceSpecsApi.getServiceSpecs(this.row_type)
.then( .then(
(response) => { (response) => {
this.service_specs = response.data this.service_specs = response.data

View File

@ -69,7 +69,7 @@
</b-button> </b-button>
</h2> </h2>
<div v-show="showResources"> <div v-show="showResources">
<h-domain-service v-for="(svc, idx) in services" :key="idx" :service="svc" /> <h-domain-service v-for="(svc, idx) in services" :key="idx" :origin="origin" :service="svc" :zone-meta="zoneMeta" />
</div> </div>
</div> </div>
</div> </div>
@ -92,9 +92,17 @@ export default {
type: String, type: String,
required: true required: true
}, },
origin: {
type: String,
required: true
},
services: { services: {
type: Array, type: Array,
required: true required: true
},
zoneMeta: {
type: Object,
required: true
} }
}, },

View File

@ -33,12 +33,12 @@
<template> <template>
<div v-if="!isLoading" class="pt-3"> <div v-if="!isLoading" class="pt-3">
<h-subdomain-item v-for="(dn, index) in sortedDomains" :key="index" :dn="dn" :services="myServices.services[dn]===undefined?[]:myServices.services[dn]" :aliases="myServices.aliases[dn]===undefined?[]:myServices.aliases[dn]" /> <h-subdomain-item v-for="(dn, index) in sortedDomains" :key="index" :dn="dn" :origin="domain.domain" :services="myServices.services[dn]===undefined?[]:myServices.services[dn]" :aliases="myServices.aliases[dn]===undefined?[]:myServices.aliases[dn]" :zone-meta="zoneMeta" />
</div> </div>
</template> </template>
<script> <script>
import axios from 'axios' import ZoneApi from '@/services/ZoneApi'
export default { export default {
name: 'HSubdomainList', name: 'HSubdomainList',
@ -67,7 +67,7 @@ export default {
computed: { computed: {
isLoading () { isLoading () {
return this.myServices == null return this.myServices == null && this.zoneMeta === undefined
}, },
sortedDomains () { sortedDomains () {
@ -105,9 +105,7 @@ export default {
}, },
created () { created () {
if (this.domain !== undefined && this.domain.domain !== undefined && this.zoneMeta !== undefined) {
this.pullZone() this.pullZone()
}
}, },
methods: { methods: {
@ -121,8 +119,12 @@ export default {
}, },
pullZone () { pullZone () {
axios if (this.domain === undefined || this.domain.domain === undefined || this.zoneMeta === undefined || this.zoneMeta.id === undefined) {
.get('/api/domains/' + encodeURIComponent(this.domain.domain) + '/zone/' + encodeURIComponent(this.zoneMeta.id)) return
}
ZoneApi
.getZone(this.domain.domain, this.zoneMeta.id)
.then( .then(
(response) => { (response) => {
this.myServices = response.data this.myServices = response.data

View File

@ -0,0 +1,43 @@
// Copyright or © or Copr. happyDNS (2020)
//
// 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.
import Api from '@/services/Api'
export default {
getServiceSpecs (serviceType) {
if (serviceType != null) {
serviceType = serviceType[0] === '*' ? serviceType.substr(1) : serviceType
return Api().get('/api/service_specs/' + serviceType)
} else {
return Api().get('/api/service_specs')
}
}
}

View File

@ -32,11 +32,11 @@
import Api from '@/services/Api' import Api from '@/services/Api'
export default { export default {
getServices () { getServices (domain) {
return Api().get('/api/service_specs') return Api().get('/api/service_specs')
}, },
getServiceSpecs (serviceType) { updateService (service) {
serviceType = serviceType[0] === '*' ? serviceType.substr(1) : serviceType var serviceType = serviceType[0] === '*' ? serviceType.substr(1) : serviceType
return Api().get('/api/service_specs/' + serviceType) return Api().get('/api/service_specs/' + serviceType)
} }
} }

View File

@ -0,0 +1,38 @@
// Copyright or © or Copr. happyDNS (2020)
//
// 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.
import Api from '@/services/Api'
export default {
getZone (domain, id) {
return Api().get('/api/domains/' + encodeURIComponent(domain) + '/zone/' + encodeURIComponent(id))
}
}

View File

@ -32,7 +32,13 @@
--> -->
<template> <template>
<h-subdomain-list v-if="selectedHistory" :domain="domain" :zone-meta="selectedHistory" /> <div>
<div v-if="importInProgress" class="mt-4 text-center">
<b-spinner label="Spinning" />
<p>Please wait while we are importing your domain&nbsp;&hellip;</p>
</div>
<h-subdomain-list v-if="!importInProgress && selectedHistory" :domain="domain" :zone-meta="selectedHistory" />
</div>
</template> </template>
<script> <script>
@ -52,6 +58,7 @@ export default {
data: function () { data: function () {
return { return {
importInProgress: false,
selectedHistory: null selectedHistory: null
} }
}, },
@ -71,12 +78,14 @@ export default {
methods: { methods: {
pullDomain () { pullDomain () {
if (this.domain.zone_history === null || this.domain.zone_history.length === 0) { if (this.domain.zone_history === null || this.domain.zone_history.length === 0) {
this.importInProgress = true
axios axios
.post('/api/domains/' + encodeURIComponent(this.domain.domain) + '/import_zone') .post('/api/domains/' + encodeURIComponent(this.domain.domain) + '/import_zone')
.then( .then(
(response) => { (response) => {
this.importInProgress = false
this.selectedHistory = response.data
this.$parent.$emit('updateDomainInfo') this.$parent.$emit('updateDomainInfo')
// this.selectedHistory = response.data
} }
) )
} else { } else {

View File

@ -86,9 +86,23 @@ export default {
}, },
mounted () { mounted () {
this.updateDomainInfo()
this.$on('updateDomainInfo', this.updateDomainInfo)
},
methods: {
detachDomain () {
axios
.delete('/api/domains/' + encodeURIComponent(this.domain.domain))
.then(response => (
this.$router.push('/domains/')
))
},
updateDomainInfo () {
var mydomain = this.$route.params.domain var mydomain = this.$route.params.domain
axios axios
.get('/api/domains/' + mydomain) .get('/api/domains/' + encodeURIComponent(mydomain))
.then( .then(
response => (this.domain = response.data), response => (this.domain = response.data),
error => { error => {
@ -102,15 +116,6 @@ export default {
) )
this.$router.push('/domains/') this.$router.push('/domains/')
}) })
},
methods: {
detachDomain () {
axios
.delete('/api/domains/' + encodeURIComponent(this.domain.domain))
.then(response => (
this.$router.push('/domains/')
))
} }
} }
} }

View File

@ -32,6 +32,8 @@
package happydns package happydns
import ( import (
"bytes"
"errors"
"time" "time"
) )
@ -50,3 +52,28 @@ type Zone struct {
Aliases map[string][]string `json:"aliases"` Aliases map[string][]string `json:"aliases"`
Services map[string][]*ServiceCombined `json:"services"` Services map[string][]*ServiceCombined `json:"services"`
} }
func (z *Zone) FindService(id []byte) *ServiceCombined {
for _, services := range z.Services {
for _, svc := range services {
if bytes.Equal(svc.Id, id) {
return svc
}
}
}
return nil
}
func (z *Zone) EraseService(domain string, id []byte, s *ServiceCombined) error {
if services, ok := z.Services[domain]; ok {
for k, svc := range services {
if bytes.Equal(svc.Id, id) {
z.Services[domain][k] = s
return nil
}
}
}
return errors.New("Service not found")
}