Browse Source
fix(settings): Add event search listener on mounted to guarantee function exists
fix(settings): Add event search listener on mounted to guarantee function exists
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>pull/44255/head
No known key found for this signature in database
GPG Key ID: 45FAE7268762B400
2 changed files with 3 additions and 414 deletions
@ -1,411 +0,0 @@ |
|||
<!-- |
|||
- @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> |
|||
- |
|||
- @author Julius Härtl <jus@bitgrid.net> |
|||
- |
|||
- @license GNU AGPL version 3 or any later version |
|||
- |
|||
- This program is free software: you can redistribute it and/or modify |
|||
- it under the terms of the GNU Affero General Public License as |
|||
- published by the Free Software Foundation, either version 3 of the |
|||
- License, or (at your option) any later version. |
|||
- |
|||
- This program is distributed in the hope that it will be useful, |
|||
- but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
- GNU Affero General Public License for more details. |
|||
- |
|||
- You should have received a copy of the GNU Affero General Public License |
|||
- along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
- |
|||
--> |
|||
|
|||
<template> |
|||
<NcContent app-name="settings" |
|||
:class="{ 'with-app-sidebar': app}"> |
|||
<!-- Categories & filters --> |
|||
<NcAppNavigation :class="{ 'icon-loading': loading }" |
|||
:aria-label="t('settings', 'Apps')"> |
|||
<template #list> |
|||
<NcAppNavigationItem id="app-category-your-apps" |
|||
:to="{ name: 'apps' }" |
|||
:exact="true" |
|||
icon="icon-category-installed" |
|||
:name="$options.APPS_SECTION_ENUM.installed" /> |
|||
<NcAppNavigationItem id="app-category-enabled" |
|||
:to="{ name: 'apps-category', params: { category: 'enabled' } }" |
|||
icon="icon-category-enabled" |
|||
:name="$options.APPS_SECTION_ENUM.enabled" /> |
|||
<NcAppNavigationItem id="app-category-disabled" |
|||
:to="{ name: 'apps-category', params: { category: 'disabled' } }" |
|||
icon="icon-category-disabled" |
|||
:name="$options.APPS_SECTION_ENUM.disabled" /> |
|||
<NcAppNavigationItem v-if="updateCount > 0" |
|||
id="app-category-updates" |
|||
:to="{ name: 'apps-category', params: { category: 'updates' } }" |
|||
icon="icon-download" |
|||
:name="$options.APPS_SECTION_ENUM.updates"> |
|||
<template #counter> |
|||
<NcCounterBubble>{{ updateCount }}</NcCounterBubble> |
|||
</template> |
|||
</NcAppNavigationItem> |
|||
<NcAppNavigationItem v-if="isSubscribed" |
|||
id="app-category-supported" |
|||
:to="{ name: 'apps-category', params: { category: 'supported' } }" |
|||
:name="$options.APPS_SECTION_ENUM.supported"> |
|||
<template #icon> |
|||
<IconStarShooting :size="20" /> |
|||
</template> |
|||
</NcAppNavigationItem> |
|||
<NcAppNavigationItem id="app-category-your-bundles" |
|||
:to="{ name: 'apps-category', params: { category: 'app-bundles' } }" |
|||
icon="icon-category-app-bundles" |
|||
:name="$options.APPS_SECTION_ENUM['app-bundles']" /> |
|||
|
|||
<NcAppNavigationSpacer /> |
|||
|
|||
<!-- App store categories --> |
|||
<template v-if="appstoreEnabled"> |
|||
<NcAppNavigationItem id="app-category-featured" |
|||
:to="{ name: 'apps-category', params: { category: 'featured' } }" |
|||
icon="icon-favorite" |
|||
:name="$options.APPS_SECTION_ENUM.featured" /> |
|||
|
|||
<NcAppNavigationItem v-for="cat in categories" |
|||
:key="'icon-category-' + cat.id" |
|||
:icon="'icon-category-' + cat.id" |
|||
:to="{ |
|||
name: 'apps-category', |
|||
params: { category: cat.id }, |
|||
}" |
|||
:name="cat.displayName" /> |
|||
</template> |
|||
|
|||
<NcAppNavigationItem id="app-developer-docs" |
|||
:name="t('settings', 'Developer documentation') + ' ↗'" |
|||
@click="openDeveloperDocumentation" /> |
|||
</template> |
|||
</NcAppNavigation> |
|||
|
|||
<!-- Apps list --> |
|||
<NcAppContent class="app-settings-content" |
|||
:class="{ 'icon-loading': loadingList }" |
|||
:page-heading="pageHeading"> |
|||
<AppList :category="category" :app="app" :search="searchQuery" /> |
|||
</NcAppContent> |
|||
|
|||
<!-- Selected app details --> |
|||
<NcAppSidebar v-if="id && app" |
|||
v-bind="appSidebar" |
|||
:class="{'app-sidebar--without-background': !appSidebar.background}" |
|||
@close="hideAppDetails"> |
|||
<template v-if="!appSidebar.background" #header> |
|||
<div class="app-sidebar-header__figure--default-app-icon icon-settings-dark" /> |
|||
</template> |
|||
|
|||
<template #description> |
|||
<!-- Featured/Supported badges --> |
|||
<AppLevelBadge :level="app.level" /> |
|||
<AppScore v-if="hasRating" :score="app.appstoreData.ratingOverall" /> |
|||
|
|||
<div class="app-version"> |
|||
<p>{{ app.version }}</p> |
|||
</div> |
|||
</template> |
|||
|
|||
<!-- Tab content --> |
|||
|
|||
<NcAppSidebarTab id="desc" |
|||
icon="icon-category-office" |
|||
:name="t('settings', 'Details')" |
|||
:order="0"> |
|||
<AppDetails :app="app" /> |
|||
</NcAppSidebarTab> |
|||
<NcAppSidebarTab v-if="app.appstoreData && app.releases[0].translations.en.changelog" |
|||
id="desca" |
|||
icon="icon-category-organization" |
|||
:name="t('settings', 'Changelog')" |
|||
:order="1"> |
|||
<div v-for="release in app.releases" :key="release.version" class="app-sidebar-tabs__release"> |
|||
<h2>{{ release.version }}</h2> |
|||
<Markdown v-if="changelog(release)" :min-heading="3" :text="changelog(release)" /> |
|||
</div> |
|||
</NcAppSidebarTab> |
|||
</NcAppSidebar> |
|||
</NcContent> |
|||
</template> |
|||
|
|||
<script> |
|||
import { subscribe, unsubscribe } from '@nextcloud/event-bus' |
|||
import Vue from 'vue' |
|||
import VueLocalStorage from 'vue-localstorage' |
|||
|
|||
import NcAppContent from '@nextcloud/vue/dist/Components/NcAppContent.js' |
|||
import NcAppNavigation from '@nextcloud/vue/dist/Components/NcAppNavigation.js' |
|||
import NcAppNavigationItem from '@nextcloud/vue/dist/Components/NcAppNavigationItem.js' |
|||
import NcAppNavigationSpacer from '@nextcloud/vue/dist/Components/NcAppNavigationSpacer.js' |
|||
import NcAppSidebar from '@nextcloud/vue/dist/Components/NcAppSidebar.js' |
|||
import NcAppSidebarTab from '@nextcloud/vue/dist/Components/NcAppSidebarTab.js' |
|||
import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js' |
|||
import NcContent from '@nextcloud/vue/dist/Components/NcContent.js' |
|||
import IconStarShooting from 'vue-material-design-icons/StarShooting.vue' |
|||
|
|||
import AppList from '../components/AppList.vue' |
|||
import AppDetails from '../components/AppDetails.vue' |
|||
import AppManagement from '../mixins/AppManagement.js' |
|||
import AppLevelBadge from '../components/AppList/AppLevelBadge.vue' |
|||
import AppScore from '../components/AppList/AppScore.vue' |
|||
import Markdown from '../components/Markdown.vue' |
|||
|
|||
import { APPS_SECTION_ENUM } from './../constants/AppsConstants.js' |
|||
import { loadState } from '@nextcloud/initial-state' |
|||
|
|||
Vue.use(VueLocalStorage) |
|||
|
|||
const appstoreEnabled = loadState('settings', 'appstoreEnabled') |
|||
const developerDocumentation = loadState('settings', 'appstoreDeveloperDocs') |
|||
|
|||
export default { |
|||
name: 'Apps', |
|||
APPS_SECTION_ENUM, |
|||
components: { |
|||
NcAppContent, |
|||
AppDetails, |
|||
AppList, |
|||
AppLevelBadge, |
|||
IconStarShooting, |
|||
NcAppNavigation, |
|||
NcAppNavigationItem, |
|||
NcAppNavigationSpacer, |
|||
NcCounterBubble, |
|||
AppScore, |
|||
NcAppSidebar, |
|||
NcAppSidebarTab, |
|||
NcContent, |
|||
Markdown, |
|||
}, |
|||
|
|||
mixins: [AppManagement], |
|||
|
|||
props: { |
|||
category: { |
|||
type: String, |
|||
default: 'installed', |
|||
}, |
|||
id: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
}, |
|||
|
|||
data() { |
|||
return { |
|||
searchQuery: '', |
|||
screenshotLoaded: false, |
|||
} |
|||
}, |
|||
|
|||
computed: { |
|||
appstoreEnabled() { |
|||
return appstoreEnabled |
|||
}, |
|||
pageHeading() { |
|||
if (this.$options.APPS_SECTION_ENUM[this.category]) { |
|||
return this.$options.APPS_SECTION_ENUM[this.category] |
|||
} |
|||
const category = this.$store.getters.getCategoryById(this.category) |
|||
return category.displayName |
|||
}, |
|||
loading() { |
|||
return this.$store.getters.loading('categories') |
|||
}, |
|||
loadingList() { |
|||
return this.$store.getters.loading('list') |
|||
}, |
|||
app() { |
|||
return this.apps.find(app => app.id === this.id) |
|||
}, |
|||
categories() { |
|||
return this.$store.getters.getCategories |
|||
}, |
|||
apps() { |
|||
return this.$store.getters.getAllApps |
|||
}, |
|||
updateCount() { |
|||
return this.$store.getters.getUpdateCount |
|||
}, |
|||
|
|||
hasRating() { |
|||
return this.app.appstoreData && this.app.appstoreData.ratingNumOverall > 5 |
|||
}, |
|||
|
|||
// sidebar app binding |
|||
appSidebar() { |
|||
const authorName = (xmlNode) => { |
|||
if (xmlNode['@value']) { |
|||
// Complex node (with email or homepage attribute) |
|||
return xmlNode['@value'] |
|||
} |
|||
|
|||
// Simple text node |
|||
return xmlNode |
|||
} |
|||
|
|||
const author = Array.isArray(this.app.author) |
|||
? this.app.author.map(authorName).join(', ') |
|||
: authorName(this.app.author) |
|||
const license = t('settings', '{license}-licensed', { license: ('' + this.app.licence).toUpperCase() }) |
|||
|
|||
const subname = t('settings', 'by {author}\n{license}', { author, license }) |
|||
|
|||
return { |
|||
background: this.app.screenshot && this.screenshotLoaded |
|||
? this.app.screenshot |
|||
: this.app.preview, |
|||
compact: !(this.app.screenshot && this.screenshotLoaded), |
|||
name: this.app.name, |
|||
subname, |
|||
} |
|||
}, |
|||
changelog() { |
|||
return (release) => release.translations.en.changelog |
|||
}, |
|||
/** |
|||
* Check if the current instance has a support subscription from the Nextcloud GmbH |
|||
*/ |
|||
isSubscribed() { |
|||
// For customers of the Nextcloud GmbH the app level will be set to `300` for apps that are supported in their subscription |
|||
return this.apps.some(app => app.level === 300) |
|||
}, |
|||
}, |
|||
|
|||
watch: { |
|||
category() { |
|||
this.searchQuery = '' |
|||
}, |
|||
|
|||
app() { |
|||
this.screenshotLoaded = false |
|||
if (this.app?.releases && this.app?.screenshot) { |
|||
const image = new Image() |
|||
image.onload = () => { |
|||
this.screenshotLoaded = true |
|||
} |
|||
image.src = this.app.screenshot |
|||
} |
|||
}, |
|||
}, |
|||
|
|||
beforeMount() { |
|||
this.$store.dispatch('getCategories', { shouldRefetchCategories: true }) |
|||
this.$store.dispatch('getAllApps') |
|||
this.$store.dispatch('getGroups', { offset: 0, limit: 5 }) |
|||
}, |
|||
|
|||
mounted() { |
|||
subscribe('nextcloud:unified-search.search', this.setSearch) |
|||
subscribe('nextcloud:unified-search.reset', this.resetSearch) |
|||
}, |
|||
beforeDestroy() { |
|||
unsubscribe('nextcloud:unified-search.search', this.setSearch) |
|||
unsubscribe('nextcloud:unified-search.reset', this.resetSearch) |
|||
}, |
|||
|
|||
methods: { |
|||
setSearch({ query }) { |
|||
this.searchQuery = query |
|||
}, |
|||
resetSearch() { |
|||
this.searchQuery = '' |
|||
}, |
|||
|
|||
hideAppDetails() { |
|||
this.$router.push({ |
|||
name: 'apps-category', |
|||
params: { category: this.category }, |
|||
}) |
|||
}, |
|||
openDeveloperDocumentation() { |
|||
window.open(developerDocumentation) |
|||
}, |
|||
}, |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.app-sidebar::v-deep { |
|||
&:not(.app-sidebar--without-background) { |
|||
// with full screenshot, let's fill the figure |
|||
:not(.app-sidebar-header--compact) .app-sidebar-header__figure { |
|||
background-size: cover; |
|||
} |
|||
// revert sidebar app icon so it is black |
|||
.app-sidebar-header--compact .app-sidebar-header__figure { |
|||
background-size: 32px; |
|||
|
|||
filter: var(--background-invert-if-bright); |
|||
} |
|||
} |
|||
|
|||
.app-sidebar-header__description { |
|||
.app-version { |
|||
padding-left: 10px; |
|||
} |
|||
} |
|||
|
|||
// default icon slot styling |
|||
&.app-sidebar--without-background { |
|||
.app-sidebar-header__figure { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
&--default-app-icon { |
|||
width: 32px; |
|||
height: 32px; |
|||
background-size: 32px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// TODO: migrate to components |
|||
.app-sidebar-header__desc { |
|||
// allow multi line subtitle for the license |
|||
.app-sidebar-header__subtitle { |
|||
overflow: visible !important; |
|||
height: auto; |
|||
white-space: normal !important; |
|||
line-height: 16px; |
|||
} |
|||
} |
|||
|
|||
.app-sidebar-header__action { |
|||
// align with tab content |
|||
margin: 0 20px; |
|||
input { |
|||
margin: 3px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Align the appNavigation toggle with the apps header toolbar |
|||
.app-navigation::v-deep button.app-navigation-toggle { |
|||
top: 8px; |
|||
right: -8px; |
|||
} |
|||
|
|||
.app-sidebar-tabs__release { |
|||
h2 { |
|||
border-bottom: 1px solid var(--color-border); |
|||
} |
|||
|
|||
// Overwrite changelog heading styles |
|||
::v-deep { |
|||
h3 { |
|||
font-size: 20px; |
|||
} |
|||
h4 { |
|||
font-size: 17px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue