Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui): refactor add remove dialog #475

Merged
merged 17 commits into from
Feb 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 4 additions & 114 deletions src/components/ControlPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,9 @@

<DialogAddRemove
v-model="addRemoveShowDialog"
:status="addRemoveStatus"
:alert="addRemoveAlert"
:nodeAddedOrRemoved="addRemoveNode"
@close="onAddRemoveClose"
@action="onAddRemoveAction"
@apiRequest="apiRequest"
/>

<nodes-table
Expand Down Expand Up @@ -104,66 +103,12 @@ export default {
return this.appInfo.controllerStatus
}
},
watch: {
addRemoveEndDate (newVal) {
if (this.addRemoveTimer) {
clearInterval(this.addRemoveTimer)
}
this.addRemoveTimer = setInterval(() => {
const now = new Date()
const s = Math.trunc((this.addRemoveEndDate - now) / 1000)
if (this.addRemoveStatus === 'start') {
this.addRemoveAlert = {
type: 'info',
text: `${this.addRemoveAction} started: ${s}s remaining`
}
}
if (now > newVal) clearInterval(this.addRemoveTimer)
}, 100)
},
controllerStatus (status) {
if (status.indexOf('clusion') > 0) {
if (this.addRemoveAction === null) return // ignore initial status

// inclusion/exclusion started, start the countdown timer
if (status.indexOf('started') > 0) {
this.addRemoveEndDate = new Date(
new Date().getTime() + this.timeoutMs
)
this.addRemoveNode = null
this.addRemoveStatus = 'start'
} else if (status.indexOf('stopped') > 0) {
// inclusion/exclusion stopped, check what happened
this.addRemoveEndDate = new Date()
this.addRemoveAlert = {
type: 'info',
text: `${this.addRemoveAction} stopped, checking nodes…`
}
this.addRemoveStatus = 'wait'
this.waitTimeout = setTimeout(this.showResults, 5000) // add additional discovery time
} else {
// error
this.addRemoveEndDate = new Date()
this.addRemoveAlert = {
type: 'error',
text: status // TODO: better formatting?
}
this.addRemoveStatus = 'stop'
}
}
}
},
watch: {},
data () {
return {
settings: new Settings(localStorage),
bindedSocketEvents: {}, // keep track of the events-handlers
addRemoveShowDialog: false,
addRemoveAction: null,
addRemoveStatus: 'stop',
waitTimeout: null,
addRemoveAlert: null,
addRemoveEndDate: new Date(),
addRemoveTimer: null,
addRemoveNode: null,
node_actions: [
{
Expand Down Expand Up @@ -268,52 +213,8 @@ export default {
},
onAddRemoveClose () {
this.addRemoveShowDialog = false
this.addRemoveAlert = null
},
async onAddRemoveAction (action) {
this.addRemoveStatus = 'wait' // make sure user can't trigger another action too soon
this.addRemoveAction = action.name // Inclusion/Secure inclusion/Exclusion
this.addRemoveEndDate = new Date()
this.addRemoveAlert = {
type: 'info',
text: `${action.name} ${
action.method === 'start' ? 'starting…' : 'stopping…'
}`
}
const args = []
if (action.secure && action.id < 2 && action.method === 'start') {
args.push(action.secure)
}
this.apiRequest(action.method + action.baseAction, args)
this.addRemoveNode = null
},
showResults () {
if (this.waitTimeout) {
clearTimeout(this.waitTimeout)
this.waitTimeout = null
}

this.addRemoveAlert = null

if (this.addRemoveNode == null) {
this.addRemoveAlert = {
type: 'warning',
text: `${this.addRemoveAction} stopped, none found`
}
} else if (this.addRemoveAction === 'Exclusion') {
this.addRemoveAlert = {
type: 'success',
text: `Node ${this.addRemoveNode.id} removed`
}
} else {
this.addRemoveAlert = {
type: 'success',
text: `Device found! Node ${this.addRemoveNode.id} added` // we don't know yet if it's added securely or not, need to wait interview
}
}

this.addRemoveStatus = 'stop'
},

async sendCntAction () {
if (this.cnt_action) {
const args = []
Expand Down Expand Up @@ -445,10 +346,6 @@ export default {
},
onNodeAddedRemoved (node) {
this.addRemoveNode = node
// the add/remove dialog is waiting for a feedback
if (this.waitTimeout) {
this.showResults()
}
},
bindEvent (eventName, handler) {
this.socket.on(socketEvents[eventName], handler)
Expand All @@ -472,13 +369,6 @@ export default {
if (this.socket) {
this.unbindEvents()
}
if (this.addRemoveTimer) {
clearInterval(this.addRemoveTimer)
}

if (this.waitTimeout) {
clearTimeout(this.waitTimeout)
}
}
}
</script>
171 changes: 144 additions & 27 deletions src/components/dialogs/DialogAddRemove.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

<v-card-text style="padding-bottom:0">
<v-container fluid style="margin-top:-2rem">
<v-radio-group v-model="mode" mandatory>
<v-radio value="0">
<v-radio-group v-model="selectedMode" mandatory>
<v-radio :value="0">
<template v-slot:label>
<div class="option">
<v-icon color="green accent-4" small>add_circle</v-icon>
Expand All @@ -19,7 +19,7 @@
</div>
</template>
</v-radio>
<v-radio value="1">
<v-radio :value="1">
<template v-slot:label>
<div class="option">
<v-icon color="amber accent-4" small
Expand All @@ -30,7 +30,7 @@
</div>
</template>
</v-radio>
<v-radio value="2">
<v-radio :value="2">
<template v-slot:label>
<div class="option">
<v-icon color="red accent-4" small>remove_circle</v-icon>
Expand All @@ -50,17 +50,17 @@
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
v-if="status === 'stop'"
v-if="state === 'stop' || state === 'new'"
color="red darken-1"
text
@click="$emit('close')"
>Close</v-btn
>
<v-btn
v-if="status !== 'wait'"
v-if="state !== 'wait'"
color="blue darken-1"
text
@click="$emit('action', action)"
@click="onAction"
>{{ method }}</v-btn
>
</v-card-actions>
Expand All @@ -69,51 +69,168 @@
</template>

<script>
import { mapGetters } from 'vuex'

export default {
components: {},
props: {
value: Boolean, // show or hide
status: String,
alert: Object
},
watch: {},
computed: {
method () {
return this.status === 'stop' ? 'start' : 'stop'
},
action () {
return {
...this.modes[this.mode],
method: this.method
}
}
nodeAddedOrRemoved: Object
},
data () {
return {
selectedMode: 0,
mode: 0, // most common action should be default
modes: [
{
id: 0,
baseAction: 'Inclusion',
name: 'Inclusion',
secure: false
},
{
id: 1,
baseAction: 'Inclusion',
name: 'Secure inclusion',
secure: true
},
{
id: 2,
baseAction: 'Exclusion',
name: 'Exclusion',
secure: false
}
]
],
state: 'new', // new -> wait -> start -> wait -> stop
commandEndDate: new Date(),
commandTimer: null,
waitTimeout: null,
alert: null,
nodeFound: null
}
},
computed: {
...mapGetters(['appInfo', 'zwave']),
method () {
return this.state === 'new' || this.state === 'stop' ? 'start' : 'stop'
},
timeoutMs () {
return this.zwave.commandsTimeout * 1000 + 800 // add small buffer
},
controllerStatus () {
return this.appInfo.controllerStatus
},
modeName () {
return this.modes[this.mode].name
}
},
watch: {
nodeAddedOrRemoved (node) {
this.nodeFound = node

// the add/remove dialog is waiting for a feedback
if (this.waitTimeout) {
this.showResults()
}
},
commandEndDate (newVal) {
if (this.commandTimer) {
clearInterval(this.commandTimer)
}
this.commandTimer = setInterval(() => {
const now = new Date()
const s = Math.trunc((this.commandEndDate - now) / 1000)
if (this.state === 'start') {
this.alert = {
type: 'info',
text: `${this.modeName} started: ${s}s remaining`
}
}
if (now > newVal) clearInterval(this.commandTimer)
}, 100)
},
controllerStatus (status) {
if (status.indexOf('clusion') > 0) {
if (this.state === 'new') return // ignore initial status

// inclusion/exclusion started, start the countdown timer
if (status.indexOf('started') > 0) {
this.commandEndDate = new Date(new Date().getTime() + this.timeoutMs)
this.nodeFound = null
this.state = 'start'
} else if (status.indexOf('stopped') > 0) {
// inclusion/exclusion stopped, check what happened
this.commandEndDate = new Date()
this.alert = {
type: 'info',
text: `${this.modeName} stopped, checking nodes…`
}
this.state = 'wait'
this.waitTimeout = setTimeout(this.showResults, 5000) // add additional discovery time
} else {
// error
this.commandEndDate = new Date()
this.alert = {
type: 'error',
text: status // TODO: better formatting?
}
this.state = 'stop'
}
}
}
},
methods: {
onAction () {
this.mode = this.selectedMode
this.commandEndDate = new Date()
this.alert = {
type: 'info',
text: `${this.modeName} ${
this.method === 'start' ? 'starting…' : 'stopping…'
}`
}
const args = []
if (this.mode < 2 && this.method === 'start') {
args.push(this.modes[this.mode].secure)
}
this.$emit(
'apiRequest',
this.method + this.modes[this.mode].baseAction,
args
)
this.state = 'wait' // make sure user can't trigger another action too soon
},
showResults () {
if (this.waitTimeout) {
clearTimeout(this.waitTimeout)
this.waitTimeout = null
}

if (this.nodeFound === null) {
this.alert = {
type: 'warning',
text: `${this.modeName} stopped, no changes detected`
}
} else if (this.mode === 2) {
this.alert = {
type: 'success',
text: `Node ${this.nodeFound.id} removed`
}
} else {
this.alert = {
type: 'success',
text: `Device found! Node ${this.nodeFound.id} added` // we don't know yet if it's added securely or not, need to wait interview
}
}

this.state = 'stop'
}
},
methods: {}
beforeDestroy () {
if (this.commandTimer) {
clearInterval(this.commandTimer)
}

if (this.waitTimeout) {
clearTimeout(this.waitTimeout)
}
}
}
</script>

Expand Down