Empty state placeholders (#188)
Add information on how to start when there's nothing to display on a page - a common UX pattern which helps users figure out what they need to do. https://uxdesign.cc/writing-empty-states-3e0279f39066 https://material.io/design/communication/empty-states.html Fix search in rules screens. Adjust positions of lists across screens. Detect when the rules engine is not installed and display a message accordingly. Signed-off-by: Yannick Schaus <github@schaus.net>pull/190/head
parent
2e2356922a
commit
ba7bc37051
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"inbox.title": "The Inbox is empty",
|
||||||
|
"inbox.text": "Discovery results from your bindings that can be added as things will appear here.<br><br>You can also start a scan for a certain binding or add things manually with the button below.",
|
||||||
|
|
||||||
|
"things.nobindings.title": "No bindings installed",
|
||||||
|
"things.nobindings.text": "You need to install binding add-ons to add things they support to your system. Click the button below to install some.",
|
||||||
|
|
||||||
|
"things.title": "No things yet",
|
||||||
|
"things.text": "Things are the devices and services connected to openHAB, they are provided by binding add-ons.<br><br>Check the Inbox to add auto-discovered things. You can also start a scan for a certain binding or add your first thing manually with the button below.",
|
||||||
|
|
||||||
|
"items.title": "No items yet",
|
||||||
|
"items.text": "Items represent the functional side of your home - you can link them to the channels defined by your things. Start with the Model view to create a clean initial structure.<br><br>You can also define items with configuration files, or with the button below.",
|
||||||
|
|
||||||
|
"model.title": "Start modelling your home",
|
||||||
|
"model.text": "Build a model from your items to organize them and relate them to each other semantically.<br><br>Begin with a hierarchy of locations: buildings, outside areas, floors and rooms, as needed. Then, insert equipments and points from your things (or manually).",
|
||||||
|
|
||||||
|
"rules.title": "No rules yet",
|
||||||
|
"rules.text": "Rules are the basic building blocks to automate your home - they define which actions to perform when certain events occur.<br><br>Create your first rule with the button below; for more advanced scenarios, you can also write script files in your configuration folder.",
|
||||||
|
|
||||||
|
"schedule.title": "Nothing in the schedule",
|
||||||
|
"schedule.text": "The schedule displays up to 30 days of times when rules specifically tagged \"Schedule\" are expected to run.<br><br>Click the button below to create your first scheduled rule.",
|
||||||
|
|
||||||
|
"rules.missingengine.title": "Rule engine not installed",
|
||||||
|
"rules.missingengine.text": "The rule engine must be installed before rules can be created.",
|
||||||
|
|
||||||
|
"addons.title": "No add-ons installed",
|
||||||
|
"addons.text": "Add-ons add functionality to your openHAB system.<br><br>Install them with the button below."
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
<template>
|
||||||
|
<f7-block class="empty-state-placeholder text-color-gray">
|
||||||
|
<f7-row>
|
||||||
|
<f7-col>
|
||||||
|
<f7-icon :f7="icon" size="64" color="gray" />
|
||||||
|
<h1>{{texts[title] || title}}</h1>
|
||||||
|
<p v-html="texts[text] || text"></p>
|
||||||
|
</f7-col>
|
||||||
|
</f7-row>
|
||||||
|
</f7-block>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
.empty-state-placeholder
|
||||||
|
margin-top 10vh !important
|
||||||
|
text-align center
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// TODO: i18n
|
||||||
|
import texts from '@/assets/i18n/en/empty-states.json'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['icon', 'title', 'text'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
texts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -4,6 +4,7 @@ import Vue from 'vue'
|
||||||
import SitemapWidgetGeneric from '../components/sitemap/widget-generic.vue'
|
import SitemapWidgetGeneric from '../components/sitemap/widget-generic.vue'
|
||||||
import OHIconComponent from '../components/oh-icon.vue'
|
import OHIconComponent from '../components/oh-icon.vue'
|
||||||
import TreeviewItem from '../components/model/treeview-item.vue'
|
import TreeviewItem from '../components/model/treeview-item.vue'
|
||||||
|
import EmptyStatePlaceholder from '../components/empty-state-placeholder.vue'
|
||||||
|
|
||||||
// Import Framework7
|
// Import Framework7
|
||||||
import Framework7 from 'framework7/framework7-lite.esm.bundle.js'
|
import Framework7 from 'framework7/framework7-lite.esm.bundle.js'
|
||||||
|
@ -47,3 +48,4 @@ const app = new Vue({
|
||||||
Vue.component('sitemap-widget-generic', SitemapWidgetGeneric)
|
Vue.component('sitemap-widget-generic', SitemapWidgetGeneric)
|
||||||
Vue.component('oh-icon', OHIconComponent)
|
Vue.component('oh-icon', OHIconComponent)
|
||||||
Vue.component('model-treeview-item', TreeviewItem)
|
Vue.component('model-treeview-item', TreeviewItem)
|
||||||
|
Vue.component('empty-state-placeholder', EmptyStatePlaceholder)
|
||||||
|
|
|
@ -105,7 +105,7 @@ export default {
|
||||||
break
|
break
|
||||||
case 'failed':
|
case 'failed':
|
||||||
this.$f7.toast.create({
|
this.$f7.toast.create({
|
||||||
text: `Installation of addon ${topicParts[2]} failed`,
|
text: `Installation of add-on ${topicParts[2]} failed`,
|
||||||
closeButton: true,
|
closeButton: true,
|
||||||
destroyOnClose: true
|
destroyOnClose: true
|
||||||
}).open()
|
}).open()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<f7-page @page:afterin="onPageAfterIn" @page:beforeout="addonPopupOpened = false" @page:afterout="stopEventSource">
|
<f7-page @page:afterin="onPageAfterIn" @page:beforeout="addonPopupOpened = false" @page:afterout="stopEventSource">
|
||||||
<f7-navbar :title="'Add-ons: ' + addonType" back-link="Settings" back-link-url="/settings/" back-link-force>
|
<f7-navbar :title="'Add-ons: ' + addonsLabels[addonType]" back-link="Settings" back-link-url="/settings/" back-link-force>
|
||||||
<!-- <f7-nav-right>
|
<!-- <f7-nav-right>
|
||||||
<f7-link href="add">Add</f7-link>
|
<f7-link href="add">Add</f7-link>
|
||||||
</f7-nav-right>-->
|
</f7-nav-right>-->
|
||||||
|
@ -44,11 +44,7 @@
|
||||||
</f7-col>
|
</f7-col>
|
||||||
</f7-block>
|
</f7-block>
|
||||||
<f7-block form v-if="ready && !addons.length" class="service-config block-narrow">
|
<f7-block form v-if="ready && !addons.length" class="service-config block-narrow">
|
||||||
<f7-col>
|
<empty-state-placeholder :icon="addonsIcons[addonType]" :title="'No ' + addonsLabels[addonType] + ' installed yet'" text="addons.text" />
|
||||||
<f7-block strong>
|
|
||||||
<p>No add-ons of type {{addonType}} installed yet. Click the + button to add one!</p>
|
|
||||||
</f7-block>
|
|
||||||
</f7-col>
|
|
||||||
</f7-block>
|
</f7-block>
|
||||||
<f7-fab position="right-bottom" slot="fixed" color="blue" href="add">
|
<f7-fab position="right-bottom" slot="fixed" color="blue" href="add">
|
||||||
<f7-icon ios="f7:plus" md="material:add" aurora="f7:plus"></f7-icon>
|
<f7-icon ios="f7:plus" md="material:add" aurora="f7:plus"></f7-icon>
|
||||||
|
@ -84,7 +80,25 @@ export default {
|
||||||
ready: false,
|
ready: false,
|
||||||
currentAddonId: null,
|
currentAddonId: null,
|
||||||
addonPopupOpened: false,
|
addonPopupOpened: false,
|
||||||
currentlyUninstalling: []
|
currentlyUninstalling: [],
|
||||||
|
addonsLabels: {
|
||||||
|
binding: 'bindings',
|
||||||
|
action: 'actions',
|
||||||
|
persistence: 'persistence services',
|
||||||
|
transformation: 'transformations',
|
||||||
|
misc: 'miscellaneous add-ons',
|
||||||
|
ui: 'user interfaces',
|
||||||
|
voice: 'voice services'
|
||||||
|
},
|
||||||
|
addonsIcons: {
|
||||||
|
binding: 'circle_grid_hex',
|
||||||
|
action: 'bolt_horizontal',
|
||||||
|
persistence: 'download_circle',
|
||||||
|
transformation: 'function',
|
||||||
|
misc: 'rectangle_3_offgrid',
|
||||||
|
ui: 'play_rectangle',
|
||||||
|
voice: 'chat_bubble_2'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -123,7 +137,7 @@ export default {
|
||||||
break
|
break
|
||||||
case 'failed':
|
case 'failed':
|
||||||
this.$f7.toast.create({
|
this.$f7.toast.create({
|
||||||
text: `Installation of addon ${topicParts[2]} failed`,
|
text: `Uninstallation of add-on ${topicParts[2]} failed`,
|
||||||
closeButton: true,
|
closeButton: true,
|
||||||
destroyOnClose: true
|
destroyOnClose: true
|
||||||
}).open()
|
}).open()
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
<label @click="toggleIgnored" style="cursor:pointer">Show ignored</label> <f7-checkbox :checked="showIgnored" @change="toggleIgnored"></f7-checkbox>
|
<label @click="toggleIgnored" style="cursor:pointer">Show ignored</label> <f7-checkbox :checked="showIgnored" @change="toggleIgnored"></f7-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</f7-block-title>
|
</f7-block-title>
|
||||||
<div class="padding-left padding-right">
|
<div class="padding-left padding-right" v-show="!ready || inboxCount > 0">
|
||||||
<f7-segmented strong tag="p">
|
<f7-segmented strong tag="p">
|
||||||
<f7-button :active="groupBy === 'alphabetical'" @click="groupBy = 'alphabetical'; $nextTick(() => $refs.listIndex.update())">Alphabetical</f7-button>
|
<f7-button :active="groupBy === 'alphabetical'" @click="groupBy = 'alphabetical'; $nextTick(() => $refs.listIndex.update())">Alphabetical</f7-button>
|
||||||
<f7-button :active="groupBy === 'binding'" @click="groupBy = 'binding'">By binding</f7-button>
|
<f7-button :active="groupBy === 'binding'" @click="groupBy = 'binding'">By binding</f7-button>
|
||||||
|
@ -95,12 +95,8 @@
|
||||||
|
|
||||||
</f7-col>
|
</f7-col>
|
||||||
</f7-block>
|
</f7-block>
|
||||||
<f7-block v-if="ready && !inbox.length" class="block-narrow">
|
<f7-block v-if="ready && inboxCount === 0" class="block-narrow">
|
||||||
<f7-col>
|
<empty-state-placeholder icon="tray" title="inbox.title" text="inbox.text" />
|
||||||
<f7-block strong>
|
|
||||||
<p>Inbox is empty.</p>
|
|
||||||
</f7-block>
|
|
||||||
</f7-col>
|
|
||||||
</f7-block>
|
</f7-block>
|
||||||
<f7-fab v-show="!showCheckboxes" position="right-bottom" slot="fixed" color="blue" href="/settings/things/add">
|
<f7-fab v-show="!showCheckboxes" position="right-bottom" slot="fixed" color="blue" href="/settings/things/add">
|
||||||
<f7-icon ios="f7:plus" md="material:add" aurora="f7:plus"></f7-icon>
|
<f7-icon ios="f7:plus" md="material:add" aurora="f7:plus"></f7-icon>
|
||||||
|
@ -209,7 +205,7 @@ export default {
|
||||||
bold: true,
|
bold: true,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
console.log(`Add ${entry.thingUID} as thing`)
|
console.log(`Add ${entry.thingUID} as thing`)
|
||||||
this.$f7.dialog.prompt(`This will create a new Thing ${entry.thingUID} with the following name:`,
|
this.$f7.dialog.prompt(`This will create a new Thing of type ${entry.thingTypeUID} with the following name:`,
|
||||||
'Add as Thing',
|
'Add as Thing',
|
||||||
(name) => {
|
(name) => {
|
||||||
this.$oh.api.postPlain(`/rest/inbox/${entry.thingUID}/approve`, name).then((res) => {
|
this.$oh.api.postPlain(`/rest/inbox/${entry.thingUID}/approve`, name).then((res) => {
|
||||||
|
@ -259,7 +255,7 @@ export default {
|
||||||
text: 'Remove',
|
text: 'Remove',
|
||||||
color: 'red',
|
color: 'red',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
this.$f7.dialog.confirm(`Remove ${entry.label} from Inbox?`, 'Remove Entry', () => {
|
this.$f7.dialog.confirm(`Remove ${entry.label} from the Inbox?`, 'Remove Entry', () => {
|
||||||
this.$oh.api.delete('/rest/inbox/' + entry.thingUID).then((res) => {
|
this.$oh.api.delete('/rest/inbox/' + entry.thingUID).then((res) => {
|
||||||
this.$f7.toast.create({
|
this.$f7.toast.create({
|
||||||
text: 'Entry removed',
|
text: 'Entry removed',
|
||||||
|
|
|
@ -32,30 +32,31 @@
|
||||||
<f7-list-item title="Nothing found"></f7-list-item>
|
<f7-list-item title="Nothing found"></f7-list-item>
|
||||||
</f7-list>
|
</f7-list>
|
||||||
<!-- skeleton for not ready -->
|
<!-- skeleton for not ready -->
|
||||||
<f7-block class="block-narrow" v-if="!ready">
|
<f7-block class="block-narrow">
|
||||||
<f7-block-title class="col wide padding-left">Loading...</f7-block-title>
|
<f7-col v-show="!ready">
|
||||||
<f7-list media-list class="col wide">
|
<f7-block-title> Loading...</f7-block-title>
|
||||||
<f7-list-group>
|
<f7-list media-list class="col wide">
|
||||||
<f7-list-item
|
<f7-list-group>
|
||||||
media-item
|
<f7-list-item
|
||||||
v-for="n in 20"
|
media-item
|
||||||
:key="n"
|
v-for="n in 20"
|
||||||
:class="`skeleton-text skeleton-effect-blink`"
|
:key="n"
|
||||||
title="Label of the item"
|
:class="`skeleton-text skeleton-effect-blink`"
|
||||||
subtitle="type, semantic metadata"
|
title="Label of the item"
|
||||||
after="The item state"
|
subtitle="type, semantic metadata"
|
||||||
footer="This contains the type of the item"
|
after="The item state"
|
||||||
>
|
footer="This contains the type of the item"
|
||||||
<f7-skeleton-block style="width: 32px; height: 32px; border-radius: 50%" slot="media"></f7-skeleton-block>
|
>
|
||||||
</f7-list-item>
|
<f7-skeleton-block style="width: 32px; height: 32px; border-radius: 50%" slot="media"></f7-skeleton-block>
|
||||||
</f7-list-group>
|
</f7-list-item>
|
||||||
</f7-list>
|
</f7-list-group>
|
||||||
</f7-block>
|
</f7-list>
|
||||||
<f7-block class="block-narrow" v-else>
|
</f7-col>
|
||||||
<f7-block-title class="col wide padding-left searchbar-hide-on-search">{{items.length}} items</f7-block-title>
|
<f7-col v-if="ready">
|
||||||
<f7-col>
|
<f7-block-title class="searchbar-hide-on-search">{{items.length}} items</f7-block-title>
|
||||||
<f7-list
|
<f7-list
|
||||||
class="searchbar-found col wide"
|
v-show="items.length > 0"
|
||||||
|
class="searchbar-found col"
|
||||||
ref="itemsList"
|
ref="itemsList"
|
||||||
media-list
|
media-list
|
||||||
virtual-list
|
virtual-list
|
||||||
|
@ -86,13 +87,9 @@
|
||||||
</f7-list>
|
</f7-list>
|
||||||
</f7-col>
|
</f7-col>
|
||||||
</f7-block>
|
</f7-block>
|
||||||
<!-- <f7-block v-if="!items.length" class="service-config block-narrow">
|
<f7-block v-if="ready && !items.length" class="service-config block-narrow">
|
||||||
<f7-col>
|
<empty-state-placeholder icon="square_on_circle" title="items.title" text="items.text" />
|
||||||
<f7-block strong>
|
</f7-block>
|
||||||
<p>No items.</p>
|
|
||||||
</f7-block>
|
|
||||||
</f7-col>
|
|
||||||
</f7-block>-->
|
|
||||||
<f7-fab v-show="!showCheckboxes" position="right-bottom" slot="fixed" color="blue">
|
<f7-fab v-show="!showCheckboxes" position="right-bottom" slot="fixed" color="blue">
|
||||||
<f7-icon ios="f7:plus" md="material:add" aurora="f7:plus"></f7-icon>
|
<f7-icon ios="f7:plus" md="material:add" aurora="f7:plus"></f7-icon>
|
||||||
<f7-icon ios="f7:multiply" md="material:close" aurora="f7:multiply"></f7-icon>
|
<f7-icon ios="f7:multiply" md="material:close" aurora="f7:multiply"></f7-icon>
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
</div>
|
</div>
|
||||||
<f7-link :disabled="selectedItem != null" class="right" @click="selectedItem = null">Clear</f7-link>
|
<f7-link :disabled="selectedItem != null" class="right" @click="selectedItem = null">Clear</f7-link>
|
||||||
</f7-toolbar>
|
</f7-toolbar>
|
||||||
|
|
||||||
<f7-block v-if="!ready" class="text-align-center">
|
<f7-block v-if="!ready" class="text-align-center">
|
||||||
<f7-preloader></f7-preloader>
|
<f7-preloader></f7-preloader>
|
||||||
<div>Loading...</div>
|
<div>Loading...</div>
|
||||||
|
@ -32,7 +31,9 @@
|
||||||
<f7-block v-else class="semantic-tree-wrapper" :class="{ 'sheet-opened' : detailsOpened }">
|
<f7-block v-else class="semantic-tree-wrapper" :class="{ 'sheet-opened' : detailsOpened }">
|
||||||
<f7-row>
|
<f7-row>
|
||||||
<f7-col width="100" medium="50">
|
<f7-col width="100" medium="50">
|
||||||
<f7-block strong class="semantic-tree" no-gap @click.native="clearSelection">
|
<empty-state-placeholder v-if="empty" icon="list_bullet_indent" title="model.title" text="model.text" />
|
||||||
|
<f7-block v-show="!empty" strong class="semantic-tree" no-gap @click.native="clearSelection">
|
||||||
|
<!-- <empty-state-placeholder v-if="empty" icon="list_bullet_indent" title="model.title" text="model.text" /> -->
|
||||||
<f7-treeview>
|
<f7-treeview>
|
||||||
<model-treeview-item v-for="node in [rootLocations, rootEquipments, rootPoints, rootGroups, rootItems].flat()"
|
<model-treeview-item v-for="node in [rootLocations, rootEquipments, rootPoints, rootGroups, rootItems].flat()"
|
||||||
:key="node.item.name" :model="node"
|
:key="node.item.name" :model="node"
|
||||||
|
@ -103,10 +104,9 @@
|
||||||
.semantic-tree-wrapper
|
.semantic-tree-wrapper
|
||||||
padding 0
|
padding 0
|
||||||
margin-bottom 0
|
margin-bottom 0
|
||||||
.block
|
|
||||||
padding 0
|
|
||||||
border-right 1px solid var(--f7-block-strong-border-color)
|
|
||||||
.semantic-tree
|
.semantic-tree
|
||||||
|
padding 0
|
||||||
|
border-right 1px solid var(--f7-block-strong-border-color)
|
||||||
.treeview
|
.treeview
|
||||||
--f7-treeview-item-height 40px
|
--f7-treeview-item-height 40px
|
||||||
.treeview-item-label
|
.treeview-item-label
|
||||||
|
@ -191,6 +191,12 @@ export default {
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
|
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
empty () {
|
||||||
|
let emptySemantic = !this.rootLocations.length && !this.rootEquipments.length && !this.rootPoints.length
|
||||||
|
return (this.includeNonSemantic) ? emptySemantic && !this.rootGroups.length && !this.rootItems.length : emptySemantic
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onPageAfterIn () {
|
onPageAfterIn () {
|
||||||
|
|
|
@ -12,14 +12,14 @@
|
||||||
:init="initSearchbar"
|
:init="initSearchbar"
|
||||||
search-container=".rules-list"
|
search-container=".rules-list"
|
||||||
search-item=".rulelist-item"
|
search-item=".rulelist-item"
|
||||||
search-in=".item-title, .item-header, .item-footer"
|
search-in=".item-title, .item-subtitle, .item-header, .item-footer"
|
||||||
remove-diacritics
|
remove-diacritics
|
||||||
:disable-button="!$theme.aurora"
|
:disable-button="!$theme.aurora"
|
||||||
></f7-searchbar>
|
></f7-searchbar>
|
||||||
</f7-subnavbar>
|
</f7-subnavbar>
|
||||||
</f7-navbar>
|
</f7-navbar>
|
||||||
<f7-toolbar class="contextual-toolbar" :class="{ 'navbar': $theme.md }" v-if="showCheckboxes" bottom-ios bottom-aurora>
|
<f7-toolbar class="contextual-toolbar" :class="{ 'navbar': $theme.md }" v-if="showCheckboxes" bottom-ios bottom-aurora>
|
||||||
<f7-link v-show="selectedItems.length" v-if="!$theme.md" class="delete" icon-ios="f7:trash" icon-aurora="f7:trash" @click="removeSelected">Remove {{selectedItems.length}}</f7-link>
|
<f7-link color="red" v-show="selectedItems.length" v-if="!$theme.md" class="delete" icon-ios="f7:trash" icon-aurora="f7:trash" @click="removeSelected">Remove {{selectedItems.length}}</f7-link>
|
||||||
<f7-link v-if="$theme.md" icon-md="material:close" icon-color="white" @click="showCheckboxes = false"></f7-link>
|
<f7-link v-if="$theme.md" icon-md="material:close" icon-color="white" @click="showCheckboxes = false"></f7-link>
|
||||||
<div class="title" v-if="$theme.md">
|
<div class="title" v-if="$theme.md">
|
||||||
{{selectedItems.length}} selected
|
{{selectedItems.length}} selected
|
||||||
|
@ -33,30 +33,34 @@
|
||||||
<f7-list class="searchbar-not-found">
|
<f7-list class="searchbar-not-found">
|
||||||
<f7-list-item title="Nothing found"></f7-list-item>
|
<f7-list-item title="Nothing found"></f7-list-item>
|
||||||
</f7-list>
|
</f7-list>
|
||||||
|
|
||||||
|
<empty-state-placeholder v-if="noRuleEngine" icon="exclamationmark_triangle" title="rules.missingengine.title" text="rules.missingengine.text" />
|
||||||
|
|
||||||
<!-- skeleton for not ready -->
|
<!-- skeleton for not ready -->
|
||||||
<f7-block class="block-narrow" v-if="!ready">
|
<f7-block class="block-narrow" v-show="!noRuleEngine">
|
||||||
<f7-block-title class="col wide padding-left">Loading...</f7-block-title>
|
<f7-col v-show="!ready">
|
||||||
<f7-list media-list class="col wide">
|
<f7-block-title> Loading...</f7-block-title>
|
||||||
<f7-list-group>
|
<f7-list media-list class="col wide">
|
||||||
<f7-list-item
|
<f7-list-group>
|
||||||
media-item
|
<f7-list-item
|
||||||
v-for="n in 20"
|
media-item
|
||||||
:key="n"
|
v-for="n in 20"
|
||||||
:class="`skeleton-text skeleton-effect-blink`"
|
:key="n"
|
||||||
title="Title of the rule"
|
:class="`skeleton-text skeleton-effect-blink`"
|
||||||
subtitle="Tags, Schedule, Scene..."
|
title="Title of the rule"
|
||||||
after="status badge"
|
subtitle="Tags, Schedule, Scene..."
|
||||||
footer="Description of the rule"
|
after="status badge"
|
||||||
>
|
footer="Description of the rule"
|
||||||
</f7-list-item>
|
>
|
||||||
</f7-list-group>
|
</f7-list-item>
|
||||||
</f7-list>
|
</f7-list-group>
|
||||||
</f7-block>
|
</f7-list>
|
||||||
<f7-block class="block-narrow" v-else>
|
</f7-col>
|
||||||
<f7-block-title class="col wide padding-left searchbar-hide-on-search">{{rules.length}} rules</f7-block-title>
|
<f7-col v-if="ready">
|
||||||
<f7-col>
|
<f7-block-title v-show="rules.length" class="searchbar-hide-on-search">{{rules.length}} rules</f7-block-title>
|
||||||
<f7-list
|
<f7-list
|
||||||
class="searchbar-found col wide rules-list"
|
v-show="rules.length > 0"
|
||||||
|
class="searchbar-found col rules-list"
|
||||||
ref="rulesList"
|
ref="rulesList"
|
||||||
media-list>
|
media-list>
|
||||||
<f7-list-item
|
<f7-list-item
|
||||||
|
@ -83,7 +87,10 @@
|
||||||
</f7-list>
|
</f7-list>
|
||||||
</f7-col>
|
</f7-col>
|
||||||
</f7-block>
|
</f7-block>
|
||||||
<f7-fab v-show="!showCheckboxes" position="right-bottom" slot="fixed" color="blue" href="add">
|
<f7-block v-if="ready && !noRuleEngine && !rules.length" class="service-config block-narrow">
|
||||||
|
<empty-state-placeholder icon="wand_rays" title="rules.title" text="rules.text" />
|
||||||
|
</f7-block>
|
||||||
|
<f7-fab v-show="ready && !showCheckboxes" position="right-bottom" slot="fixed" color="blue" href="add">
|
||||||
<f7-icon ios="f7:plus" md="material:add" aurora="f7:plus"></f7-icon>
|
<f7-icon ios="f7:plus" md="material:add" aurora="f7:plus"></f7-icon>
|
||||||
<f7-icon ios="f7:close" md="material:close" aurora="f7:close"></f7-icon>
|
<f7-icon ios="f7:close" md="material:close" aurora="f7:close"></f7-icon>
|
||||||
</f7-fab>
|
</f7-fab>
|
||||||
|
@ -96,6 +103,7 @@ export default {
|
||||||
return {
|
return {
|
||||||
ready: false,
|
ready: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
noRuleEngine: false,
|
||||||
rules: [],
|
rules: [],
|
||||||
initSearchbar: false,
|
initSearchbar: false,
|
||||||
selectedItems: [],
|
selectedItems: [],
|
||||||
|
@ -117,11 +125,15 @@ export default {
|
||||||
this.rules = data.sort((a, b) => {
|
this.rules = data.sort((a, b) => {
|
||||||
return a.name.localeCompare(b.name)
|
return a.name.localeCompare(b.name)
|
||||||
})
|
})
|
||||||
this.initSearchbar = true
|
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.ready = true
|
this.ready = true
|
||||||
|
setTimeout(() => { this.initSearchbar = true })
|
||||||
|
|
||||||
if (!this.eventSource) this.startEventSource()
|
if (!this.eventSource) this.startEventSource()
|
||||||
|
}).catch((err, status) => {
|
||||||
|
if (err === 'Not Found' || status === 404) {
|
||||||
|
this.noRuleEngine = true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
startEventSource () {
|
startEventSource () {
|
||||||
|
|
|
@ -30,7 +30,9 @@
|
||||||
</div>
|
</div>
|
||||||
</f7-toolbar>
|
</f7-toolbar>
|
||||||
|
|
||||||
<div class="timeline timeline-horizontal col-33 tablet-15">
|
<empty-state-placeholder v-if="noRuleEngine" icon="exclamationmark_triangle" title="rules.missingengine.title" text="rules.missingengine.text" />
|
||||||
|
<empty-state-placeholder v-else-if="ready && !rules.length" icon="calendar" title="schedule.title" text="schedule.text" />
|
||||||
|
<div v-else class="timeline timeline-horizontal col-33 tablet-15">
|
||||||
<div class="timeline-year" v-for="(yearObj, year) in calendar" :key="year">
|
<div class="timeline-year" v-for="(yearObj, year) in calendar" :key="year">
|
||||||
<div class="timeline-year-title"><span>{{year}}</span></div>
|
<div class="timeline-year-title"><span>{{year}}</span></div>
|
||||||
<div class="timeline-month" v-for="(monthObj, month) in yearObj" :key="month">
|
<div class="timeline-month" v-for="(monthObj, month) in yearObj" :key="month">
|
||||||
|
@ -49,7 +51,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<f7-fab position="right-bottom" slot="fixed" color="blue" href="add">
|
<f7-fab v-if="ready" position="right-bottom" slot="fixed" color="blue" href="add">
|
||||||
<f7-icon ios="f7:plus" md="material:add" aurora="f7:plus"></f7-icon>
|
<f7-icon ios="f7:plus" md="material:add" aurora="f7:plus"></f7-icon>
|
||||||
<f7-icon ios="f7:close" md="material:close" aurora="f7:close"></f7-icon>
|
<f7-icon ios="f7:close" md="material:close" aurora="f7:close"></f7-icon>
|
||||||
</f7-fab>
|
</f7-fab>
|
||||||
|
@ -75,6 +77,7 @@ export default {
|
||||||
ready: false,
|
ready: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
rules: [],
|
rules: [],
|
||||||
|
noRuleEngine: false,
|
||||||
calendar: {},
|
calendar: {},
|
||||||
initSearchbar: false,
|
initSearchbar: false,
|
||||||
selectedItems: [],
|
selectedItems: [],
|
||||||
|
@ -163,6 +166,10 @@ export default {
|
||||||
|
|
||||||
this.ready = true
|
this.ready = true
|
||||||
if (!this.eventSource) this.startEventSource()
|
if (!this.eventSource) this.startEventSource()
|
||||||
|
}).catch((err, status) => {
|
||||||
|
if (err === 'Not Found' || status === 404) {
|
||||||
|
this.noRuleEngine = true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
startEventSource () {
|
startEventSource () {
|
||||||
|
|
|
@ -20,43 +20,41 @@
|
||||||
:scroll-list="true"
|
:scroll-list="true"
|
||||||
:label="true"
|
:label="true"
|
||||||
></f7-list-index>
|
></f7-list-index>
|
||||||
|
|
||||||
|
<empty-state-placeholder v-if="ready && !bindings.length" icon="circle_grid_hex" title="things.nobindings.title" text="things.nobindings.text" />
|
||||||
|
|
||||||
<f7-block class="block-narrow">
|
<f7-block class="block-narrow">
|
||||||
<f7-col>
|
<f7-col>
|
||||||
<f7-list v-if="!ready" class="col binding-list">
|
<f7-list v-if="!ready" class="col binding-list">
|
||||||
<f7-list-group>
|
<f7-list-group>
|
||||||
<f7-list-item
|
<f7-list-item
|
||||||
v-for="n in 10"
|
v-for="n in 10"
|
||||||
|
media-item
|
||||||
:key="n"
|
:key="n"
|
||||||
:class="`skeleton-text skeleton-effect-blink`"
|
:class="`skeleton-text skeleton-effect-blink`"
|
||||||
title="Label of the binding"
|
title="Label of the binding"
|
||||||
header="BindingID"
|
header="BindingID"
|
||||||
footer="This contains the description of the binding"
|
footer="This contains the description of the binding">
|
||||||
media-item
|
|
||||||
>
|
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
</f7-list-group>
|
</f7-list-group>
|
||||||
</f7-list>
|
</f7-list>
|
||||||
<f7-list v-else class="col">
|
<f7-list v-else class="col">
|
||||||
<f7-list-item v-for="binding in bindings"
|
<f7-list-item
|
||||||
|
v-for="binding in bindings"
|
||||||
|
media-item
|
||||||
:key="binding.id"
|
:key="binding.id"
|
||||||
:link="binding.id"
|
:link="binding.id"
|
||||||
:title="binding.name"
|
:title="binding.name"
|
||||||
:header="binding.id"
|
:header="binding.id"
|
||||||
:footer="binding.description"
|
:footer="(binding.description && binding.description.indexOf('<br>') >= 0) ?
|
||||||
media-item
|
binding.description.split('<br>')[0] : binding.description">
|
||||||
>
|
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
</f7-list>
|
</f7-list>
|
||||||
|
|
||||||
</f7-col>
|
</f7-col>
|
||||||
<f7-col v-if="ready && !bindings.length">
|
|
||||||
<f7-block strong>
|
|
||||||
<p>No bindings available.</p>
|
|
||||||
</f7-block>
|
|
||||||
</f7-col>
|
|
||||||
<f7-col>
|
<f7-col>
|
||||||
<f7-list>
|
<f7-list>
|
||||||
<f7-list-button color="blue" title="Install New Bindings" href="/settings/addons/binding/add" />
|
<f7-list-button color="blue" title="Install Bindings" href="/settings/addons/binding/add" />
|
||||||
</f7-list>
|
</f7-list>
|
||||||
</f7-col>
|
</f7-col>
|
||||||
</f7-block>
|
</f7-block>
|
||||||
|
@ -72,13 +70,9 @@ export default {
|
||||||
initSearchbar: false,
|
initSearchbar: false,
|
||||||
bindings: []
|
bindings: []
|
||||||
}
|
}
|
||||||
},
|
|
||||||
created () {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onPageAfterIn () {
|
onPageAfterIn () {
|
||||||
// this.$f7.preloader.show()
|
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.$oh.api.get('/rest/bindings').then((data) => {
|
this.$oh.api.get('/rest/bindings').then((data) => {
|
||||||
this.bindings = data.sort((a, b) => a.name.localeCompare(b.name))
|
this.bindings = data.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<f7-col>
|
<f7-col>
|
||||||
<div v-if="discoverySupported" class="display-flex justify-content-center">
|
<div v-if="discoverySupported" class="display-flex justify-content-center">
|
||||||
<div class="flex-shrink-0">
|
<div class="flex-shrink-0">
|
||||||
<f7-button class="padding-left padding-right" style="width: 150px" color="blue" large raised fill :disabled="scanning" @click="scan">{{(scanning) ? 'Scanning...' : 'Rescan'}}</f7-button>
|
<f7-button class="padding-left padding-right" style="width: 150px" color="blue" large raised fill :disabled="scanning" @click="scan">{{(scanning) ? 'Scanning...' : 'Scan Again'}}</f7-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="margin-left margin-right" style="height: 30px" id="scan-progress"></p>
|
<p class="margin-left margin-right" style="height: 30px" id="scan-progress"></p>
|
||||||
|
@ -157,7 +157,7 @@ export default {
|
||||||
},
|
},
|
||||||
approve (entry) {
|
approve (entry) {
|
||||||
console.log(`Add ${entry.thingUID} as thing`)
|
console.log(`Add ${entry.thingUID} as thing`)
|
||||||
this.$f7.dialog.prompt(`This will create a new Thing ${entry.thingUID} with the following name:`,
|
this.$f7.dialog.prompt(`This will create a new Thing of type ${entry.thingTypeUID} with the following name:`,
|
||||||
'Add as Thing',
|
'Add as Thing',
|
||||||
(name) => {
|
(name) => {
|
||||||
this.$oh.api.postPlain(`/rest/inbox/${entry.thingUID}/approve`, name).then((res) => {
|
this.$oh.api.postPlain(`/rest/inbox/${entry.thingUID}/approve`, name).then((res) => {
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<f7-block class="block-narrow">
|
<f7-block class="block-narrow">
|
||||||
<f7-col>
|
<f7-col>
|
||||||
<f7-block-title class="searchbar-hide-on-search"><span v-if="ready">{{things.length}} things</span></f7-block-title>
|
<f7-block-title class="searchbar-hide-on-search"><span v-if="ready">{{things.length}} things</span></f7-block-title>
|
||||||
<div class="padding-left padding-right">
|
<div class="padding-left padding-right" v-show="!ready || things.length > 0">
|
||||||
<f7-segmented strong tag="p">
|
<f7-segmented strong tag="p">
|
||||||
<f7-button :active="groupBy === 'alphabetical'" @click="groupBy = 'alphabetical'; $nextTick(() => $refs.listIndex.update())">Alphabetical</f7-button>
|
<f7-button :active="groupBy === 'alphabetical'" @click="groupBy = 'alphabetical'; $nextTick(() => $refs.listIndex.update())">Alphabetical</f7-button>
|
||||||
<f7-button :active="groupBy === 'binding'" @click="groupBy = 'binding'">By binding</f7-button>
|
<f7-button :active="groupBy === 'binding'" @click="groupBy = 'binding'">By binding</f7-button>
|
||||||
|
@ -67,13 +67,9 @@
|
||||||
|
|
||||||
</f7-col>
|
</f7-col>
|
||||||
</f7-block>
|
</f7-block>
|
||||||
<!-- <f7-block v-if="!things.length" class="block-narrow">
|
<f7-block v-if="ready && !things.length" class="block-narrow">
|
||||||
<f7-col>
|
<empty-state-placeholder icon="lightbulb" title="things.title" text="things.text" />
|
||||||
<f7-block strong>
|
</f7-block>
|
||||||
<p>No things.</p>
|
|
||||||
</f7-block>
|
|
||||||
</f7-col>
|
|
||||||
</f7-block>-->
|
|
||||||
<f7-fab position="right-bottom" slot="fixed" color="blue" href="add">
|
<f7-fab position="right-bottom" slot="fixed" color="blue" href="add">
|
||||||
<f7-icon ios="f7:plus" md="material:add" aurora="f7:plus"></f7-icon>
|
<f7-icon ios="f7:plus" md="material:add" aurora="f7:plus"></f7-icon>
|
||||||
<f7-icon ios="f7:close" md="material:close" aurora="f7:close"></f7-icon>
|
<f7-icon ios="f7:close" md="material:close" aurora="f7:close"></f7-icon>
|
||||||
|
|
Loading…
Reference in New Issue