-
-
Notifications
You must be signed in to change notification settings - Fork 243
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replace Add-on Management UI with Add-on Store (#1158)
Depends on openhab/openhab-core#2405. This replaces the current section of the UI for managing add-ons with a completely new "store-like" interface. External data, like logos and detailed descriptions for distribution add-ons are fetched from well-known locations on the website or GitHub to provide a "store" look & feel. The add-on store is orgnanized around 4 categories: bindings, automation, UI, and others, with a separate search tab. Each category is splitted into subsections. The availability of these sections depend on the add-on services that are registered. The sections currently supports add-ons provided by the "karaf" & "marketplace" services, as provided by openhab/openhab-core#2405. Other add-on services should be supported as well. Signed-off-by: Yannick Schaus <[email protected]>
- Loading branch information
Showing
18 changed files
with
1,437 additions
and
79 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
export const AddonIcons = { | ||
automation: 'wand_stars', | ||
binding: 'circle_grid_hex_fill', | ||
persistence: 'download_circle', | ||
transformation: 'function', | ||
misc: 'rectangle_3_offgrid', | ||
ui: 'play_rectangle', | ||
voice: 'chat_bubble_2_fill' | ||
} | ||
|
||
export const ContentTypes = { | ||
'application/java-archive': 'Java Archive', | ||
'application/vnd.openhab.bundle': 'OSGi Bundle', | ||
'application/vnd.openhab.feature;type=karaf': 'Karaf Feature', | ||
'application/vnd.openhab.feature;type=karfile': 'Karaf KAR Archive', | ||
'application/vnd.openhab.ruletemplate': 'Rule Template', | ||
'application/vnd.openhab.uicomponent;type=widget': 'UI Component - Widget' | ||
} | ||
|
||
export const Formats = { | ||
'yaml_content': 'Inline YAML Code', | ||
'json_content': 'Inline JSON Code', | ||
'yaml_download_url': 'Linked YAML File', | ||
'json_download_url': 'Linked JSON File', | ||
'jar_download_url': 'Linked JAR file', | ||
'kar_download_url': 'Linked KAR file', | ||
'karaf': 'Karaf' | ||
} | ||
|
||
export const AddonStoreTabShortcuts = [ | ||
{ | ||
id: 'bindings', | ||
label: 'Bindings', | ||
icon: 'circle_grid_hex', | ||
subtitle: 'Connect and control hardware and online services' | ||
}, | ||
{ | ||
id: 'automation', | ||
label: 'Automation', | ||
icon: 'sparkles', | ||
subtitle: 'Scripting languages, templates and module types' | ||
}, | ||
{ | ||
id: 'ui', | ||
label: 'User Interfaces', | ||
icon: 'play_rectangle', | ||
subtitle: 'Community widgets & alternative frontends' | ||
}, | ||
{ | ||
id: 'other', | ||
label: 'Other Add-ons', | ||
icon: 'ellipsis', | ||
subtitle: 'System integrations, persistence, voice & more' | ||
} | ||
] | ||
|
||
export function compareAddons (a1, a2) { | ||
if (a1.installed && !a2.installed) return -1 | ||
if (a2.installed && !a1.installed) return 1 | ||
if (a1.verifiedAuthor && !a2.verifiedAuthor) return -1 | ||
if (a2.verifiedAuthor && !a1.verifiedAuthor) return 1 | ||
if (a2.properties && a2.properties) { | ||
if (a1.properties.like_count >= 0 && a2.properties.like_count >= 0 && | ||
a1.properties.like_count !== a2.properties.like_count) { | ||
return (a1.properties.like_count > a2.properties.like_count) ? -1 : 1 | ||
} | ||
|
||
if (a1.properties.views >= 0 && a2.properties.views >= 0 && | ||
a1.properties.views !== a2.properties.views) { | ||
return (a1.properties.views > a2.properties.views) ? -1 : 1 | ||
} | ||
} | ||
|
||
const nameOrId1 = a1.label || a1.id | ||
const nameOrId2 = a2.label || a2.name | ||
return nameOrId1.localeCompare(nameOrId2) | ||
} |
154 changes: 154 additions & 0 deletions
154
bundles/org.openhab.ui/web/src/components/addons/addon-card.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
<template> | ||
<f7-link | ||
v-if="addon" | ||
class="addon-card padding-right-half" :href="addon.id"> | ||
<div class="addon-card-headline"> | ||
<div>{{ headline || autoHeadline }}</div> | ||
</div> | ||
<div class="addon-card-title"> | ||
<div class="addon-card-title-after"> | ||
<f7-preloader v-if="addon.pending" color="blue" /> | ||
<f7-button v-else-if="addon.installed" class="install-button prevent-active-state-propagation" text="Remove" color="red" round small @click="buttonClicked" /> | ||
<f7-button v-else class="install-button prevent-active-state-propagation" :text="installActionText || 'Install'" color="blue" round small @click="buttonClicked" /> | ||
</div> | ||
<div class="addon-card-label"> | ||
{{ addon.label }} | ||
</div> | ||
<div v-if="addon.verifiedAuthor" class="addon-card-subtitle"> | ||
{{ addon.author }} | ||
<f7-icon v-if="addon.verifiedAuthor" size="15" :color="$f7.data.themeOptions.dark === 'dark' ? 'white' : 'blue'" f7="checkmark_seal_fill" style="margin-top: -3px;" /> | ||
</div> | ||
<div v-else-if="addon.properties && addon.properties.views" class="addon-card-subtitle"> | ||
<addon-stats-line :addon="addon" :iconSize="15" /> | ||
</div> | ||
</div> | ||
<div class="logo-square"> | ||
<f7-icon v-show="!logoLoaded" size="150" color="gray" :f7="addonIcon" class="card-default-icon" /> | ||
<img v-if="!logoError" class="lazy logo" :style="{ visibility: logoLoaded ? 'visible': 'hidden' }" ref="logo" :data-src="imageUrl"> | ||
</div> | ||
</f7-link> | ||
</template> | ||
|
||
<style lang="stylus"> | ||
.addon-card | ||
display flex | ||
flex-direction column | ||
align-items flex-start | ||
align-content flex-end | ||
color inherit | ||
scroll-snap-align center center | ||
padding 5px 0px 0px | ||
position relative | ||
margin-bottom 1rem | ||
.install-button | ||
// --f7-button-bg-color var(--f7-color-gray) | ||
--f7-button-text-transform uppercase | ||
--f7-button-bg-color var(--f7-list-item-border-color) | ||
.addon-card-headline | ||
text-transform uppercase | ||
color var(--f7-theme-color) | ||
font-size 11px | ||
font-weight 500 | ||
.addon-card-title | ||
height 3.4rem | ||
width 100% | ||
/* display flex | ||
justify-content space-between | ||
box-sizing border-box */ | ||
font-size var(--f7-timeline-item-title-font-size) // 21px | ||
font-weight var(--f7-list-media-item-title-font-weight) | ||
line-height 1.75 | ||
.addon-card-label | ||
text-overflow ellipsis | ||
overflow hidden | ||
white-space nowrap | ||
width calc(100% - 5rem) | ||
.addon-card-title-after | ||
.preloader-inner .preloader-inner-left, .preloader-inner .preloader-inner-right, .preloader-inner .preloader-inner-line | ||
margin-left inherit !important | ||
display flex | ||
float right | ||
align-self top | ||
min-width 70px | ||
justify-content center | ||
height var(--f7-button-small-height) | ||
--f7-preloader-size var(--f7-button-small-height) | ||
.addon-card-subtitle | ||
color var(--f7-list-item-after-text-color) | ||
font-size var(--f7-list-item-subtitle-font-size) // 21px | ||
font-weight var(--f7-list-item-subtitle-font-weight) | ||
line-height 1.75 | ||
&:after | ||
content ' ' | ||
display inline-block | ||
.logo-square | ||
position relative | ||
background #fff | ||
width 100% | ||
margin-top 5px | ||
// height 220px | ||
border 1px solid var(--f7-list-item-border-color) | ||
border-radius 5px | ||
display flex | ||
justify-content center | ||
align-items center | ||
&:after | ||
content ' ' | ||
display block | ||
padding-bottom 100% | ||
.card-default-icon | ||
opacity 0.2 | ||
position absolute | ||
.logo | ||
position absolute | ||
top 3px | ||
left 3px | ||
width calc(100% - 6px) | ||
height calc(100% - 6px) | ||
object-fit contain | ||
</style> | ||
|
||
<script> | ||
import { AddonIcons } from '@/assets/addon-store' | ||
import AddonStatsLine from './addon-stats-line.vue' | ||
export default { | ||
props: ['addon', 'headline', 'installActionText'], | ||
components: { | ||
AddonStatsLine | ||
}, | ||
data () { | ||
return { | ||
logoLoaded: false, | ||
logoError: false, | ||
addonIcon: null | ||
} | ||
}, | ||
computed: { | ||
autoHeadline () { | ||
if (this.addon.properties && this.addon.properties.like_count && this.addon.properties.like_count >= 20) return 'Top' | ||
if (this.addon.properties && this.addon.properties.views && this.addon.properties.views >= 1000) return 'Popular' | ||
if (this.addon.properties && this.addon.properties.posts_count && this.addon.properties.posts_count >= 15) return 'Hot' | ||
return '' | ||
}, | ||
imageUrl () { | ||
if (this.addon.imageLink) return this.addon.imageLink.replace(/^\/\//, 'https://') | ||
return 'https://www.openhab.org/logos/' + this.addon.id.substring(this.addon.id.indexOf('-') + 1) + '.png' | ||
} | ||
}, | ||
mounted () { | ||
this.addonIcon = AddonIcons[this.addon.type] | ||
this.$$(this.$refs.logo).once('lazy:loaded', (e) => { | ||
this.logoLoaded = true | ||
}) | ||
this.$$(this.$refs.logo).once('lazy:error', (e) => { | ||
this.logoError = true | ||
}) | ||
}, | ||
methods: { | ||
buttonClicked () { | ||
this.$emit('addonButtonClick', this.addon) | ||
} | ||
} | ||
} | ||
</script> |
Oops, something went wrong.