Loading src/components/genericComponents/taskProgress.vue +6 −4 Original line number Diff line number Diff line Loading @@ -22,6 +22,11 @@ export default { type: String, required: true }, pollInterval: { type: Number, required: false, default: 500 }, }, data: function () { Loading @@ -34,7 +39,7 @@ export default { created() { this.polling = setInterval(() => { this.pollProgress() }, 500) }, this.pollInterval) }, beforeDestroy () { Loading @@ -44,14 +49,11 @@ export default { methods: { pollProgress: function() { console.log("Starting progress polling") var interval = 500; axios.get(`${this.$store.getters.uri}/task/${this.taskId}`) .then(response => { console.log("PROGRESS RESPONSE: ", response.data.progress) this.progress = response.data.progress }) }, terminateTask: function() { Loading src/components/genericComponents/taskSubmitter.vue 0 → 100644 +282 −0 Original line number Diff line number Diff line <template> <div class="uk-margin-top uk-margin-horizontal-remove uk-padding-remove"> <div v-if="taskRunning" ref="isPollingElement"> <div class="progress"> <div v-if="progress" class="determinate" :style="barWidthFromProgress"></div> <div v-else class="indeterminate"></div> </div> <button type="button" v-on:click="terminateTask()" class="uk-button uk-button-danger uk-form-small uk-float-right uk-width-1-1">Terminate</button> </div> <button type="button" v-on:click="startTask()" v-bind:hidden="taskRunning" class="uk-button uk-button-primary uk-form-small uk-float-right uk-width-1-1">{{ submitLabel }}</button> </div> </template> <script> import axios from 'axios' export default { name: 'taskSubmitter', props: { submitURL: { type: String, required: true }, submitData: { type: Object, required: false, default: {} }, pollInterval: { type: Number, required: false, default: 500 }, submitLabel: { type: String, required: false, default: "Submit" }, }, data: function () { return { taskId: null, polling: null, progress: null, taskRunning: false } }, created() { }, beforeDestroy () { }, methods: { startTask: function() { console.log("Task start clicked") this.$emit('submit', this.submitData) // Send a request to start a task axios.post(this.submitURL, this.submitData) // Get the returned Task ID .then(response => { // Fetch the task ID console.log("Task ID: " + response.data.id) this.taskId = response.data.id // Start the store polling TaskId for success this.taskRunning = true // Return the poll-task promise (starts polling the task) return this.pollTask(this.taskId, null, null) }) .then(response => { // Do something with the final response console.log("Emitting onResponse: ", response) this.$emit('response', response) }) .catch(error => { if (!error) { error = "Unknown error" } console.log("Emitting onError: ", error) this.$emit('error', error) }) .finally(() => { console.log("Cleaning up after task.") // Reset taskRunning and taskId this.taskRunning = false this.taskId = null // Update the form data if we're self-updating if (this.selfUpdate) { this.getFormData() } }) }, pollTask: function(taskId, timeout, interval) { var endTime = Number(new Date()) + (timeout*1000 || 30000); interval = interval*1000 || 500; var checkCondition = (resolve, reject) => { // If the condition is met, we're done! axios.get(`${this.$store.getters.uri}/task/${taskId}`) .then(response => { console.log(response.data.status) var result = response.data.status // If the task ends with success if(result == 'success') { resolve(response.data) } // If task ends with an error else if (result == 'error') { // Pass the error string back with reject reject(new Error(response.data.return)) } // If task ends with termination else if (result == 'terminated') { // Pass a generic termination error back with reject reject(new Error("Task terminated")) } // If task ends in any other way else if (result != 'running') { // Pass status string as error reject(new Error(result)) } // If the condition isn't met but the timeout hasn't elapsed, go again else if (Number(new Date()) < endTime) { // Since the task is still running, we can update the progress bar this.progress = response.data.progress // Check again after timeout setTimeout(checkCondition, interval, resolve, reject) } // Didn't match and too much time, reject! else { reject(new Error('Polling timed out')) } }) }; return new Promise(checkCondition); }, pollProgress: function() { console.log("Starting progress polling") axios.get(`${this.$store.getters.uri}/task/${this.taskId}`) .then(response => { console.log("PROGRESS RESPONSE: ", response.data.progress) this.progress = response.data.progress }) }, terminateTask: function() { axios.delete(`${this.$store.getters.uri}/task/${this.taskId}`) .then(response => { console.log("TERMINATION RESPONSE: ", response.data) }) }, }, computed: { barWidthFromProgress: function () { var progress = ((this.progress <= 100) ? this.progress : 100) var styleString = `width: ${progress}%` return styleString }, } } </script> <style lang="less" scoped> @import "../../assets/less/theme.less"; .progress { position: relative; height: 5px; display: block; width: 100%; background-color: rgba(180, 180, 180, 0.15); border-radius: 2px; background-clip: padding-box; margin: 0.5rem 0 1rem 0; overflow: hidden; } .progress .determinate { position: absolute; background-color: inherit; top: 0; bottom: 0; transition: width .3s linear; } .progress .indeterminate, .progress .determinate { background-color: @global-primary-background; } .hook-inverse() { .progress .indeterminate, .progress .determinate{ background-color: @inverse-primary-muted-color; } } .progress .indeterminate:before { content: ''; position: absolute; background-color: inherit; top: 0; left: 0; bottom: 0; will-change: left, right; -webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; } .progress .indeterminate:after { content: ''; position: absolute; background-color: inherit; top: 0; left: 0; bottom: 0; will-change: left, right; -webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite; animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite; -webkit-animation-delay: 1.15s; animation-delay: 1.15s; } @-webkit-keyframes indeterminate { 0% { left: -35%; right: 100%; } 60% { left: 100%; right: -90%; } 100% { left: 100%; right: -90%; } } @keyframes indeterminate { 0% { left: -35%; right: 100%; } 60% { left: 100%; right: -90%; } 100% { left: 100%; right: -90%; } } @-webkit-keyframes indeterminate-short { 0% { left: -200%; right: 100%; } 60% { left: 107%; right: -8%; } 100% { left: 107%; right: -8%; } } @keyframes indeterminate-short { 0% { left: -200%; right: 100%; } 60% { left: 107%; right: -8%; } 100% { left: 107%; right: -8%; } } </style> No newline at end of file src/components/pluginComponents/JsonForm.vue +27 −51 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ <a href="#" v-if="selfUpdate" v-on:click="getFormData()" class="uk-icon uk-width-auto"><i class="material-icons">cached</i></a> </div> <form @submit.prevent="submitForm" class="uk-form-stacked"> <form @submit.prevent="" class="uk-form-stacked" ref="formContainer"> <div v-for="(field, index) in schema" :key="index"> <div v-if="Array.isArray(field)" class="uk-grid-small uk-width-1-1 uk-child-width-expand" uk-grid> Loading @@ -26,11 +26,16 @@ </component> </div> <div v-if="taskRunning"> <taskProgress v-bind:taskId="taskId"></taskProgress> </div> <taskSubmitter v-if="isTask" v-bind:submitURL="submitApiUri" v-bind:submitData="formData" v-bind:submitLabel="submitLabel" v-on:submit="onTaskSubmit" v-on:response="onTaskResponse" v-on:error="onTaskError"> </taskSubmitter> <button type="submit" v-bind:hidden="taskRunning" class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin-small uk-width-1-1">{{ submitLabel }}</button> <button v-else type="button" v-on:click="newQuickRequest(formData);" class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin-small uk-width-1-1">{{ submitLabel }}</button> </form> Loading @@ -50,8 +55,7 @@ import checkList from "../fieldComponents/checkList" import tagList from "../fieldComponents/tagList" import keyvalList from "../fieldComponents/keyvalList" import progressBar from "../genericComponents/progressBar" import taskProgress from "../genericComponents/taskProgress" import taskSubmitter from "../genericComponents/taskSubmitter" export default { name: 'JsonForm', Loading @@ -65,8 +69,7 @@ export default { checkList, tagList, keyvalList, progressBar, taskProgress taskSubmitter }, props: { Loading Loading @@ -102,9 +105,7 @@ export default { data: function () { return { formData: {}, taskRunning: false, taskId: null formData: {} } }, Loading Loading @@ -145,15 +146,6 @@ export default { this.$emit('input', this.formData) }, submitForm() { if (this.isTask == true) { this.newLongRequest(this.formData) } else { this.newQuickRequest(this.formData) } }, getFormData: function() { // Send a quick request axios.get(this.submitApiUri) Loading Loading @@ -184,38 +176,22 @@ export default { }) }, newLongRequest: function(params) { axios.post(this.submitApiUri, params) .then(response => { // Fetch the task ID console.log("Task ID: " + response.data.id) this.taskId = response.data.id // Start the store polling TaskId for success this.taskRunning = true return this.$store.dispatch('pollTask', [this.taskId, null, null]) }) .then(response => { // Do something with the response console.log(response) }) .catch(error => { console.log("Task eneded with error: ", error) if (error) { this.modalError(error) // Display the error, if one exists } }) .finally(() => { console.log("Cleaning up after task.") // Reset taskRunning and taskId this.taskRunning = false this.taskId = null // Update the form data if we're self-updating onTaskSubmit: function(submitData) { // We don't need to do anything on this event yet console.log("onTaskSubmit event triggered") }, onTaskResponse: function(responseData) { console.log("Task finished with response data: ", responseData) if (this.selfUpdate) { this.getFormData() } }) }, onTaskError: function(error) { this.modalError(error) } }, computed: { Loading Loading
src/components/genericComponents/taskProgress.vue +6 −4 Original line number Diff line number Diff line Loading @@ -22,6 +22,11 @@ export default { type: String, required: true }, pollInterval: { type: Number, required: false, default: 500 }, }, data: function () { Loading @@ -34,7 +39,7 @@ export default { created() { this.polling = setInterval(() => { this.pollProgress() }, 500) }, this.pollInterval) }, beforeDestroy () { Loading @@ -44,14 +49,11 @@ export default { methods: { pollProgress: function() { console.log("Starting progress polling") var interval = 500; axios.get(`${this.$store.getters.uri}/task/${this.taskId}`) .then(response => { console.log("PROGRESS RESPONSE: ", response.data.progress) this.progress = response.data.progress }) }, terminateTask: function() { Loading
src/components/genericComponents/taskSubmitter.vue 0 → 100644 +282 −0 Original line number Diff line number Diff line <template> <div class="uk-margin-top uk-margin-horizontal-remove uk-padding-remove"> <div v-if="taskRunning" ref="isPollingElement"> <div class="progress"> <div v-if="progress" class="determinate" :style="barWidthFromProgress"></div> <div v-else class="indeterminate"></div> </div> <button type="button" v-on:click="terminateTask()" class="uk-button uk-button-danger uk-form-small uk-float-right uk-width-1-1">Terminate</button> </div> <button type="button" v-on:click="startTask()" v-bind:hidden="taskRunning" class="uk-button uk-button-primary uk-form-small uk-float-right uk-width-1-1">{{ submitLabel }}</button> </div> </template> <script> import axios from 'axios' export default { name: 'taskSubmitter', props: { submitURL: { type: String, required: true }, submitData: { type: Object, required: false, default: {} }, pollInterval: { type: Number, required: false, default: 500 }, submitLabel: { type: String, required: false, default: "Submit" }, }, data: function () { return { taskId: null, polling: null, progress: null, taskRunning: false } }, created() { }, beforeDestroy () { }, methods: { startTask: function() { console.log("Task start clicked") this.$emit('submit', this.submitData) // Send a request to start a task axios.post(this.submitURL, this.submitData) // Get the returned Task ID .then(response => { // Fetch the task ID console.log("Task ID: " + response.data.id) this.taskId = response.data.id // Start the store polling TaskId for success this.taskRunning = true // Return the poll-task promise (starts polling the task) return this.pollTask(this.taskId, null, null) }) .then(response => { // Do something with the final response console.log("Emitting onResponse: ", response) this.$emit('response', response) }) .catch(error => { if (!error) { error = "Unknown error" } console.log("Emitting onError: ", error) this.$emit('error', error) }) .finally(() => { console.log("Cleaning up after task.") // Reset taskRunning and taskId this.taskRunning = false this.taskId = null // Update the form data if we're self-updating if (this.selfUpdate) { this.getFormData() } }) }, pollTask: function(taskId, timeout, interval) { var endTime = Number(new Date()) + (timeout*1000 || 30000); interval = interval*1000 || 500; var checkCondition = (resolve, reject) => { // If the condition is met, we're done! axios.get(`${this.$store.getters.uri}/task/${taskId}`) .then(response => { console.log(response.data.status) var result = response.data.status // If the task ends with success if(result == 'success') { resolve(response.data) } // If task ends with an error else if (result == 'error') { // Pass the error string back with reject reject(new Error(response.data.return)) } // If task ends with termination else if (result == 'terminated') { // Pass a generic termination error back with reject reject(new Error("Task terminated")) } // If task ends in any other way else if (result != 'running') { // Pass status string as error reject(new Error(result)) } // If the condition isn't met but the timeout hasn't elapsed, go again else if (Number(new Date()) < endTime) { // Since the task is still running, we can update the progress bar this.progress = response.data.progress // Check again after timeout setTimeout(checkCondition, interval, resolve, reject) } // Didn't match and too much time, reject! else { reject(new Error('Polling timed out')) } }) }; return new Promise(checkCondition); }, pollProgress: function() { console.log("Starting progress polling") axios.get(`${this.$store.getters.uri}/task/${this.taskId}`) .then(response => { console.log("PROGRESS RESPONSE: ", response.data.progress) this.progress = response.data.progress }) }, terminateTask: function() { axios.delete(`${this.$store.getters.uri}/task/${this.taskId}`) .then(response => { console.log("TERMINATION RESPONSE: ", response.data) }) }, }, computed: { barWidthFromProgress: function () { var progress = ((this.progress <= 100) ? this.progress : 100) var styleString = `width: ${progress}%` return styleString }, } } </script> <style lang="less" scoped> @import "../../assets/less/theme.less"; .progress { position: relative; height: 5px; display: block; width: 100%; background-color: rgba(180, 180, 180, 0.15); border-radius: 2px; background-clip: padding-box; margin: 0.5rem 0 1rem 0; overflow: hidden; } .progress .determinate { position: absolute; background-color: inherit; top: 0; bottom: 0; transition: width .3s linear; } .progress .indeterminate, .progress .determinate { background-color: @global-primary-background; } .hook-inverse() { .progress .indeterminate, .progress .determinate{ background-color: @inverse-primary-muted-color; } } .progress .indeterminate:before { content: ''; position: absolute; background-color: inherit; top: 0; left: 0; bottom: 0; will-change: left, right; -webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; } .progress .indeterminate:after { content: ''; position: absolute; background-color: inherit; top: 0; left: 0; bottom: 0; will-change: left, right; -webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite; animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite; -webkit-animation-delay: 1.15s; animation-delay: 1.15s; } @-webkit-keyframes indeterminate { 0% { left: -35%; right: 100%; } 60% { left: 100%; right: -90%; } 100% { left: 100%; right: -90%; } } @keyframes indeterminate { 0% { left: -35%; right: 100%; } 60% { left: 100%; right: -90%; } 100% { left: 100%; right: -90%; } } @-webkit-keyframes indeterminate-short { 0% { left: -200%; right: 100%; } 60% { left: 107%; right: -8%; } 100% { left: 107%; right: -8%; } } @keyframes indeterminate-short { 0% { left: -200%; right: 100%; } 60% { left: 107%; right: -8%; } 100% { left: 107%; right: -8%; } } </style> No newline at end of file
src/components/pluginComponents/JsonForm.vue +27 −51 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ <a href="#" v-if="selfUpdate" v-on:click="getFormData()" class="uk-icon uk-width-auto"><i class="material-icons">cached</i></a> </div> <form @submit.prevent="submitForm" class="uk-form-stacked"> <form @submit.prevent="" class="uk-form-stacked" ref="formContainer"> <div v-for="(field, index) in schema" :key="index"> <div v-if="Array.isArray(field)" class="uk-grid-small uk-width-1-1 uk-child-width-expand" uk-grid> Loading @@ -26,11 +26,16 @@ </component> </div> <div v-if="taskRunning"> <taskProgress v-bind:taskId="taskId"></taskProgress> </div> <taskSubmitter v-if="isTask" v-bind:submitURL="submitApiUri" v-bind:submitData="formData" v-bind:submitLabel="submitLabel" v-on:submit="onTaskSubmit" v-on:response="onTaskResponse" v-on:error="onTaskError"> </taskSubmitter> <button type="submit" v-bind:hidden="taskRunning" class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin-small uk-width-1-1">{{ submitLabel }}</button> <button v-else type="button" v-on:click="newQuickRequest(formData);" class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin-small uk-width-1-1">{{ submitLabel }}</button> </form> Loading @@ -50,8 +55,7 @@ import checkList from "../fieldComponents/checkList" import tagList from "../fieldComponents/tagList" import keyvalList from "../fieldComponents/keyvalList" import progressBar from "../genericComponents/progressBar" import taskProgress from "../genericComponents/taskProgress" import taskSubmitter from "../genericComponents/taskSubmitter" export default { name: 'JsonForm', Loading @@ -65,8 +69,7 @@ export default { checkList, tagList, keyvalList, progressBar, taskProgress taskSubmitter }, props: { Loading Loading @@ -102,9 +105,7 @@ export default { data: function () { return { formData: {}, taskRunning: false, taskId: null formData: {} } }, Loading Loading @@ -145,15 +146,6 @@ export default { this.$emit('input', this.formData) }, submitForm() { if (this.isTask == true) { this.newLongRequest(this.formData) } else { this.newQuickRequest(this.formData) } }, getFormData: function() { // Send a quick request axios.get(this.submitApiUri) Loading Loading @@ -184,38 +176,22 @@ export default { }) }, newLongRequest: function(params) { axios.post(this.submitApiUri, params) .then(response => { // Fetch the task ID console.log("Task ID: " + response.data.id) this.taskId = response.data.id // Start the store polling TaskId for success this.taskRunning = true return this.$store.dispatch('pollTask', [this.taskId, null, null]) }) .then(response => { // Do something with the response console.log(response) }) .catch(error => { console.log("Task eneded with error: ", error) if (error) { this.modalError(error) // Display the error, if one exists } }) .finally(() => { console.log("Cleaning up after task.") // Reset taskRunning and taskId this.taskRunning = false this.taskId = null // Update the form data if we're self-updating onTaskSubmit: function(submitData) { // We don't need to do anything on this event yet console.log("onTaskSubmit event triggered") }, onTaskResponse: function(responseData) { console.log("Task finished with response data: ", responseData) if (this.selfUpdate) { this.getFormData() } }) }, onTaskError: function(error) { this.modalError(error) } }, computed: { Loading