Skip to content

Commit 794832f

Browse files
committed
DRY page-type handling
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
1 parent b84ffb9 commit 794832f

File tree

5 files changed

+74
-65
lines changed

5 files changed

+74
-65
lines changed

bundles/org.openhab.ui/web/src/components/developer/developer-sidebar.vue

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,7 @@ import SearchResults from './search-results.vue'
636636
import ExpressionTester from './expression-tester.vue'
637637
import ClipboardIcon from '@/components/util/clipboard-icon.vue'
638638
639+
import PageType from '@/pages/page-type-mixin'
639640
import RuleStatus from '@/components/rule/rule-status-mixin'
640641
import ThingStatus from '@/components/thing/thing-status-mixin'
641642
import cloneDeep from 'lodash/cloneDeep'
@@ -645,7 +646,7 @@ import * as api from '@/api'
645646
import { showToast } from '@/js/dialog-promises'
646647
647648
export default {
648-
mixins: [RuleStatus, ThingStatus],
649+
mixins: [RuleStatus, ThingStatus, PageType],
649650
components: {
650651
ClipboardIcon,
651652
Item,
@@ -687,15 +688,6 @@ export default {
687688
newCollectionName: '',
688689
sseEvents: [],
689690
openedItem: null,
690-
pageTypes: [
691-
{ type: 'sitemap', label: 'Sitemap', componentType: 'Sitemap', icon: 'menu' },
692-
{ type: 'layout', label: 'Layout', componentType: 'oh-layout-page', icon: 'rectangle_grid_2x2' },
693-
{ type: 'home', label: 'Home', componentType: 'oh-home-page', icon: 'house' },
694-
{ type: 'tabs', label: 'Tabbed', componentType: 'oh-tabs-page', icon: 'squares_below_rectangle' },
695-
{ type: 'map', label: 'Map', componentType: 'oh-map-page', icon: 'map' },
696-
{ type: 'plan', label: 'Floor plan', componentType: 'oh-plan-page', icon: 'square_stack_3d_up' },
697-
{ type: 'chart', label: 'Chart', componentType: 'oh-chart-page', icon: 'graph_square' }
698-
],
699691
testExpression: '',
700692
addThingAutocomplete: null,
701693
theme
@@ -1023,9 +1015,6 @@ export default {
10231015
load()
10241016
}
10251017
},
1026-
getPageType(page) {
1027-
return this.pageTypes.find((t) => t.componentType === page.component)
1028-
},
10291018
showItem(evt, item) {
10301019
evt.cancelBubble = true
10311020
if (this.$$(evt.target).closest('.itemlist-actions').length) return

bundles/org.openhab.ui/web/src/components/developer/search-results.vue

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,10 @@
388388

389389
<script>
390390
import ClipboardIcon from '@/components/util/clipboard-icon.vue'
391+
import PageType from '@/pages/page-type-mixin'
391392
392393
export default {
394+
mixins: [PageType],
393395
components: {
394396
ClipboardIcon
395397
},
@@ -408,16 +410,7 @@ export default {
408410
rules: 'wand_stars',
409411
pages: 'tv'
410412
},
411-
expandedTypes: {},
412-
pageTypes: [
413-
{ type: 'sitemap', label: 'Sitemap', componentType: 'Sitemap', icon: 'menu' },
414-
{ type: 'layout', label: 'Layout', componentType: 'oh-layout-page', icon: 'rectangle_grid_2x2' },
415-
{ type: 'home', label: 'Home', componentType: 'oh-home-page', icon: 'house' },
416-
{ type: 'tabs', label: 'Tabbed', componentType: 'oh-tabs-page', icon: 'squares_below_rectangle' },
417-
{ type: 'map', label: 'Map', componentType: 'oh-map-page', icon: 'map' },
418-
{ type: 'plan', label: 'Floor plan', componentType: 'oh-plan-page', icon: 'square_stack_3d_up' },
419-
{ type: 'chart', label: 'Chart', componentType: 'oh-chart-page', icon: 'graph_square' }
420-
]
413+
expandedTypes: {}
421414
}
422415
},
423416
computed: {
@@ -482,9 +475,6 @@ export default {
482475
showingAll(type) {
483476
return this.expandedTypes[type] || this.searchResults[type].length <= 5
484477
},
485-
getPageType(page) {
486-
return this.pageTypes.find((t) => t.componentType === page.component)
487-
},
488478
togglePin(evt, type, obj, keyName) {
489479
evt.cancelBubble = true
490480
if (evt.target.tagName.toLowerCase() === 'i') return
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import type * as api from '@/api'
2+
import type { DeepReadonly } from 'vue'
3+
4+
type PageType = {
5+
type: string
6+
label: string
7+
icon: string
8+
}
9+
10+
const pageTypes: Record<string, PageType> = {
11+
'Sitemap': { type: 'sitemap', label: 'Sitemap', icon: 'f7:menu' },
12+
'oh-layout-page': { type: 'layout', label: 'Layout', icon: 'f7:rectangle_grid_2x2' },
13+
'oh-home-page': { type: 'home', label: 'Home', icon: 'f7:house' },
14+
'oh-tabs-page': { type: 'tabs', label: 'Tabbed', icon: 'f7:squares_below_rectangle' },
15+
'oh-map-page': { type: 'map', label: 'Map', icon: 'f7:map' },
16+
'oh-plan-page': { type: 'plan', label: 'Floor plan', icon: 'f7:square_stack_3d_up' },
17+
'oh-chart-page': { type: 'chart', label: 'Chart', icon: 'f7:graph_square' }
18+
}
19+
20+
const unknownPageType: PageType = { type: 'unknown', label: 'Unknown Page Type!', icon: 'f7:question_circle' }
21+
22+
/**
23+
* Returns the PageType for the given page, or a default "unknown" PageType if the page type is unknown.
24+
* The page type is determined by matching the page's component type against the known page types.
25+
* @param page
26+
* @returns The PageType for the given page, or a default "unknown" PageType if the page type is unknown.
27+
*/
28+
export function getPageType(page?: api.RootUiComponent | DeepReadonly<api.RootUiComponent> | null): PageType {
29+
if (!page) return unknownPageType
30+
return pageTypes[page.component] || unknownPageType
31+
}
32+
33+
/**
34+
* Returns the icon for the given page, or a default icon if the page type is unknown.
35+
* The page type is determined by matching the page's component type against the known page types.
36+
*
37+
* Special cases:
38+
* - If the page is null or undefined, it is considered an unknown page type and gets a question mark icon.
39+
* - If the page has a uid of "overview", it is considered the overview page and gets a house icon.
40+
* - If the page has a config with an icon, that icon is used.
41+
*
42+
* @param page
43+
* @returns The icon for the given page, or a default icon if the page type is unknown.
44+
*/
45+
export function getPageIcon(page?: api.RootUiComponent | DeepReadonly<api.RootUiComponent> | null): string {
46+
if (!page) return unknownPageType.icon
47+
if (page.uid === 'overview') return 'f7:house'
48+
if (page.config && page.config.icon) return (page.config.icon as string)
49+
return getPageType(page).icon
50+
}
51+
52+
const PageType = {
53+
methods: {
54+
getPageType(page: api.RootUiComponent | DeepReadonly<api.RootUiComponent> | null) {
55+
return getPageType(page)
56+
},
57+
getPageIcon(page: api.RootUiComponent | DeepReadonly<api.RootUiComponent> | null) {
58+
return getPageIcon(page)
59+
}
60+
}
61+
}
62+
63+
export default PageType

bundles/org.openhab.ui/web/src/pages/page/page-view.vue

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ import { useWidgetExpression } from '@/components/widgets/useWidgetExpression.ts
9898
import { useViewArea } from '@/js/composables/useViewArea.ts'
9999
100100
import * as api from '@/api'
101+
import { getPageType } from '@/pages/page-type-mixin'
101102
102103
import OhLayoutPage from '@/components/widgets/layout/oh-layout-page.vue'
103104
import EmptyStatePlaceholder from '@/components/empty-state-placeholder.vue'
@@ -170,7 +171,7 @@ const context = computed(() => ({
170171
vars: Object.assign(vars.value, page.value?.config?.defineVars ?? {}, props.defineVars ?? {}),
171172
store: statesStore.trackedItems
172173
}))
173-
const pageType = computed(() => (page.value ? getPageType(page.value) : null))
174+
const pageType = computed(() => getPageType(page.value).type)
174175
const pageLabel = computed(() => page.value?.config?.label)
175176
const editable = computed(() => page.value && userStore.isAdmin())
176177
const fullscreenIcon = computed(() => {
@@ -199,24 +200,6 @@ const onTabChange = (idx: number) => {
199200
// @ts-expect-error - url is not typed as part of the router
200201
props.f7router.url = url
201202
}
202-
const getPageType = (page: api.RootUiComponent | DeepReadonly<api.RootUiComponent>) => {
203-
if (!page) return null
204-
switch (page.component) {
205-
case 'oh-layout-page':
206-
return 'layout'
207-
case 'oh-map-page':
208-
return 'map'
209-
case 'oh-tabs-page':
210-
return 'tabs'
211-
case 'oh-plan-page':
212-
return 'plan'
213-
case 'oh-chart-page':
214-
return 'chart'
215-
default:
216-
console.warn('Unknown page type!')
217-
return 'unknown'
218-
}
219-
}
220203
const tabContext = (tab: api.UiComponent) => {
221204
const tabPage: DeepReadonly<api.RootUiComponent> | string = tab.config.page
222205
? componentStore.page((tab.config.page as string).replace('page:', ''))!
@@ -291,7 +274,7 @@ const editPage = () => {
291274
onClick: () => {
292275
const tabPageUid = (page.value!.slots.default![currentTab.value]!.config.page as string).replace('page:', '')
293276
const tabPage = componentStore.page(tabPageUid)!
294-
const tabPageType = getPageType(tabPage)
277+
const tabPageType = getPageType(tabPage).type
295278
props.f7router.navigate('/settings/pages/' + tabPageType + '/' + tabPageUid)
296279
}
297280
}

bundles/org.openhab.ui/web/src/pages/settings/pages/pages-list.vue

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,10 @@ import { f7, theme } from 'framework7-vue'
171171
172172
import { useLastSearchQueryStore } from '@/js/stores/useLastSearchQueryStore'
173173
import { showToast } from '@/js/dialog-promises'
174+
import PageType from '@/pages/page-type-mixin'
174175
175176
export default {
177+
mixins: [PageType],
176178
props: {
177179
f7router: Object
178180
},
@@ -187,16 +189,7 @@ export default {
187189
pages: [],
188190
selectedItems: [],
189191
groupBy: 'alphabetical',
190-
showCheckboxes: false,
191-
pageTypes: [
192-
{ type: 'sitemap', label: 'Sitemap', componentType: 'Sitemap', icon: 'f7:menu' },
193-
{ type: 'layout', label: 'Layout', componentType: 'oh-layout-page', icon: 'f7:rectangle_grid_2x2' },
194-
{ type: 'home', label: 'Home', componentType: 'oh-home-page', icon: 'f7:house' },
195-
{ type: 'tabs', label: 'Tabbed', componentType: 'oh-tabs-page', icon: 'f7:squares_below_rectangle' },
196-
{ type: 'map', label: 'Map', componentType: 'oh-map-page', icon: 'f7:map' },
197-
{ type: 'plan', label: 'Floor plan', componentType: 'oh-plan-page', icon: 'f7:square_stack_3d_up' },
198-
{ type: 'chart', label: 'Chart', componentType: 'oh-chart-page', icon: 'f7:graph_square' }
199-
]
192+
showCheckboxes: false
200193
}
201194
},
202195
computed: {
@@ -308,15 +301,6 @@ export default {
308301
this.selectedItems.push(itemName)
309302
}
310303
},
311-
getPageType(page) {
312-
return this.pageTypes.find((t) => t.componentType === page.component)
313-
},
314-
getPageIcon(page) {
315-
if (page.uid === 'overview') return 'f7:house'
316-
if (page.config && page.config.icon) return page.config.icon
317-
const pageType = this.pageTypes.find((t) => t.componentType === page.component)
318-
return pageType ? pageType.icon : 'f7:tv'
319-
},
320304
removeSelected() {
321305
const vm = this
322306

0 commit comments

Comments
 (0)