Refactor routes: Move admin pages away from entry point (#948)

Load all settings pages, about, profile, empty states, and the HABot control asynchronously.
This also moves library dependencies to separate chunks, and thus reduces the entry point
by several hundred kb if the user only accesses end-user pages, until they go to these pages.
Various other optimizations to reduce the bundle size.

Signed-off-by: Yannick Schaus <github@schaus.net>
pull/953/head
Yannick Schaus 2021-03-10 15:13:25 +01:00 committed by GitHub
parent eb7596c42d
commit da2f17e64a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 281 additions and 356 deletions

View File

@ -0,0 +1,70 @@
<template>
<f7-popup ref="mapPicker" class="mappicker-popup" @popup:open="mapPickerOpen" @popup:closed="mapPickerClosed">
<f7-page>
<f7-navbar>
<f7-nav-left>
<f7-link icon-ios="f7:arrow_left" icon-md="material:arrow_back" icon-aurora="f7:arrow_left" popup-close />
</f7-nav-left>
<f7-nav-title>{{ title }}</f7-nav-title>
<f7-nav-right>
<f7-link class="popup-close" @click="updateValue(currentPosition)">
Done
</f7-link>
</f7-nav-right>
</f7-navbar>
<location-picker v-if="showMap" :value="currentPosition" @input="updatePosition" />
</f7-page>
</f7-popup>
</template>
<style lang="stylus">
.mappicker-popup .oh-map-picker-lmap
background-color var(--f7-page-bg-color)
&.leaflet-grab
cursor crosshair
.leaflet-dragging .oh-map-picker-lmap.leaflet-grab
cursor grabbing !important
</style>
<script>
export default {
props: ['value', 'title'],
components: {
'location-picker': () => import(/* webpackChunkName: "location-picker" */ './location-picker.vue')
},
data () {
return {
showMap: false,
currentPosition: null
}
},
watch: {
value (val) {
this.currentPosition = val
}
},
methods: {
updateValue () {
if (this.currentPosition) {
this.$f7.emit('locationUpdate', this.currentPosition)
}
},
updatePosition (event) {
if (event.lat && event.lng) {
this.currentPosition = [event.lat, event.lng].join(',')
}
},
mapPickerClosed () {
this.showMap = false
this.$f7.emit('locationPickerClosed')
},
mapPickerOpen () {
this.currentPosition = this.value
this.$nextTick(() => {
this.showMap = true
})
}
}
}
</script>

View File

@ -1,43 +1,19 @@
<template>
<f7-popup ref="mapPicker" class="mappicker-popup" @popup:opened="mapPickerOpened" @popup:closed="mapPickerClosed">
<f7-page>
<f7-navbar>
<f7-nav-left>
<f7-link icon-ios="f7:arrow_left" icon-md="material:arrow_back" icon-aurora="f7:arrow_left" popup-close />
</f7-nav-left>
<f7-nav-title>{{ title }}</f7-nav-title>
<f7-nav-right>
<f7-link class="popup-close" @click="updateValue(marker)">
Done
</f7-link>
</f7-nav-right>
</f7-navbar>
<l-map
v-if="showMap"
:zoom="zoom"
:center="center"
:options="mapOptions"
@click="mapClicked"
class="oh-map-picker-lmap">
<l-tile-layer
:url="url"
:attribution="attribution" />
<l-marker v-if="marker" :lat-lng="marker" />
</l-map>
</f7-page>
</f7-popup>
<l-map
v-if="showMap"
:zoom="zoom"
:center="center"
:options="mapOptions"
@click="mapClicked"
ref="map"
class="oh-map-picker-lmap">
<l-tile-layer
:url="url"
:attribution="attribution" />
<l-marker v-if="marker" :lat-lng="marker" />
</l-map>
</template>
<style lang="stylus">
.mappicker-popup .oh-map-picker-lmap
background-color var(--f7-page-bg-color)
&.leaflet-grab
cursor crosshair
.leaflet-dragging .oh-map-picker-lmap.leaflet-grab
cursor grabbing !important
</style>
<script>
import { latLng, Icon } from 'leaflet'
import { LMap, LTileLayer, LMarker } from 'vue2-leaflet'
@ -51,7 +27,7 @@ Icon.Default.mergeOptions({
})
export default {
props: ['value', 'title'],
props: ['value'],
components: {
LMap,
LTileLayer,
@ -59,38 +35,30 @@ export default {
},
data () {
return {
showMap: false,
zoom: 4,
center: latLng(48, 6),
// url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
url: `https://a.basemaps.cartocdn.com/${this.$f7.data.themeOptions.dark}_all/{z}/{x}/{y}.png`,
attribution: '&copy; <a class="external" target="_blank" href="http://osm.org/copyright">OpenStreetMap</a>, &copy; <a class="external" target="_blank" href="https://carto.com/attribution/">CARTO</a>',
marker: null,
showMap: false,
mapOptions: {
zoomSnap: 0.5
}
}
},
mounted () {
this.$nextTick(() => {
this.zoom = (this.value) ? 13 : 4
this.marker = (this.value) ? latLng(this.value.split(',')) : null
this.center = (this.value) ? latLng(this.value.split(',')) : latLng(48, 6)
this.showMap = true
})
},
methods: {
updateValue (marker) {
if (marker.lat && marker.lng) {
this.$f7.emit('locationUpdate', marker)
}
},
mapPickerClosed () {
this.showMap = false
this.$f7.emit('locationPickerClosed')
},
mapClicked (evt) {
this.marker = latLng(evt.latlng)
},
mapPickerOpened () {
this.$nextTick(() => {
this.zoom = (this.value) ? 13 : 4
this.marker = (this.value) ? latLng(this.value.split(',')) : null
this.center = (this.value) ? latLng(this.value.split(',')) : latLng(48, 6)
this.showMap = true
})
this.$emit('input', this.marker)
}
}
}

View File

@ -19,12 +19,10 @@
{{ translation }}
</div>
</f7-list-input>
<!-- <cron-editor :value="value" :opened="popupOpened" :popup-id="`config-${configDescription.name}-fullscreen`" @closed="popupOpened = false" @input="(value) => { $emit('input', value) }" /> -->
</ul>
</template>
<script>
import CronEditorPopup from './cronexpression-editor.vue'
import cronstrue from 'cronstrue'
export default {
@ -38,25 +36,27 @@ export default {
this.$emit('input', value)
},
openPopup () {
const popup = {
component: CronEditorPopup
}
this.$f7router.navigate({
url: 'widget-code',
route: {
path: 'widget-code',
popup
import(/* webpackChunkName: "cronexpression-editor" */ '@/components/config/controls/cronexpression-editor.vue').then((c) => {
const popup = {
component: c.default
}
}, {
props: {
value: this.value
}
})
this.$f7.once('cronEditorUpdate', this.updateValue)
this.$f7.once('cronEditorClosed', () => {
this.$f7.off('cronEditorUpdate', this.updateValue)
this.$f7router.navigate({
url: 'cron-edit',
route: {
path: 'cron-edit',
popup
}
}, {
props: {
value: this.value
}
})
this.$f7.once('cronEditorUpdate', this.updateValue)
this.$f7.once('cronEditorClosed', () => {
this.$f7.off('cronEditorUpdate', this.updateValue)
})
})
}
},

View File

@ -8,7 +8,7 @@
:placeholder="placeholder"
:required="configDescription.required" validate
:clear-button="!configDescription.required"
@input="updateValue"
@input="(ev) => updateValue(ev.target.value)"
type="text">
<div class="padding-left" slot="content-end">
<f7-button slot="content-end" @click="openMapPicker">
@ -23,21 +23,17 @@
</style>
<script>
import LocationPicker from './location-picker.vue'
import LocationPickerPopup from './location-picker-popup.vue'
export default {
props: ['configDescription', 'value', 'placeholder'],
methods: {
updateValue (event) {
if (event.lat && event.lng) {
this.$emit('input', [event.lat, event.lng].join(','))
} else {
this.$emit('input', event.target.value)
}
updateValue (position) {
this.$emit('input', position)
},
openMapPicker () {
const popup = {
component: LocationPicker
component: LocationPickerPopup
}
this.$f7router.navigate({

View File

@ -53,7 +53,7 @@ import dslUtil from './dslUtil'
export default {
components: {
'editor': () => import('@/components/config/controls/script-editor.vue')
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue')
},
props: ['sitemap'],
data () {

View File

@ -38,7 +38,7 @@ import YAML from 'yaml'
export default {
props: ['component', 'componentType'],
components: {
'editor': () => import('@/components/config/controls/script-editor.vue')
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue')
},
data () {
return {

View File

@ -27,6 +27,9 @@
import modal from './modal-mixin'
export default {
mixins: [modal]
mixins: [modal],
components: {
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue')
}
}
</script>

View File

@ -25,6 +25,9 @@
import modal from './modal-mixin'
export default {
mixins: [modal]
mixins: [modal],
components: {
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue')
}
}
</script>

View File

@ -8,7 +8,6 @@ import SitemapWidgetGeneric from '../components/sitemap/widget-generic.vue'
import OHIconComponent from '../components/widgets/system/oh-icon.vue'
import ModelTreeviewItem from '../components/model/treeview-item.vue'
import SitemapTreeviewItem from '../components/pagedesigner/sitemap/treeview-item.vue'
import EmptyStatePlaceholder from '../components/empty-state-placeholder.vue'
import GenericWidgetComponent from '../components/widgets/generic-widget-component.vue'
// Import Framework7
@ -80,5 +79,4 @@ Vue.component('sitemap-widget-generic', SitemapWidgetGeneric)
Vue.component('oh-icon', OHIconComponent)
Vue.component('model-treeview-item', ModelTreeviewItem)
Vue.component('sitemap-treeview-item', SitemapTreeviewItem)
Vue.component('empty-state-placeholder', EmptyStatePlaceholder)
Vue.component('generic-widget-component', GenericWidgetComponent)

View File

@ -1,44 +1,56 @@
import HomePage from '../pages/home.vue'
import AboutPage from '../pages/about.vue'
import NotFoundPage from '../pages/not-found.vue'
import UserProfilePage from '../pages/profile.vue'
import SitemapViewPage from '../pages/page/sitemap-view.vue'
import PageViewPage from '../pages/page/page-view.vue'
import SettingsMenuPage from '../pages/settings/settings-menu.vue'
import ServiceSettingsPage from '../pages/settings/services/service-settings.vue'
import AddonsListPage from '../pages/settings/addons/addons-list.vue'
import AddonsAddPage from '../pages/settings/addons/addons-add.vue'
import AddonsConfigureBindingPage from '../pages/settings/addons/binding-config.vue'
const AboutPage = () => import(/* webpackChunkName: "about-page" */ '../pages/about.vue')
const UserProfilePage = () => import(/* webpackChunkName: "profile-page" */ '../pages/profile.vue')
import ItemsListPage from '../pages/settings/items/items-list-vlist.vue'
import ItemDetailsPage from '../pages/settings/items/item-details.vue'
import ItemEditPage from '../pages/settings/items/item-edit.vue'
import ItemsAddFromTextualDefinition from '../pages/settings/items/parser/items-add-from-textual-definition.vue'
const SettingsMenuPage = () => import(/* webpackChunkName: "admin-base" */ '../pages/settings/settings-menu.vue')
const ServiceSettingsPage = () => import(/* webpackChunkName: "admin-base" */ '../pages/settings/services/service-settings.vue')
const AddonsListPage = () => import(/* webpackChunkName: "admin-base" */ '../pages/settings/addons/addons-list.vue')
const AddonsAddPage = () => import(/* webpackChunkName: "admin-base" */ '../pages/settings/addons/addons-add.vue')
const AddonsConfigureBindingPage = () => import(/* webpackChunkName: "admin-base" */ '../pages/settings/addons/binding-config.vue')
import ThingsListPage from '../pages/settings/things/things-list.vue'
import ThingDetailsPage from '../pages/settings/things/thing-details.vue'
import AddThingChooseBindingPage from '../pages/settings/things/add/choose-binding.vue'
import AddThingChooseThingTypePage from '../pages/settings/things/add/choose-thing-type.vue'
import AddThingPage from '../pages/settings/things/add/thing-add.vue'
const ItemsListPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/items/items-list-vlist.vue')
const ItemDetailsPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/items/item-details.vue')
const ItemEditPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/items/item-edit.vue')
const ItemMetadataEditPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/items/metadata/item-metadata-edit.vue')
const ItemsAddFromTextualDefinition = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/items/parser/items-add-from-textual-definition.vue')
import InboxListPage from '../pages/settings/things/inbox/inbox-list.vue'
const ThingsListPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/things/things-list.vue')
const ThingDetailsPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/things/thing-details.vue')
const AddThingChooseBindingPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/things/add/choose-binding.vue')
const AddThingChooseThingTypePage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/things/add/choose-thing-type.vue')
const AddThingPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/things/add/thing-add.vue')
import SemanticModelPage from '../pages/settings/model/model.vue'
const InboxListPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/things/inbox/inbox-list.vue')
import RulesListPage from '../pages/settings/rules/rules-list.vue'
const SemanticModelPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/model/model.vue')
import PagesListPage from '../pages/settings/pages/pages-list.vue'
const PagesListPage = () => import(/* webpackChunkName: "admin-pages" */ '../pages/settings/pages/pages-list.vue')
const PageEditors = {
home: () => import(/* webpackChunkName: "admin-pages" */ '../pages/settings/pages/home/home-edit.vue'),
layout: () => import(/* webpackChunkName: "admin-pages" */ '../pages/settings/pages/layout/layout-edit.vue'),
tabs: () => import(/* webpackChunkName: "admin-pages" */ '../pages/settings/pages/tabs/tabs-edit.vue'),
map: () => import(/* webpackChunkName: "admin-pages-leaflet" */ '../pages/settings/pages/map/map-edit.vue'),
plan: () => import(/* webpackChunkName: "admin-pages-leaflet" */ '../pages/settings/pages/plan/plan-edit.vue'),
chart: () => import(/* webpackChunkName: "admin-pages-echarts" */ '../pages/settings/pages/chart/chart-edit.vue'),
sitemap: () => import(/* webpackChunkName: "admin-pages" */ '../pages/settings/pages/sitemap/sitemap-edit.vue')
}
// import SchedulePage from '../pages/settings/schedule/schedule.vue'
const RulesListPage = () => import(/* webpackChunkName: "admin-rules" */ '../pages/settings/rules/rules-list.vue')
const RuleEditPage = () => import(/* webpackChunkName: "admin-rules" */ '../pages/settings/rules/rule-edit.vue')
const ScriptEditPage = () => import(/* webpackChunkName: "admin-rules" */ '../pages/settings/rules/script/script-edit.vue')
const SchedulePage = () => import(/* webpackChunkName: "admin-schedule" */ '../pages/settings/schedule/schedule.vue')
import Analyzer from '../pages/analyzer/analyzer.vue'
const AnalyzerPage = () => import(/* webpackChunkName: "analyzer" */ '../pages/analyzer/analyzer.vue')
import DeveloperToolsPage from '../pages/developer/developer-tools.vue'
import WidgetsListPage from '../pages/developer/widgets/widget-list.vue'
import ApiExplorerPage from '../pages/developer/api-explorer.vue'
const DeveloperToolsPage = () => import(/* webpackChunkName: "admin-devtools" */ '../pages/developer/developer-tools.vue')
const WidgetsListPage = () => import(/* webpackChunkName: "admin-devtools" */ '../pages/developer/widgets/widget-list.vue')
const WidgetEditPage = () => import(/* webpackChunkName: "admin-devtools" */ '../pages/developer/widgets/widget-edit.vue')
const ApiExplorerPage = () => import(/* webpackChunkName: "admin-devtools" */ '../pages/developer/api-explorer.vue')
const SetupWizardPage = () => import(/* webpackChunkName: "setup-wizard" */ '../pages/wizards/setup-wizard.vue')
const checkDirtyBeforeLeave = function (routeTo, routeFrom, resolve, reject) {
if (this.currentPageEl && this.currentPageEl.__vue__ && this.currentPageEl.__vue__.$parent && this.currentPageEl.__vue__.$parent.beforeLeave &&
@ -49,13 +61,24 @@ const checkDirtyBeforeLeave = function (routeTo, routeFrom, resolve, reject) {
}
}
const loadAsync = (page, props) => {
return (routeTo, routeFrom, resolve, reject) => {
if (!props) {
page().then((c) => { resolve({ component: c.default }) })
} else if (typeof props === 'object') {
page().then((c) => { resolve({ component: c.default }, { props }) })
} else if (typeof props === 'function') {
page().then((c) => { resolve({ component: c.default }, { props: props(routeTo, routeFrom, resolve, reject) }) })
}
}
}
export default [
{
path: '/',
component: HomePage,
// keepAlive: true,
options: {
// animate: false
transition: 'f7-dive'
}
},
@ -63,88 +86,54 @@ export default [
path: '/page/:uid',
component: PageViewPage
},
{
path: '/sitemap/:sitemapId/:pageId',
component: SitemapViewPage
},
{
path: '/about/',
component: AboutPage,
async: loadAsync(AboutPage),
options: {
animate: false
}
},
{
path: '/setup-wizard/',
async (routeTo, routeFrom, resolve, reject) {
// dynamic import component; returns promise
const widgetEditComponent = () => import(/* webpackChunkName: "setup-wizard" */ '../pages/wizards/setup-wizard.vue')
// resolve promise
widgetEditComponent().then((vc) => {
// resolve with component
resolve({
component: vc.default
},
(routeTo.params.uid === 'add') ? {
props: {
createMode: true
}
} : {})
})
}
async: loadAsync(SetupWizardPage)
},
{
path: '/profile/',
component: UserProfilePage,
async: loadAsync(UserProfilePage),
options: {
animate: false
}
},
{
path: '/settings/',
component: SettingsMenuPage,
async: loadAsync(SettingsMenuPage),
keepAlive: true,
routes: [
{
path: 'items',
component: ItemsListPage,
async: loadAsync(ItemsListPage),
routes: [
{
path: 'add',
component: ItemEditPage,
options: {
props: {
createMode: true
}
}
async: loadAsync(ItemEditPage, { createMode: true })
},
{
path: 'add-from-textual-definition',
component: ItemsAddFromTextualDefinition
async: loadAsync(ItemsAddFromTextualDefinition)
},
{
path: ':itemName',
component: ItemDetailsPage,
async: loadAsync(ItemDetailsPage),
routes: [
{
path: 'edit',
component: ItemEditPage,
beforeLeave: checkDirtyBeforeLeave
beforeLeave: checkDirtyBeforeLeave,
async: loadAsync(ItemEditPage)
},
{
path: 'metadata/:namespace',
beforeLeave: checkDirtyBeforeLeave,
async (routeTo, routeFrom, resolve, reject) {
// dynamic import component; returns promise
const editorComponent = () => import(/* webpackChunkName: "metadata-edit" */ '../pages/settings/items/metadata/item-metadata-edit.vue')
// resolve promise
editorComponent().then((vc) => {
// resolve with component
resolve({
component: vc.default
})
})
}
async: loadAsync(ItemMetadataEditPage)
}
]
}
@ -152,54 +141,36 @@ export default [
},
{
path: 'pages',
component: PagesListPage,
async: loadAsync(PagesListPage),
routes: [
{
path: ':type/:uid',
beforeLeave: checkDirtyBeforeLeave,
async (routeTo, routeFrom, resolve, reject) {
// dynamic import component; returns promise
const editorComponent = () => import(/* webpackChunkName: "[request]" */ `../pages/settings/pages/${routeTo.params.type}/${routeTo.params.type}-edit.vue`)
// resolve promise
editorComponent().then((vc) => {
// resolve with component
resolve({
component: vc.default
},
(routeTo.params.uid === 'add') ? {
props: {
createMode: true
}
} : {})
})
PageEditors[routeTo.params.type]().then((c) => { resolve({ component: c.default }, (routeTo.params.uid === 'add') ? { props: { createMode: true } } : {}) })
}
}
]
},
{
path: 'things/',
component: ThingsListPage,
async: loadAsync(ThingsListPage),
routes: [
{
path: 'add',
component: AddThingChooseBindingPage,
async: loadAsync(AddThingChooseBindingPage),
routes: [
{
path: 'install-binding',
component: AddonsAddPage,
options: {
props: {
addonType: 'binding'
}
}
async: loadAsync(AddonsAddPage, { addonType: 'binding' })
},
{
path: ':bindingId',
component: AddThingChooseThingTypePage,
async: loadAsync(AddThingChooseThingTypePage),
routes: [
{
path: ':thingTypeId',
component: AddThingPage
async: loadAsync(AddThingPage)
}
]
}
@ -207,75 +178,32 @@ export default [
},
{
path: 'inbox',
component: InboxListPage
async: loadAsync(InboxListPage)
},
{
path: ':thingId',
component: ThingDetailsPage,
beforeLeave: checkDirtyBeforeLeave
beforeLeave: checkDirtyBeforeLeave,
async: loadAsync(ThingDetailsPage)
}
]
},
{
path: 'model',
component: SemanticModelPage
// keepAlive: true
// routes: [
// {
// path: ':itemName',
// component: ItemDetailsPage,
// routes: [
// {
// path: 'edit',
// component: ItemEditPage
// }
// ]
// }
// ]
async: loadAsync(SemanticModelPage)
},
{
path: 'rules/',
component: RulesListPage,
async: loadAsync(RulesListPage),
routes: [
{
path: ':ruleId',
beforeLeave: checkDirtyBeforeLeave,
async (routeTo, routeFrom, resolve, reject) {
// dynamic import component; returns promise
const ruleEditComponent = () => import(/* webpackChunkName: "rule-edit" */ '../pages/settings/rules/rule-edit.vue')
// resolve promise
ruleEditComponent().then((vc) => {
// resolve with component
resolve({
component: vc.default
},
(routeTo.params.ruleId === 'add') ? {
props: {
createMode: true
}
} : {})
})
},
async: loadAsync(RuleEditPage, (routeTo) => (routeTo.params.ruleId === 'add') ? { createMode: true } : {}),
routes: [
{
path: 'script/:moduleId',
beforeLeave: checkDirtyBeforeLeave,
async (routeTo, routeFrom, resolve, reject) {
// dynamic import component; returns promise
const ruleEditComponent = () => import(/* webpackChunkName: "rule-script-edit" */ '../pages/settings/rules/script/script-edit.vue')
// resolve promise
ruleEditComponent().then((vc) => {
// resolve with component
resolve({
component: vc.default
},
(routeTo.params.ruleId === 'add') ? {
props: {
createMode: true
}
} : {})
})
}
async: loadAsync(ScriptEditPage, (routeTo) => (routeTo.params.ruleId === 'add') ? { createMode: true } : {})
}
]
}
@ -283,143 +211,76 @@ export default [
},
{
path: 'scripts/',
component: RulesListPage,
options: {
props: {
showScripts: true
}
},
async: loadAsync(RulesListPage, { showScripts: true }),
routes: [
{
path: ':ruleId',
beforeLeave: checkDirtyBeforeLeave,
async (routeTo, routeFrom, resolve, reject) {
// dynamic import component; returns promise
const ruleEditComponent = () => import(/* webpackChunkName: "script-edit" */ '../pages/settings/rules/script/script-edit.vue')
// resolve promise
ruleEditComponent().then((vc) => {
// resolve with component
resolve({
component: vc.default
},
(routeTo.params.ruleId === 'add') ? {
props: {
createMode: true
}
} : {})
})
}
async: loadAsync(ScriptEditPage, (routeTo) => (routeTo.params.ruleId === 'add') ? { createMode: true } : {})
}
]
},
{
path: 'schedule/',
async (routeTo, routeFrom, resolve, reject) {
// dynamic import component; returns promise
const scheduleComponent = () => import(/* webpackChunkName: "schedule" */ '../pages/settings/schedule/schedule.vue')
// resolve promise
scheduleComponent().then((vc) => {
// resolve with component
resolve({
component: vc.default
})
})
},
async: loadAsync(SchedulePage),
routes: [
{
path: 'add',
beforeLeave: checkDirtyBeforeLeave,
async (routeTo, routeFrom, resolve, reject) {
// dynamic import component; returns promise
const ruleEditComponent = () => import(/* webpackChunkName: "rule-edit" */ '../pages/settings/rules/rule-edit.vue')
// resolve promise
ruleEditComponent().then((vc) => {
// resolve with component
resolve({
component: vc.default
}, {
props: {
createMode: true,
schedule: true
}
})
})
}
async: loadAsync(RuleEditPage, { createMode: true, schedule: true })
}
]
},
// {
// path: 'inbox/',
// component: InboxListPage
// },
{
path: 'addons/:addonType',
component: AddonsListPage,
async: loadAsync(AddonsListPage),
routes: [
{
path: 'add',
component: AddonsAddPage
async: loadAsync(AddonsAddPage)
},
{
path: ':bindingId/config',
component: AddonsConfigureBindingPage
async: loadAsync(AddonsConfigureBindingPage)
}
]
},
{
path: 'services/:serviceId',
component: ServiceSettingsPage,
beforeLeave: checkDirtyBeforeLeave
beforeLeave: checkDirtyBeforeLeave,
async: loadAsync(ServiceSettingsPage)
}
]
},
{
path: '/developer/',
component: DeveloperToolsPage,
options: {
animate: false
},
async: loadAsync(DeveloperToolsPage),
routes: [
{
path: 'widgets/',
component: WidgetsListPage,
async: loadAsync(WidgetsListPage),
routes: [
{
path: ':uid',
beforeLeave: checkDirtyBeforeLeave,
async (routeTo, routeFrom, resolve, reject) {
// dynamic import component; returns promise
const widgetEditComponent = () => import(/* webpackChunkName: "widget-edit" */ '../pages/developer/widgets/widget-edit.vue')
// resolve promise
widgetEditComponent().then((vc) => {
// resolve with component
resolve({
component: vc.default
},
(routeTo.params.uid === 'add') ? {
props: {
createMode: true
}
} : {})
})
}
async: loadAsync(WidgetEditPage, (routeTo) => (routeTo.params.uid === 'add') ? { createMode: true } : {})
}
]
},
{
path: 'add-items-dsl',
component: ItemsAddFromTextualDefinition
async: loadAsync(ItemsAddFromTextualDefinition)
},
{
path: 'api-explorer',
component: ApiExplorerPage
async: loadAsync(ApiExplorerPage)
}
]
},
{
path: '/analyzer/',
popup: {
component: Analyzer
async (routeTo, routeFrom, resolve, reject) {
AnalyzerPage().then((c) => { resolve({ popup: { component: c.default } }) })
}
},
/* For Cordova */

View File

@ -110,7 +110,7 @@ strOptions.fold.lineWidth = 0
export default {
mixins: [DirtyMixin],
components: {
'editor': () => import('@/components/config/controls/script-editor.vue'),
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue'),
ConfigSheet
},
props: ['uid', 'createMode'],

View File

@ -47,13 +47,13 @@
// import OtherApps from '../../components/home/other-apps.vue'
import OhLayoutPage from '@/components/widgets/layout/oh-layout-page.vue'
import Habot from '../../components/home/habot.vue'
export default {
props: ['context', 'allowChat'],
components: {
OhLayoutPage,
Habot
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue'),
'habot': () => import(/* webpackChunkName: "habot" */ '../../components/home/habot.vue')
},
data () {
return {

View File

@ -51,6 +51,7 @@ import OhLayoutPage from '@/components/widgets/layout/oh-layout-page.vue'
export default {
components: {
'oh-layout-page': OhLayoutPage,
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue'),
'oh-map-page': () => import(/* webpackChunkName: "map-page" */ '@/components/widgets/map/oh-map-page.vue'),
'oh-plan-page': () => import(/* webpackChunkName: "plan-page" */ '@/components/widgets/plan/oh-plan-page.vue'),
'oh-chart-page': () => import(/* webpackChunkName: "chart-page" */ '@/components/widgets/chart/oh-chart-page.vue')

View File

@ -71,6 +71,7 @@ import AddonDetailsSheet from './addon-details-sheet.vue'
export default {
components: {
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue'),
AddonDetailsSheet
},
props: ['addonType'],

View File

@ -116,6 +116,9 @@
<script>
export default {
components: {
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue')
},
data () {
let vlHeight
if (this.$theme.ios) vlHeight = 78

View File

@ -75,7 +75,7 @@ export default {
mixins: [DirtyMixin],
props: ['itemName', 'namespace'],
components: {
'editor': () => import('@/components/config/controls/script-editor.vue')
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue')
},
data () {
return {

View File

@ -146,7 +146,8 @@ import grammar from '@/assets/items-lexer.nearley'
export default {
components: {
'editor': () => import('@/components/config/controls/script-editor.vue')
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue'),
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue')
},
props: ['textualDefinition'],
data () {

View File

@ -202,6 +202,7 @@ function compareModelItems (o1, o2) {
export default {
components: {
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue'),
ModelDetailsPane,
ItemStatePreview,
ItemDetails,

View File

@ -91,7 +91,7 @@ import WidgetSlotConfigPopup from '@/components/pagedesigner/widget-slot-config-
export default {
mixins: [PageDesigner],
components: {
'editor': () => import('@/components/config/controls/script-editor.vue'),
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue'),
OhChartPage,
PageSettings,
ChartDesigner,

View File

@ -136,7 +136,7 @@ const ConfigurableWidgets = {
export default {
mixins: [PageDesigner, HomeCards],
components: {
'editor': () => import('@/components/config/controls/script-editor.vue'),
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue'),
ConfigSheet,
ModelTab
},

View File

@ -135,7 +135,7 @@ import { compareItems } from '@/components/widgets/widget-order'
export default {
mixins: [PageDesigner],
components: {
'editor': () => import('@/components/config/controls/script-editor.vue'),
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue'),
OhLayoutPage,
PageSettings
},

View File

@ -137,7 +137,7 @@ import ConfigSheet from '@/components/config/config-sheet.vue'
export default {
mixins: [PageDesigner],
components: {
'editor': () => import('@/components/config/controls/script-editor.vue'),
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue'),
OhMapPage,
PageSettings,
ConfigSheet

View File

@ -142,6 +142,9 @@
<script>
export default {
components: {
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue')
},
data () {
return {
ready: false,

View File

@ -138,7 +138,7 @@ import ConfigSheet from '@/components/config/config-sheet.vue'
export default {
mixins: [PageDesigner],
components: {
'editor': () => import('@/components/config/controls/script-editor.vue'),
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue'),
OhPlanPage,
PageSettings,
ConfigSheet

View File

@ -104,7 +104,7 @@ const ConfigurableWidgets = { OhTabDefinition }
export default {
mixins: [PageDesigner],
components: {
'editor': () => import('@/components/config/controls/script-editor.vue'),
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue'),
PageSettings
},
props: ['createMode', 'uid'],

View File

@ -180,7 +180,6 @@ import SemanticsPicker from '@/components/tags/semantics-picker.vue'
import TagInput from '@/components/tags/tag-input.vue'
import RuleModulePopup from './rule-module-popup.vue'
import CronEditor from '@/components/config/controls/cronexpression-editor.vue'
import ModuleDescriptionSuggestions from './module-description-suggestions'
import RuleStatus from '@/components/rule/rule-status-mixin'
@ -191,7 +190,7 @@ export default {
components: {
SemanticsPicker,
TagInput,
'editor': () => import('@/components/config/controls/script-editor.vue')
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue')
},
props: ['ruleId', 'createMode', 'schedule'],
data () {
@ -587,27 +586,29 @@ export default {
this.currentModule = mod
this.currentModuleType = mod.type
this.cronExpression = mod.configuration.cronExpression
const popup = {
component: CronEditor
}
this.$f7router.navigate({
url: 'cron-edit',
route: {
path: 'cron-edit',
popup
import(/* webpackChunkName: "cronexpression-editor" */ '@/components/config/controls/cronexpression-editor.vue').then((c) => {
const popup = {
component: c.default
}
}, {
props: {
value: this.cronExpression
}
})
this.$f7router.navigate({
url: 'cron-edit',
route: {
path: 'cron-edit',
popup
}
}, {
props: {
value: this.cronExpression
}
})
this.$f7.once('cronEditorUpdate', this.updateCronExpression)
this.$f7.once('cronEditorClosed', () => {
this.$f7.off('cronEditorUpdate', this.updateCronExpression)
this.$nextTick(() => {
this.currentModule = null
this.currentModuleType = null
this.$f7.once('cronEditorUpdate', this.updateCronExpression)
this.$f7.once('cronEditorClosed', () => {
this.$f7.off('cronEditorUpdate', this.updateCronExpression)
this.$nextTick(() => {
this.currentModule = null
this.currentModuleType = null
})
})
})
},

View File

@ -128,6 +128,9 @@ import RuleStatus from '@/components/rule/rule-status-mixin'
export default {
mixins: [RuleStatus],
props: ['showScripts'],
components: {
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue')
},
data () {
return {
ready: false,

View File

@ -119,7 +119,7 @@ export default {
mixins: [RuleStatus, ModuleDescriptionSuggestions, DirtyMixin],
components: {
ScriptGeneralSettings,
'editor': () => import('@/components/config/controls/script-editor.vue'),
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue'),
'blockly-editor': () => import(/* webpackChunkName: "blockly-editor" */ './blockly-editor.vue')
},
props: ['ruleId', 'moduleId', 'createMode'],

View File

@ -82,6 +82,9 @@
import later from 'later-again'
export default {
components: {
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue')
},
data () {
return {
ready: false,

View File

@ -63,6 +63,9 @@
<script>
export default {
components: {
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue')
},
data () {
return {
ready: false,

View File

@ -117,6 +117,9 @@
<script>
export default {
components: {
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue')
},
data () {
return {
ready: false,

View File

@ -260,7 +260,7 @@ export default {
ChannelList,
ThingGeneralSettings,
ZWaveNetworkPopup,
'editor': () => import('@/components/config/controls/script-editor.vue')
'editor': () => import(/* webpackChunkName: "script-editor" */ '@/components/config/controls/script-editor.vue')
},
props: ['thingId'],
data () {

View File

@ -124,6 +124,9 @@ import thingStatus from '@/components/thing/thing-status-mixin'
export default {
mixins: [thingStatus],
components: {
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue')
},
data () {
return {
ready: false,