feat(frontend): add Atom feed settings page and notifications discovery (#2760)
This commit is contained in:
parent
6b14307896
commit
b9e3bb95fa
|
|
@ -58,6 +58,7 @@ import {
|
|||
faPlay,
|
||||
faPlus,
|
||||
faPowerOff,
|
||||
faRss,
|
||||
faSearch,
|
||||
faShareAlt,
|
||||
faSignOutAlt,
|
||||
|
|
@ -168,6 +169,7 @@ library.add(faPercent)
|
|||
library.add(faPlay)
|
||||
library.add(faPlus)
|
||||
library.add(faPowerOff)
|
||||
library.add(faRss)
|
||||
library.add(faSave)
|
||||
library.add(faSearch)
|
||||
library.add(faShareAlt)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,18 @@
|
|||
ref="popup"
|
||||
class="notifications-list"
|
||||
>
|
||||
<span class="head">{{ $t('notification.title') }}</span>
|
||||
<div class="head">
|
||||
<span>{{ $t('notification.title') }}</span>
|
||||
<BaseButton
|
||||
v-tooltip="$t('notification.subscribeFeed')"
|
||||
class="feed-link"
|
||||
:to="{name: 'user.settings.feeds'}"
|
||||
@click="showNotifications = false"
|
||||
>
|
||||
<span class="is-sr-only">{{ $t('notification.subscribeFeed') }}</span>
|
||||
<Icon icon="rss" />
|
||||
</BaseButton>
|
||||
</div>
|
||||
<div
|
||||
v-for="(n, index) in notifications"
|
||||
:key="n.id"
|
||||
|
|
@ -284,6 +295,19 @@ async function markAllRead() {
|
|||
font-family: $vikunja-font;
|
||||
font-size: 1rem;
|
||||
padding: .5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.feed-link {
|
||||
color: var(--grey-500);
|
||||
transition: color $transition;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.single-notification {
|
||||
|
|
|
|||
|
|
@ -219,6 +219,13 @@
|
|||
"usernameIs": "Your username for CalDAV is: {0}",
|
||||
"apiTokenHint": "You can also use an API token with CalDAV permission. Create one in {link}."
|
||||
},
|
||||
"feeds": {
|
||||
"title": "Atom Feed",
|
||||
"howTo": "You can subscribe to your Vikunja notifications from any Atom-compatible feed reader. Use the following URL:",
|
||||
"usernameIs": "Your username for the feed is: {0}",
|
||||
"apiTokenHint": "Authenticate with an API token that has the {scope} permission. Create one in {link}.",
|
||||
"tokenTitle": "Atom feed"
|
||||
},
|
||||
"avatar": {
|
||||
"title": "Avatar",
|
||||
"initials": "Initials",
|
||||
|
|
@ -1323,7 +1330,8 @@
|
|||
"none": "You don't have any notifications. Have a nice day!",
|
||||
"explainer": "Notifications will appear here when actions, projects or tasks you subscribed to happen.",
|
||||
"markAllRead": "Mark all notifications as read",
|
||||
"markAllReadSuccess": "Successfully marked all notifications as read."
|
||||
"markAllReadSuccess": "Successfully marked all notifications as read.",
|
||||
"subscribeFeed": "Subscribe to notifications via Atom feed"
|
||||
},
|
||||
"quickActions": {
|
||||
"notLoggedIn": "Please log in to the main Vikunja window first.",
|
||||
|
|
|
|||
|
|
@ -117,6 +117,11 @@ const router = createRouter({
|
|||
name: 'user.settings.data-export',
|
||||
component: () => import('@/views/user/settings/DataExport.vue'),
|
||||
},
|
||||
{
|
||||
path: '/user/settings/feeds',
|
||||
name: 'user.settings.feeds',
|
||||
component: () => import('@/views/user/settings/AtomFeed.vue'),
|
||||
},
|
||||
{
|
||||
path: '/user/settings/deletion',
|
||||
name: 'user.settings.deletion',
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@ const navigationItems = computed(() => {
|
|||
routeName: 'user.settings.caldav',
|
||||
condition: caldavEnabled.value,
|
||||
},
|
||||
{
|
||||
title: t('user.settings.feeds.title'),
|
||||
routeName: 'user.settings.feeds',
|
||||
},
|
||||
{
|
||||
title: t('user.settings.apiTokens.title'),
|
||||
routeName: 'user.settings.apiTokens',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<Card :title="$t('user.settings.feeds.title')">
|
||||
<p>
|
||||
{{ $t('user.settings.feeds.howTo') }}
|
||||
</p>
|
||||
<FormField
|
||||
v-model="feedUrl"
|
||||
type="text"
|
||||
readonly
|
||||
>
|
||||
<template #addon>
|
||||
<XButton
|
||||
v-tooltip="$t('misc.copy')"
|
||||
:shadow="false"
|
||||
icon="paste"
|
||||
@click="copy(feedUrl)"
|
||||
/>
|
||||
</template>
|
||||
</FormField>
|
||||
|
||||
<p class="mbs-4">
|
||||
<i18n-t
|
||||
keypath="user.settings.feeds.usernameIs"
|
||||
scope="global"
|
||||
>
|
||||
<strong>{{ username }}</strong>
|
||||
</i18n-t>
|
||||
</p>
|
||||
|
||||
<p class="mbs-2">
|
||||
<i18n-t
|
||||
keypath="user.settings.feeds.apiTokenHint"
|
||||
scope="global"
|
||||
>
|
||||
<template #scope>
|
||||
<code>feeds:access</code>
|
||||
</template>
|
||||
<template #link>
|
||||
<RouterLink
|
||||
:to="{
|
||||
name: 'user.settings.apiTokens',
|
||||
query: {
|
||||
title: $t('user.settings.feeds.tokenTitle'),
|
||||
scopes: 'feeds:access',
|
||||
},
|
||||
}"
|
||||
>
|
||||
{{ $t('user.settings.apiTokens.title') }}
|
||||
</RouterLink>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</p>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {computed} from 'vue'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
|
||||
import {useTitle} from '@/composables/useTitle'
|
||||
import {useCopyToClipboard} from '@/composables/useCopyToClipboard'
|
||||
import FormField from '@/components/input/FormField.vue'
|
||||
import {useConfigStore} from '@/stores/config'
|
||||
import {useAuthStore} from '@/stores/auth'
|
||||
|
||||
const copy = useCopyToClipboard()
|
||||
|
||||
const {t} = useI18n({useScope: 'global'})
|
||||
useTitle(() => `${t('user.settings.feeds.title')} - ${t('user.settings.title')}`)
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const configStore = useConfigStore()
|
||||
const username = computed(() => authStore.info?.username)
|
||||
const feedUrl = computed(() => `${configStore.apiBase}/feeds/notifications.atom`)
|
||||
</script>
|
||||
Loading…
Reference in New Issue