Improve thing addition and add-ons management
Shortcut to install new bindings when adding a thing Inbox listens to SSE and refreshes automatically Refresh constantly the discovery results when scanning Fix search in manual thing type selection Improve look & feel of add-on screens and sheet Signed-off-by: Yannick Schaus <github@schaus.net>pull/188/head
parent
2a03c40f9e
commit
0ab0a0b691
|
@ -1,36 +1,14 @@
|
|||
<template>
|
||||
<f7-sheet class="demo-sheet-swipe-to-step" :opened="opened" @sheet:closed="$emit('closed')" swipe-to-close swipe-to-step backdrop
|
||||
style="height:auto; --f7-sheet-bg-color: #fff;">
|
||||
<f7-sheet ref="sheet" class="demo-sheet-swipe-to-step" @sheet:closed="$emit('closed')" swipe-to-close swipe-to-step backdrop>
|
||||
<div class="sheet-modal-swipe-step">
|
||||
|
||||
<div class="swipe-handler"></div>
|
||||
<div class="swipe-handler" @click="toggleSwipeStep"></div>
|
||||
<f7-block-title><strong><big>{{addon.label}}</big></strong></f7-block-title>
|
||||
<f7-block>
|
||||
<f7-row>
|
||||
<f7-col class="col-100 tablet-50">
|
||||
<f7-button
|
||||
outline
|
||||
color="blue"
|
||||
:href="addon.link"
|
||||
external
|
||||
target="_blank"
|
||||
>Documentation</f7-button>
|
||||
</f7-col>
|
||||
<f7-col class="col-100 tablet-50">
|
||||
<f7-button
|
||||
outline
|
||||
fill
|
||||
color="blue"
|
||||
v-if="state === 'UNINSTALLED'"
|
||||
@click="install()"
|
||||
>Install</f7-button>
|
||||
<f7-button
|
||||
outline
|
||||
fill
|
||||
color="red"
|
||||
v-if="state === 'INSTALLED'"
|
||||
@click="uninstall()"
|
||||
>Uninstall</f7-button>
|
||||
<f7-col class="col-100 margin-top padding-horizontal">
|
||||
<f7-button large fill color="blue" v-if="state === 'UNINSTALLED'" @click="install()" >Install</f7-button>
|
||||
<f7-button large fill color="red" v-if="state !== 'UNINSTALLED'" @click="uninstall()" >Uninstall</f7-button>
|
||||
</f7-col>
|
||||
</f7-row>
|
||||
</f7-block>
|
||||
|
@ -40,27 +18,30 @@
|
|||
</div>
|
||||
<f7-page-content>
|
||||
<f7-block>
|
||||
<p>
|
||||
<strong>Version: {{addon.version}}</strong>
|
||||
</p>
|
||||
<f7-list>
|
||||
<f7-list-item title="Version" :after="addon.version"></f7-list-item>
|
||||
<f7-list-button v-if="addon.link" color="blue" external target="_blank" :href="addon.link" title="Documentation"></f7-list-button>
|
||||
</f7-list>
|
||||
</f7-block>
|
||||
<f7-block v-if="bindingInfo.description">
|
||||
<p>
|
||||
<strong>Author: {{bindingInfo.author}}</strong>
|
||||
</p>
|
||||
<div v-html="bindingInfo.description"/>
|
||||
<p>
|
||||
<em>Author: {{bindingInfo.author}}</em>
|
||||
</p>
|
||||
</f7-block>
|
||||
<f7-block v-if="!bindingInfo.description">
|
||||
<!-- <f7-block v-else>
|
||||
<p>No description available.</p>
|
||||
</f7-block>
|
||||
</f7-block> -->
|
||||
</f7-page-content>
|
||||
</f7-sheet>
|
||||
</template>
|
||||
|
||||
<style lang="stylus">
|
||||
.demo-sheet-swipe-to-step
|
||||
height auto
|
||||
|
||||
.demo-sheet-swipe-to-close,
|
||||
.demo-sheet-swipe-to-step {
|
||||
--f7-sheet-bg-color: #fff;
|
||||
--f7-sheet-border-color: transparent;
|
||||
border-radius: 15px 15px 0 0;
|
||||
overflow: hidden;
|
||||
|
@ -71,7 +52,6 @@
|
|||
left: 0;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
}
|
||||
|
@ -90,15 +70,15 @@
|
|||
|
||||
@media (min-width: 1024px)
|
||||
.demo-sheet-swipe-to-close, .demo-sheet-swipe-to-step
|
||||
margin-left 150px
|
||||
margin-right 150px
|
||||
width: calc(100% - 300px)
|
||||
margin-left 15%
|
||||
margin-right 15%
|
||||
width calc(100% - 30%)
|
||||
|
||||
@media (min-width: 1280px)
|
||||
.demo-sheet-swipe-to-close, .demo-sheet-swipe-to-step
|
||||
margin-left 250px
|
||||
margin-right 250px
|
||||
width: calc(100% - 500px)
|
||||
margin-left 30%
|
||||
margin-right 30%
|
||||
width: calc(100% - 60%)
|
||||
|
||||
</style>
|
||||
|
||||
|
@ -112,23 +92,38 @@ export default {
|
|||
}
|
||||
},
|
||||
watch: {
|
||||
addonId () {
|
||||
if (!this.addonId) {
|
||||
this.addon = {}
|
||||
this.bindingInfo = {}
|
||||
return
|
||||
}
|
||||
this.$oh.api.get('/rest/extensions/' + this.addonId).then(data => {
|
||||
this.addon = data
|
||||
|
||||
if (this.addon.type === 'binding' && this.addon.installed) {
|
||||
this.$oh.api.get('/rest/bindings').then(data2 => {
|
||||
this.bindingInfo = data2.find(b => b.id === this.addonId.replace('binding-', '')) || {}
|
||||
|
||||
// TODO: binding configuration stuff
|
||||
})
|
||||
opened (state) {
|
||||
let self = this
|
||||
if (state) {
|
||||
if (!this.addonId) {
|
||||
this.addon = {}
|
||||
this.bindingInfo = {}
|
||||
return
|
||||
}
|
||||
})
|
||||
self.$f7.preloader.show()
|
||||
this.$oh.api.get('/rest/extensions/' + this.addonId).then(data => {
|
||||
this.addon = data
|
||||
|
||||
if (this.addon.type === 'binding' && this.addon.installed) {
|
||||
this.$oh.api.get('/rest/bindings').then(data2 => {
|
||||
this.bindingInfo = data2.find(b => b.id === this.addonId.replace('binding-', '')) || {}
|
||||
self.$f7.preloader.hide()
|
||||
setTimeout(() => {
|
||||
self.$refs.sheet.f7Sheet.setSwipeStep()
|
||||
self.$refs.sheet.f7Sheet.open()
|
||||
})
|
||||
|
||||
// TODO: binding configuration stuff
|
||||
})
|
||||
} else {
|
||||
self.$f7.preloader.hide()
|
||||
self.$refs.sheet.f7Sheet.setSwipeStep()
|
||||
self.$refs.sheet.f7Sheet.open()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
self.$refs.sheet.f7Sheet.close()
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -139,6 +134,10 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
toggleSwipeStep () {
|
||||
const self = this
|
||||
self.$f7.sheet.stepToggle('.demo-sheet-swipe-to-step')
|
||||
},
|
||||
install () {
|
||||
this.$oh.api.post('/rest/extensions/' + this.addonId + '/install', {}, 'text').then((data) => {
|
||||
this.$emit('install', this.addon)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<f7-page @page:afterin="onPageAfterIn" @page:beforeout="stopEventSource">
|
||||
<f7-navbar :title="'Add ' + addonType + ' add-on'" back-link="Back">
|
||||
<f7-navbar :title="'Add ' + addonType + ' add-ons'" back-link="Back">
|
||||
<f7-subnavbar :inner="false">
|
||||
<f7-searchbar search-container=".search-list" search-in=".item-title" remove-diacritics :disable-button="!$theme.aurora"></f7-searchbar>
|
||||
</f7-subnavbar>
|
||||
|
@ -10,10 +10,21 @@
|
|||
</f7-list>
|
||||
<f7-block class="block-narrow">
|
||||
<f7-col>
|
||||
<f7-block-title
|
||||
v-if="addons.length"
|
||||
>{{addons.length}} Addon{{addons.length > 1 ? 's' : ''}} available</f7-block-title>
|
||||
<f7-list media-list class="search-list searchbar-found">
|
||||
<f7-block-title v-if="!ready">Loading...</f7-block-title>
|
||||
<f7-block-title v-else>{{addons.length}} add-on{{addons.length > 1 ? 's' : ''}} available</f7-block-title>
|
||||
<f7-list media-list v-if="!ready">
|
||||
<f7-list-item
|
||||
v-for="n in 10"
|
||||
:key="n"
|
||||
:class="`skeleton-text skeleton-effect-blink`"
|
||||
title="Label of the binding"
|
||||
header="BindingID"
|
||||
footer="Binding version"
|
||||
media-item
|
||||
>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
<f7-list v-else media-list class="search-list searchbar-found">
|
||||
<f7-list-item
|
||||
media-item
|
||||
v-for="addon in addons"
|
||||
|
@ -25,16 +36,10 @@
|
|||
:after="(currentlyInstalling.indexOf(addon.id) >= 0) ? 'Installing...' : ''"
|
||||
:title="addon.label"
|
||||
>
|
||||
<!-- <f7-icon slot="media" icon="demo-list-icon"></f7-icon> -->
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</f7-col>
|
||||
</f7-block>
|
||||
<!-- <addon-details-popup
|
||||
:addon-id="currentAddonId"
|
||||
:opened="addonPopupOpened"
|
||||
@closed="addonPopupOpened = false"
|
||||
/> -->
|
||||
<addon-details-sheet
|
||||
:addon-id="currentAddonId"
|
||||
:opened="addonPopupOpened"
|
||||
|
@ -45,12 +50,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
// import AddonDetailsPopup from './addon-details-popup.vue'
|
||||
import AddonDetailsSheet from './addon-details-sheet.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
// AddonDetailsPopup,
|
||||
AddonDetailsSheet
|
||||
},
|
||||
props: ['addonType'],
|
||||
|
@ -58,6 +61,7 @@ export default {
|
|||
return {
|
||||
addons: [],
|
||||
currentAddonId: null,
|
||||
ready: false,
|
||||
addonPopupOpened: false,
|
||||
currentlyInstalling: []
|
||||
}
|
||||
|
@ -74,6 +78,7 @@ export default {
|
|||
load () {
|
||||
this.$oh.api.get('/rest/extensions').then(data => {
|
||||
this.addons = data.filter(addon => !addon.installed && addon.type === this.addonType)
|
||||
this.ready = true
|
||||
this.startEventSource()
|
||||
}).catch((err) => {
|
||||
// sometimes we get 502 errors ('Jersey is not ready yet!'), keep trying
|
||||
|
@ -95,6 +100,15 @@ export default {
|
|||
this.stopEventSource()
|
||||
this.load()
|
||||
break
|
||||
case 'failed':
|
||||
this.$f7.toast.create({
|
||||
text: `Installation of addon ${topicParts[2]} failed`,
|
||||
closeButton: true,
|
||||
destroyOnClose: true
|
||||
}).open()
|
||||
this.stopEventSource()
|
||||
this.load()
|
||||
break
|
||||
}
|
||||
}, () => {
|
||||
// in case of error, maybe the SSE connection was closed by the add-ons change itself - try reloading to refresh
|
||||
|
|
|
@ -5,10 +5,23 @@
|
|||
<f7-link href="add">Add</f7-link>
|
||||
</f7-nav-right>-->
|
||||
</f7-navbar>
|
||||
<f7-block form v-if="addons.length" class="service-config block-narrow">
|
||||
<f7-block form class="service-config block-narrow">
|
||||
<f7-col>
|
||||
<f7-block-title>{{addons.length}} Add-on{{addons.length > 1 ? 's' : ''}} installed</f7-block-title>
|
||||
<f7-list media-list>
|
||||
<f7-block-title v-if="!ready">Loading...</f7-block-title>
|
||||
<f7-block-title v-else-if="addons.length">{{addons.length}} add-on{{addons.length > 1 ? 's' : ''}} installed</f7-block-title>
|
||||
<f7-list media-list v-if="!ready">
|
||||
<f7-list-item
|
||||
v-for="n in 10"
|
||||
:key="n"
|
||||
:class="`skeleton-text skeleton-effect-blink`"
|
||||
title="Label of the binding"
|
||||
header="BindingID"
|
||||
footer="Binding version"
|
||||
media-item
|
||||
>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
<f7-list v-else>
|
||||
<f7-list-item
|
||||
media-item
|
||||
link="#"
|
||||
|
@ -30,7 +43,7 @@
|
|||
</f7-list>
|
||||
</f7-col>
|
||||
</f7-block>
|
||||
<f7-block form v-if="!addons.length" class="service-config block-narrow">
|
||||
<f7-block form v-if="ready && !addons.length" class="service-config block-narrow">
|
||||
<f7-col>
|
||||
<f7-block strong>
|
||||
<p>No add-ons of type {{addonType}} installed yet. Click the + button to add one!</p>
|
||||
|
@ -67,6 +80,7 @@ export default {
|
|||
data () {
|
||||
return {
|
||||
addons: [],
|
||||
ready: false,
|
||||
currentAddonId: null,
|
||||
addonPopupOpened: false,
|
||||
currentlyUninstalling: []
|
||||
|
@ -84,6 +98,7 @@ export default {
|
|||
load () {
|
||||
this.$oh.api.get('/rest/extensions').then(data => {
|
||||
this.addons = data.filter(addon => addon.installed && addon.type === this.addonType)
|
||||
this.ready = true
|
||||
this.startEventSource()
|
||||
}).catch((err) => {
|
||||
// sometimes we get 502 errors ('Jersey is not ready yet!'), keep trying
|
||||
|
@ -105,6 +120,15 @@ export default {
|
|||
this.stopEventSource()
|
||||
this.load()
|
||||
break
|
||||
case 'failed':
|
||||
this.$f7.toast.create({
|
||||
text: `Installation of addon ${topicParts[2]} failed`,
|
||||
closeButton: true,
|
||||
destroyOnClose: true
|
||||
}).open()
|
||||
this.stopEventSource()
|
||||
this.load()
|
||||
break
|
||||
}
|
||||
}, () => {
|
||||
// in case of error, maybe the SSE connection was closed by the add-ons change itself - try reloading to refresh
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<f7-page @page:afterin="onPageAfterIn">
|
||||
<f7-page @page:afterin="onPageAfterIn" @page:afterout="stopEventSource">
|
||||
<f7-navbar title="Inbox" back-link="Settings" back-link-url="/settings/" back-link-force>
|
||||
<f7-nav-right>
|
||||
<f7-link icon-md="material:done_all" @click="toggleCheck()"
|
||||
|
@ -42,7 +42,7 @@
|
|||
|
||||
<f7-block class="block-narrow">
|
||||
<f7-col>
|
||||
<f7-block-title><span v-if="ready">{{inbox.length}} entries</span>
|
||||
<f7-block-title><span v-if="ready">{{inboxCount}} entries</span>
|
||||
<div style="text-align:right; color:var(--f7-block-text-color); font-weight: normal" class="float-right">
|
||||
<label @click="toggleIgnored" style="cursor:pointer">Show ignored</label> <f7-checkbox :checked="showIgnored" @change="toggleIgnored"></f7-checkbox>
|
||||
</div>
|
||||
|
@ -130,6 +130,10 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
inboxCount () {
|
||||
if (!this.inbox) return 0
|
||||
return (this.showIgnored) ? this.inbox.length : this.inbox.filter((e) => e.flag !== 'IGNORED').length
|
||||
},
|
||||
indexedInbox () {
|
||||
const filteredInbox = (this.showIgnored) ? this.inbox : this.inbox.filter((e) => e.flag !== 'IGNORED')
|
||||
if (this.groupBy === 'alphabetical') {
|
||||
|
@ -168,6 +172,18 @@ export default {
|
|||
},
|
||||
onPageAfterIn () {
|
||||
this.load()
|
||||
this.startEventSource()
|
||||
},
|
||||
startEventSource () {
|
||||
this.eventSource = this.$oh.sse.connect('/rest/events?topics=smarthome/inbox/*', null, (event) => {
|
||||
console.log(event)
|
||||
// const topicParts = event.topic.split('/')
|
||||
this.load()
|
||||
})
|
||||
},
|
||||
stopEventSource () {
|
||||
this.$oh.sse.close(this.eventSource)
|
||||
this.eventSource = null
|
||||
},
|
||||
openEntryActions (e, entry) {
|
||||
if (this.showCheckboxes) {
|
||||
|
|
|
@ -49,13 +49,16 @@
|
|||
</f7-list>
|
||||
|
||||
</f7-col>
|
||||
</f7-block>
|
||||
<f7-block v-if="ready && !bindings.length" class="block-narrow">
|
||||
<f7-col>
|
||||
<f7-col v-if="ready && !bindings.length">
|
||||
<f7-block strong>
|
||||
<p>No bindings available.</p>
|
||||
</f7-block>
|
||||
</f7-col>
|
||||
<f7-col>
|
||||
<f7-list>
|
||||
<f7-list-button color="blue" title="Install New Bindings" href="/settings/addons/binding/add" />
|
||||
</f7-list>
|
||||
</f7-col>
|
||||
</f7-block>
|
||||
</f7-page>
|
||||
</template>
|
||||
|
|
|
@ -13,13 +13,6 @@
|
|||
></f7-searchbar>
|
||||
</f7-subnavbar>
|
||||
</f7-navbar>
|
||||
|
||||
<!-- <f7-list-index
|
||||
ref="listIndex"
|
||||
list-el=".thing-type-list"
|
||||
:scroll-list="true"
|
||||
:label="true"
|
||||
></f7-list-index> -->
|
||||
<f7-block class="block-narrow">
|
||||
<f7-col>
|
||||
<div v-if="discoverySupported" class="display-flex justify-content-center">
|
||||
|
@ -29,18 +22,7 @@
|
|||
</div>
|
||||
<p class="margin-left margin-right" style="height: 30px" id="scan-progress"></p>
|
||||
<f7-block-title v-if="discoverySupported && scanResults.length">Discovered Things</f7-block-title>
|
||||
<!-- <f7-list class="col thing-type-list" v-if="scanning">
|
||||
<f7-list-item title="Scanning for things...">
|
||||
<f7-preloader slot="media" :size="42"></f7-preloader>
|
||||
</f7-list-item>
|
||||
</f7-list> -->
|
||||
<!-- <f7-list class="col thing-type-list" v-if="ready && discoverySupported && !scanning && !scanResults.length">
|
||||
<f7-list-item
|
||||
title="No discovery results.">
|
||||
<f7-button slot="after" @click="scan()">Retry</f7-button>
|
||||
</f7-list-item>
|
||||
</f7-list> -->
|
||||
<f7-list class="col thing-type-list" v-if="scanResults.length">
|
||||
<f7-list class="col" v-if="scanResults.length">
|
||||
<f7-list-item v-for="entry in scanResults"
|
||||
:key="entry.thingUID"
|
||||
:link="true"
|
||||
|
@ -54,7 +36,7 @@
|
|||
</f7-list>
|
||||
|
||||
<f7-block-title>Add Manually</f7-block-title>
|
||||
<f7-list>
|
||||
<f7-list class="thing-type-list">
|
||||
<ul v-if="!ready">
|
||||
<f7-list-item
|
||||
v-for="n in 10"
|
||||
|
@ -67,21 +49,23 @@
|
|||
>
|
||||
</f7-list-item>
|
||||
</ul>
|
||||
<f7-list-item v-else v-for="thingType in thingTypes"
|
||||
:key="thingType.UID"
|
||||
:link="thingType.UID"
|
||||
:title="thingType.label"
|
||||
:footer="thingType.description"
|
||||
:header="thingType.UID"
|
||||
:badge="thingType.bridge ? 'Bridge' : ''" badge-color="blue"
|
||||
media-item
|
||||
>
|
||||
</f7-list-item>
|
||||
<ul v-else>
|
||||
<f7-list-item v-for="thingType in thingTypes"
|
||||
:key="thingType.UID"
|
||||
:link="thingType.UID"
|
||||
:title="thingType.label"
|
||||
:footer="thingType.description"
|
||||
:header="thingType.UID"
|
||||
:badge="thingType.bridge ? 'Bridge' : ''" badge-color="blue"
|
||||
media-item
|
||||
>
|
||||
</f7-list-item>
|
||||
</ul>
|
||||
</f7-list>
|
||||
|
||||
</f7-col>
|
||||
</f7-block>
|
||||
<f7-block v-if="!loading && !thingTypes.length" class="block-narrow">
|
||||
<f7-block v-if="!loading && ready && !thingTypes.length" class="block-narrow">
|
||||
<f7-col>
|
||||
<f7-block strong>
|
||||
<p>No thing types can be added with this binding.</p>
|
||||
|
@ -128,8 +112,9 @@ export default {
|
|||
return a.label.localeCompare(b.label)
|
||||
})
|
||||
this.loading = false
|
||||
this.ready = true
|
||||
this.initSearchbar = true
|
||||
this.ready = true
|
||||
this.loadInbox()
|
||||
this.$oh.api.get('/rest/discovery').then((data) => {
|
||||
if (data.indexOf(this.bindingId) >= 0) {
|
||||
this.discoverySupported = true
|
||||
|
@ -142,13 +127,13 @@ export default {
|
|||
this.scanning = true
|
||||
this.$oh.api.postPlain('/rest/discovery/bindings/' + this.bindingId + '/scan', null, 'text/plain', 'text/plain').then((data) => {
|
||||
try {
|
||||
this.loadInbox()
|
||||
this.scanTimeout = parseInt(data)
|
||||
this.scanProgress = 0
|
||||
let progressBarEl = this.$f7.progressbar.show('#scan-progress', 0, 'blue')
|
||||
this.intervalId = setInterval(() => {
|
||||
this.scanProgress += 1
|
||||
this.$f7.progressbar.set(progressBarEl, this.scanProgress * 100 / this.scanTimeout)
|
||||
this.loadInbox()
|
||||
}, 1000)
|
||||
setTimeout(() => {
|
||||
this.scanning = false
|
||||
|
|
|
@ -244,10 +244,11 @@ export default {
|
|||
this.$f7.dialog.alert('Please configure the channel to link')
|
||||
return
|
||||
}
|
||||
if (!this.itemTypeCompatible()) {
|
||||
this.$f7.dialog.alert('The channel and item type are not compatible')
|
||||
return
|
||||
}
|
||||
// temporarily disabled
|
||||
// if (!this.itemTypeCompatible()) {
|
||||
// this.$f7.dialog.alert('The channel and item type are not compatible')
|
||||
// return
|
||||
// }
|
||||
|
||||
if (this.createItem) {
|
||||
this.$oh.api.put('/rest/items/' + this.newItem.name, this.newItem).then((data) => {
|
||||
|
|
Loading…
Reference in New Issue