<!-- - Copyright 2014-2018 the original author or authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. --> <template> <div class="box"> <h1 class="is-size-5">Environment Manager</h1> <datalist id="allPropertyNames"> <option v-for="name in allPropertyNames" :key="name" v-text="name"/> </datalist> <div class="field is-horizontal" v-for="(prop, index) in managedProperties" :key="`managed-${index}`"> <div class="field-body"> <div class="field"> <div class="control"> <input class="input" type="text" placeholder="Property name" list="allPropertyNames" v-model="prop.name" @input="handlePropertyNameChange(prop, index)"> </div> <p class="help is-danger" v-text="prop.validation"/> </div> <div class="field"> <div class="control has-icons-right" :class="{'is-loading' : prop.status === 'executing'}"> <input class="input" type="text" placeholder="Value" v-model="prop.input" @input="prop.status = null"> <span class="icon is-right has-text-success" v-if="prop.status === 'completed'"> <font-awesome-icon icon="check"/> </span> <span class="icon is-right has-text-warning" v-else-if="prop.status === 'failed'"> <font-awesome-icon icon="exclamation-triangle"/> </span> <span class="icon is-right" v-else-if="prop.input !== prop.value"> <font-awesome-icon icon="pencil-alt"/> </span> </div> </div> </div> </div> <div class="field is-horizontal"> <div class="field-body" v-if="instance.hasEndpoint('refresh')"> <div class="field"> <div class="control"> <sba-confirm-button class="button is-light" :class="{'is-loading' : refreshStatus === 'executing', 'is-danger' : refreshStatus === 'failed', 'is-info' : refreshStatus === 'completed'}" :disabled="refreshStatus === 'executing'" @click="refreshContext"> <span v-if="refreshStatus === 'completed'">Context refreshed</span> <span v-else-if="refreshStatus === 'failed'">Failed</span> <span v-else>Refresh Context</span> </sba-confirm-button> </div> </div> </div> <div class="field-body"> <div class="field is-grouped is-grouped-right"> <div class="control"> <button class="button is-light" :class="{'is-loading' : resetStatus === 'executing', 'is-danger' : resetStatus === 'failed', 'is-success' : resetStatus === 'completed'}" :disabled="!hasManagedProperty || resetStatus === 'executing'" @click="resetEnvironment"> <span v-if="resetStatus === 'completed'">Resetted</span> <span v-else-if="resetStatus === 'failed'">Failed</span> <span v-else>Reset</span> </button> </div> <div class="control"> <button class="button is-primary" :class="{'is-loading' : updateStatus === 'executing', 'is-danger' : updateStatus === 'failed', 'is-success' : updateStatus === 'completed'}" :disabled="hasErrorProperty || !hasChangedProperty || updateStatus === 'executing'" @click="updateEnvironment"> <span v-if="updateStatus === 'completed'">Updated</span> <span v-else-if="updateStatus === 'failed'">Failed</span> <span v-else>Update</span> </button> </div> </div> </div> </div> </div> </template> <script> import Instance from '@/services/instance'; import {Observable} from '@/utils/rxjs'; import _ from 'lodash'; export default { props: { instance: { type: Instance, required: true }, propertySources: { type: Array, default: () => [] } }, data: () => ({ error: null, refreshStatus: null, resetStatus: null, updateStatus: null, managedProperties: [{ name: null, input: null, value: null, status: null, validation: null }] }), computed: { allPropertyNames() { return _.uniq(this.propertySources.map(ps => Object.keys(ps.properties)) .reduce((result, names) => result.concat(names)) .sort()); }, managerPropertySource() { return this.propertySources.find(ps => ps.name === 'manager') || {name: 'manager', properties: []}; }, hasManagedProperty() { return this.managedProperties.findIndex(property => !!property.name) >= 0; }, hasChangedProperty() { return this.managedProperties.findIndex(property => property.input !== property.value) >= 0; }, hasErrorProperty() { return this.managedProperties.findIndex(property => property.validation !== null) >= 0; } }, methods: { handlePropertyNameChange: _.debounce(function (prop, idx) { if (prop.name && idx === this.managedProperties.length - 1) { this.managedProperties.push({ name: null, input: null, value: null, status: null, validation: null }); } }, 250), refreshContext() { const vm = this; Observable.from(vm.instance.refreshContext()) .listen(status => vm.refreshStatus = status) .subscribe({ complete: () => { setTimeout(() => vm.refreshStatus = null, 2500); return vm.$emit('reset'); }, error: () => vm.$emit('reset') }); }, updateEnvironment() { const vm = this; Observable.from(vm.managedProperties) .filter(property => !!property.name && property.input !== property.value) .listen(status => vm.updateStatus = status) .concatMap(property => Observable.from(vm.instance.setEnv(property.name, property.input)) .listen(status => property.status = status) ) .subscribe({ complete: () => { setTimeout(() => vm.updateStatus = null, 2500); return vm.$emit('update'); }, error: () => vm.$emit('update') }); }, resetEnvironment() { const vm = this; Observable.from(vm.instance.resetEnv()) .listen(status => vm.resetStatus = status) .subscribe({ complete: () => { vm.managedProperties = [{ name: null, input: null, value: null, status: null, validation: null }]; setTimeout(() => vm.resetStatus = null, 2500); return vm.$emit('refresh'); }, error: () => vm.$emit('refresh') }); }, updateManagedProperties(manager) { _.entries(manager.properties).forEach(([name, property]) => { const managedProperty = this.managedProperties.find(property => property.name === name); if (managedProperty) { managedProperty.value = property.value } else { const idx = this.managedProperties.length - 1; this.managedProperties.splice(idx, 0, { name, input: property.value, value: property.value, status: null, validation: null }) } }); } }, watch: { managerPropertySource: { handler: 'updateManagedProperties', immediate: true }, managedProperties: { deep: true, handler() { const counts = this.managedProperties.reduce( (acc, v) => { if (v.name) { acc[v.name] = (acc[v.name] || 0) + 1; } return acc; }, {}); this.managedProperties.forEach(property => { if (!property.name) { if (property.input) { property.validation = 'Property name is required'; } return; } const count = counts[property.name] || 0; if (count > 1) { property.validation = 'Property name must be unique'; return; } property.validation = null; }); } } } } </script>