aboutsummaryrefslogtreecommitdiffstats
path: root/apps/updatenotification
diff options
context:
space:
mode:
Diffstat (limited to 'apps/updatenotification')
-rw-r--r--apps/updatenotification/src/components/UpdateNotification.vue252
1 files changed, 127 insertions, 125 deletions
diff --git a/apps/updatenotification/src/components/UpdateNotification.vue b/apps/updatenotification/src/components/UpdateNotification.vue
index 88ea8e50791..c8374a12195 100644
--- a/apps/updatenotification/src/components/UpdateNotification.vue
+++ b/apps/updatenotification/src/components/UpdateNotification.vue
@@ -7,13 +7,15 @@
</NcNoteCard>
<p>
+ <!-- eslint-disable-next-line vue/no-v-html -->
<span v-html="newVersionAvailableString" /><br>
<span v-if="!isListFetched" class="icon icon-loading-small" />
+ <!-- eslint-disable-next-line vue/no-v-html -->
<span v-html="statusText" />
</p>
<template v-if="missingAppUpdates.length">
- <h3 @click="toggleHideMissingUpdates">
+ <h3 class="clickable" @click="toggleHideMissingUpdates">
{{ t('updatenotification', 'Apps missing compatible version') }}
<span v-if="!hideMissingUpdates" class="icon icon-triangle-n" />
<span v-if="hideMissingUpdates" class="icon icon-triangle-s" />
@@ -26,7 +28,7 @@
</template>
<template v-if="availableAppUpdates.length">
- <h3 @click="toggleHideAvailableUpdates">
+ <h3 class="clickable" @click="toggleHideAvailableUpdates">
{{ t('updatenotification', 'Apps with compatible version') }}
<span v-if="!hideAvailableUpdates" class="icon icon-triangle-n" />
<span v-if="hideAvailableUpdates" class="icon icon-triangle-s" />
@@ -56,14 +58,26 @@
<span v-if="updaterEnabled && !webUpdaterEnabled">
{{ t('updatenotification', 'Please use the command line updater to update.') }}
</span>
- <div v-if="whatsNew" class="whatsNew">
- <div class="toggleWhatsNew">
- <a v-click-outside="hideMenu" class="button" @click="toggleMenu">{{ t('updatenotification', 'What\'s new?') }}</a>
- <div class="popovermenu" :class="{ 'menu-center': true, open: openedWhatsNew }">
- <NcPopoverMenu :menu="whatsNew" />
- </div>
- </div>
- </div>
+ <NcActions v-if="whatsNewData || changelogURL"
+ :force-menu="true"
+ :menu-title="t('updatenotification', 'What\'s new?')"
+ type="tertiary">
+ <template #icon>
+ <IconNewBox :size="20" />
+ </template>
+ <template #default>
+ <NcActionCaption v-for="changes,index in whatsNewData" :key="index" :title="changes" />
+ <NcActionLink v-if="changelogURL"
+ :href="changelogURL"
+ close-after-click
+ target="_blank">
+ {{ t('updatenotification', 'View changelog') }}
+ <template #icon>
+ <IconLink :size="20" />
+ </template>
+ </NcActionLink>
+ </template>
+ </NcActions>
</div>
</template>
<template v-else-if="!isUpdateChecked">
@@ -81,61 +95,80 @@
</template>
</div>
- <div>
- {{ t('updatenotification', 'You can change the update channel below which also affects the apps management page. E.g. after switching to the beta channel, beta app updates will be offered to you in the apps management page.') }}
+ <h3>{{ t('updatenotification', 'Update channel') }}</h3>
+ <p class="inlineblock">
+ {{ t('updatenotification', 'Changing the update channel also affects the apps management page. E.g. after switching to the beta channel, beta app updates will be offered to you in the apps management page.') }}
+ </p>
+ <div class="update-channel-selector">
+ <span>{{ t('updatenotification', 'Current update channel:') }}</span>
+ <NcActions :force-menu="true"
+ :menu-title="localizedChannelName"
+ type="tertiary">
+ <template #icon>
+ <IconChevronDown :size="20" />
+ </template>
+ <template #default>
+ <!-- TODO use NcActionRadio if it provides long text, e.g. subtitle -->
+ <NcActionButton v-for="channel,index in channelList"
+ :key="index"
+ :aria-checked="channel.active ? 'true' : 'false'"
+ :aria-label="channel.text"
+ :disabled="!!channel.disabled"
+ :icon="channel.icon"
+ :name="channel.text"
+ class="update-channel-action"
+ close-after-click
+ role="menuitemradio"
+ @click="channel.action">
+ {{ channel.longtext }}
+ </NcActionButton>
+ </template>
+ </NcActions>
</div>
-
- <h3 class="update-channel-selector">
- {{ t('updatenotification', 'Update channel:') }}
- <div v-click-outside="closeUpdateChannelMenu" class="update-menu">
- <span class="icon-update-menu" @click="toggleUpdateChannelMenu">
- {{ localizedChannelName }}
- <span class="icon-triangle-s" />
- </span>
- <div class="popovermenu menu menu-center" :class="{ 'show-menu': openedUpdateChannelMenu}">
- <NcPopoverMenu :menu="channelList" />
- </div>
- </div>
- </h3>
- <span id="channel_save_msg" class="msg" /><br>
<p>
<em>{{ t('updatenotification', 'You can always update to a newer version. But you can never downgrade to a more stable version.') }}</em><br>
+ <!-- eslint-disable-next-line vue/no-v-html -->
<em v-html="noteDelayedStableString" />
</p>
- <p id="oca_updatenotification_groups">
- {{ t('updatenotification', 'Notify members of the following groups about available updates:') }}
- <NcSelect v-model="notifyGroups"
- :options="groups"
- :multiple="true"
- label="displayname"
- :loading="loadingGroups"
- :close-on-select="false"
- @search="searchGroup">
- <template #no-options>
- {{ t('updatenotification', 'No groups') }}
- </template>
- </NcSelect>
- <br>
+ <h4>{{ t('updatenotification', 'Notify members of the following groups about available updates:') }}</h4>
+ <NcSelect v-model="notifyGroups"
+ :options="groups"
+ :multiple="true"
+ label="displayname"
+ :loading="loadingGroups"
+ :close-on-select="false"
+ @search="searchGroup">
+ <template #no-options>
+ {{ t('updatenotification', 'No groups') }}
+ </template>
+ </NcSelect>
+ <p>
<em v-if="currentChannel === 'daily' || currentChannel === 'git'">{{ t('updatenotification', 'Only notifications for app updates are available.') }}</em>
<em v-if="currentChannel === 'daily'">{{ t('updatenotification', 'The selected update channel makes dedicated notifications for the server obsolete.') }}</em>
- <em v-if="currentChannel === 'git'">{{ t('updatenotification', 'The selected update channel does not support updates of the server.') }}</em>
+ <em v-else-if="currentChannel === 'git'">{{ t('updatenotification', 'The selected update channel does not support updates of the server.') }}</em>
</p>
</NcSettingsSection>
</template>
<script>
+import { showSuccess } from '@nextcloud/dialogs'
+import { loadState } from '@nextcloud/initial-state'
+import { getLoggerBuilder } from '@nextcloud/logger'
import { generateUrl, getRootUrl, generateOcsUrl } from '@nextcloud/router'
-import NcPopoverMenu from '@nextcloud/vue/dist/Components/NcPopoverMenu.js'
+
+import axios from '@nextcloud/axios'
+import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
+import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
+import NcActionCaption from '@nextcloud/vue/dist/Components/NcActionCaption.js'
+import NcActionLink from '@nextcloud/vue/dist/Components/NcActionLink.js'
+import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
import NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection.js'
-import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
-import ClickOutside from 'vue-click-outside'
-import axios from '@nextcloud/axios'
-import { loadState } from '@nextcloud/initial-state'
-import { showSuccess } from '@nextcloud/dialogs'
+import IconChevronDown from 'vue-material-design-icons/ChevronDown.vue'
+import IconLink from 'vue-material-design-icons/Link.vue'
+import IconNewBox from 'vue-material-design-icons/NewBox.vue'
import debounce from 'debounce'
-import { getLoggerBuilder } from '@nextcloud/logger'
const logger = getLoggerBuilder()
.setApp('updatenotification')
@@ -145,13 +178,16 @@ const logger = getLoggerBuilder()
export default {
name: 'UpdateNotification',
components: {
+ IconChevronDown,
+ IconLink,
+ IconNewBox,
+ NcActions,
+ NcActionButton,
+ NcActionCaption,
+ NcActionLink,
+ NcNoteCard,
NcSelect,
- NcPopoverMenu,
NcSettingsSection,
- NcNoteCard,
- },
- directives: {
- ClickOutside,
},
data() {
return {
@@ -224,26 +260,6 @@ export default {
: n('updatenotification', '<strong>%n</strong> app has no compatible version for this Nextcloud version available.', '<strong>%n</strong> apps have no compatible version for this Nextcloud version available.', this.missingAppUpdates.length)
},
- whatsNew() {
- if (this.whatsNewData.length === 0) {
- return null
- }
- const whatsNew = []
- for (const i in this.whatsNewData) {
- whatsNew[i] = { icon: 'icon-checkmark', longtext: this.whatsNewData[i] }
- }
- if (this.changelogURL) {
- whatsNew.push({
- href: this.changelogURL,
- text: t('updatenotification', 'View changelog'),
- icon: 'icon-link',
- target: '_blank',
- action: '',
- })
- }
- return whatsNew
- },
-
channelList() {
const channelList = []
@@ -277,6 +293,7 @@ export default {
text: this.currentChannel,
icon: 'icon-rename',
active: true,
+ action: () => {},
})
}
@@ -431,24 +448,12 @@ export default {
this.openedUpdateChannelMenu = false
},
- toggleUpdateChannelMenu() {
- this.openedUpdateChannelMenu = !this.openedUpdateChannelMenu
- },
toggleHideMissingUpdates() {
this.hideMissingUpdates = !this.hideMissingUpdates
},
toggleHideAvailableUpdates() {
this.hideAvailableUpdates = !this.hideAvailableUpdates
},
- toggleMenu() {
- this.openedWhatsNew = !this.openedWhatsNew
- },
- closeUpdateChannelMenu() {
- this.openedUpdateChannelMenu = false
- },
- hideMenu() {
- this.openedWhatsNew = false
- },
},
}
</script>
@@ -459,6 +464,10 @@ export default {
max-width: 900px;
}
+ .topMargin {
+ margin-top: 15px;
+ }
+
div.update,
p:not(.inlineblock) {
margin-bottom: 25px;
@@ -467,17 +476,23 @@ export default {
margin-top: 25px;
}
h3 {
- cursor: pointer;
- .icon {
+ &.clickable {
cursor: pointer;
+ .icon {
+ cursor: pointer;
+ }
}
&:first-of-type {
margin-top: 0;
}
- &.update-channel-selector {
- display: inline-block;
- cursor: inherit;
- }
+ }
+ h4 {
+ margin-block-end: 0.7rem;
+ }
+ .update-channel-selector {
+ display: flex;
+ align-items: center;
+ gap: 12px;
}
.icon {
display: inline-block;
@@ -486,20 +501,6 @@ export default {
.icon-triangle-s, .icon-triangle-n {
opacity: 0.5;
}
- .whatsNew {
- display: inline-block;
- }
- .toggleWhatsNew {
- position: relative;
- }
- .popovermenu {
- p {
- margin-bottom: 0;
- width: 100%;
- }
- margin-top: 5px;
- width: 300px;
- }
.applist {
margin-bottom: 25px;
}
@@ -518,32 +519,33 @@ export default {
opacity: 1;
}
}
- .popovermenu {
- display: none;
- top: 28px;
- &.show-menu {
- display: block;
- }
- }
}
}
</style>
<style lang="scss">
- /* override needed to make menu wider */
- #updatenotification .popovermenu {
- p {
- margin-top: 5px;
- width: 100%;
- }
- margin-top: 5px;
- width: 300px;
+// Make current selected update channel visually visible, remove if NcActionRadio is used
+.update-channel-action[aria-checked=true] {
+ border-inline-start: 4px solid var(--color-primary-element);
+
+ &:hover, &:focus-within {
+ background-color: var(--color-primary-element-light-hover);
}
+
+ button {
+ background-color: var(--color-primary-element-light);
+ color: var(--color-primary-element-light-text);
+ }
+}
+// Ensure outline for focus-visible works even with background color of selected channel
+.update-channel-action[aria-checked] {
+ margin-block: 2px;
+}
+
+#updatenotification {
/* override needed to replace yellow hover state with a dark one */
- #updatenotification .update-menu .icon-star:hover,
- #updatenotification .update-menu .icon-star:focus {
+ .update-menu .icon-star:hover,
+ .update-menu .icon-star:focus {
background-image: var(--icon-starred);
}
- #updatenotification .topMargin {
- margin-top: 15px;
- }
+}
</style>