Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add frontend refresh features #2844

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
139ad72
fix: counter not always synced with backend
wofferl Oct 24, 2024
a8344bd
fix: clear allItemsLoaded counter when getting new items from backend
wofferl Oct 30, 2024
93a10f4
fix: fetchKey watcher not work when select static routes (unread, all…
wofferl Oct 30, 2024
5c89f06
fix: add 'r' shortkey to refresh feed and item list
wofferl Oct 30, 2024
0080a20
fix: reachedEnd never becomes true
wofferl Oct 30, 2024
1bbac31
fix: add an automatic refresh with 60 seconds interval. Can be deacti…
wofferl Nov 1, 2024
ddd8d8e
fix: state feed ordering not set properly
wofferl Nov 1, 2024
02d401a
fix: set newestItemId only when syncing feeds, use newestItemId chang…
wofferl Nov 1, 2024
dc7a8ed
fix: only skip load-more when all items are loaded
wofferl Nov 1, 2024
6ff30a4
fix: problems with item list when changing settings or change feeds
wofferl Nov 1, 2024
5df0a9e
fix: reset the list for items be marked as read when changing feeds
wofferl Nov 1, 2024
9e19905
fix: refresh not work on initial empty unread list
wofferl Nov 1, 2024
b1e745a
fix: use the currently known newestItemId to prevent marking not seen…
wofferl Nov 1, 2024
b544025
add changelog entry for automatic refresh feature
wofferl Nov 1, 2024
53771ca
fix: add missing defines for the disable refresh setting
wofferl Nov 2, 2024
a1f3811
fix: add new setting disableRefresh to the unit-test
wofferl Nov 2, 2024
d8a148e
fix: use v-show to hide folders/feeds instead of rebuilding topLevelN…
wofferl Nov 3, 2024
5e596b2
fix: show when feeds and folder have errors
wofferl Nov 3, 2024
3af112a
fix: add keyboard shortcuts 'd', 'f', 'c' and 'v' to switch between f…
wofferl Nov 3, 2024
fda6dcc
fix: clear states not necessary any more
wofferl Nov 5, 2024
f3bfb76
fix: folder order is not really based on folderId
wofferl Nov 5, 2024
b7a3341
fix: creating new folder messes up the sidebar list since the current…
wofferl Nov 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@
### Changed
- Performance improvements on item list
- Rework feed and global sort ordering
- Add 'r' shortkey to refresh feed and item list

Check failure on line 12 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'shortkey'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'shortkey'?", "location": {"path": "CHANGELOG.md", "range": {"start": {"line": 12, "column": 11}}}, "severity": "ERROR"}
- Show automatically new news items on VueJS implementation (#2502)
- Show when feeds and folder have errors
- Add keyboard shortcuts 'd', 'f', 'c' and 'v' to switch between feeds and folders

### Fixed
- starred items in a feed can prevent further scrolling
- j shortcut doesn't load more items in infinite scroll (#2847)
- Feed ordering uses wrong values (#2846)
- Unread Counter becomes negative (#2839)

# Releases
## [25.0.0-alpha12] - 2024-10-23
Expand Down
8 changes: 6 additions & 2 deletions lib/Controller/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
if (class_exists('\OCP\ServerVersion')) {
$version = (new \OCP\ServerVersion())->getMajorVersion();
} else {
$version = Util::getVersion()[0];

Check failure on line 64 in lib/Controller/PageController.php

View workflow job for this annotation

GitHub Actions / phpstan: Nextcloud pre-release with 8.3

Call to deprecated method getVersion() of class OCP\Util: 31.0.0 Use \OCP\ServerVersion::getVersion
}

$response = new TemplateResponse(
Expand All @@ -81,7 +81,8 @@
'oldestFirst',
'showAll',
'lastViewedFeedId',
'lastViewedFeedType'
'lastViewedFeedType',
'disableRefresh'
];

foreach ($usersettings as $setting) {
Expand Down Expand Up @@ -155,21 +156,24 @@
* @param bool $preventReadOnScroll
* @param bool $oldestFirst
* @param bool $compactExpand
* @param bool $disableRefresh
*/
#[NoAdminRequired]
public function updateSettings(
bool $showAll,
bool $compact,
bool $preventReadOnScroll,
bool $oldestFirst,
bool $compactExpand
bool $compactExpand,
bool $disableRefresh
): void {
$settings = [
'showAll' => $showAll,
'compact' => $compact,
'preventReadOnScroll' => $preventReadOnScroll,
'oldestFirst' => $oldestFirst,
'compactExpand' => $compactExpand,
'disableRefresh' => $disableRefresh,
];

foreach ($settings as $setting => $value) {
Expand Down
22 changes: 2 additions & 20 deletions src/components/MoveFeed.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@
return this.$store.state.folders.folders
},
disableMoveFeed(): boolean {
console.log('feed', this.feed)

Check warning on line 64 in src/components/MoveFeed.vue

View workflow job for this annotation

GitHub Actions / eslint node

Unexpected console statement

Check warning on line 64 in src/components/MoveFeed.vue

View workflow job for this annotation

GitHub Actions / NPM lint

Unexpected console statement
console.log('this.folder', this.folder)

Check warning on line 65 in src/components/MoveFeed.vue

View workflow job for this annotation

GitHub Actions / eslint node

Unexpected console statement

Check warning on line 65 in src/components/MoveFeed.vue

View workflow job for this annotation

GitHub Actions / NPM lint

Unexpected console statement
return (this.folder !== undefined && this.folder.id === this.feed.folderId)
},
},
Expand All @@ -73,31 +73,13 @@
async moveFeed() {
const data = {
feedId: this.feed.id,
folderId: this.folder ? this.folder.id : null,
folderId: this.folder ? this.folder.id : 0,
}
await this.$store.dispatch(ACTIONS.MOVE_FEED, data)
await this.reloadFeeds()
await this.$store.dispatch(ACTIONS.FETCH_FEEDS)

this.$emit('close')
},
async reloadFeeds() {
// Clear feeds and folders
const currentState = this.$store.state
const newState = {
...currentState,
folders: {
folders: [],
},
feeds: {
feeds: [],
},
}
this.$store.replaceState(newState)

// Fetch feeds and folders
await this.$store.dispatch(ACTIONS.FETCH_FOLDERS)
await this.$store.dispatch(ACTIONS.FETCH_FEEDS)
},
},
})

Expand Down
185 changes: 158 additions & 27 deletions src/components/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@
<EyeIcon />
</template>
<template #counter>
<NcCounterBubble v-if="items.unreadCount > 0">
<NcCounterBubble v-show="items.unreadCount > 0">
{{ items.unreadCount }}
</NcCounterBubble>
</template>
</NcAppNavigationItem>
<NcAppNavigationItem v-if="showAll"
<NcAppNavigationItem v-show="showAll"
:name="t('news', 'All articles')"
icon="icon-rss"
:to="{ name: ROUTES.ALL }">
Expand All @@ -53,7 +53,9 @@
</template>
<template v-else>
<NcAppNavigationItem v-for="topLevelItem in topLevelNav"
v-show="showItem(topLevelItem)"
:key="topLevelItem.name || topLevelItem.title"
:ref="isFolder(topLevelItem) ? 'folder-' + topLevelItem.id : 'feed-' + topLevelItem.id"
:name="topLevelItem.name || topLevelItem.title"
:icon="''"
:open="topLevelItem.opened"
Expand All @@ -62,7 +64,9 @@
:force-menu="true"
@update:open="toggleFolderState(topLevelItem)">
<template v-for="feed in topLevelItem.feeds">
<NcAppNavigationItem :key="feed.name"
<NcAppNavigationItem v-show="showItem(feed)"
:key="feed.name"
:ref="'feed-' + feed.id"
:name="feed.title"
:icon="''"
:to="{ name: ROUTES.FEED, params: { feedId: feed.id.toString() } }">
Expand All @@ -71,7 +75,13 @@
<span v-if="feed.faviconLink" style="width: 16px; height: 16px; background-size: contain;" :style="{ 'backgroundImage': 'url(' + feed.faviconLink + ')' }" />
</template>
<template #counter>
<NcCounterBubble v-if="feed.unreadCount > 0">
<NcCounterBubble v-show="feed.updateErrorCount > 0"
v-tooltip="feed.lastUpdateError"
type="highlighted"
style="background-color: red">
{{ feed.updateErrorCount }}
</NcCounterBubble>
<NcCounterBubble v-show="feed.unreadCount > 0">
{{ feed.unreadCount }}
</NcCounterBubble>
</template>
Expand All @@ -82,15 +92,22 @@
</NcAppNavigationItem>
</template>
<template #icon>
<FolderIcon v-if="topLevelItem.feedCount !== undefined" style="width:22px" />
<RssIcon v-if="topLevelItem.feedCount === undefined && !topLevelItem.faviconLink" />
<span v-if="topLevelItem.feedCount === undefined && topLevelItem.faviconLink" style="height: 16px; width: 16px; background-size: contain;" :style="{ 'backgroundImage': 'url(' + topLevelItem.faviconLink + ')' }" />
<FolderAlertIcon v-if="isFolder(topLevelItem) && hasErrorFeeds(topLevelItem)" v-tooltip="t('news', 'Has feeds with errors!')" style="width: 22px; color: red" />
<FolderIcon v-if="isFolder(topLevelItem) && !hasErrorFeeds(topLevelItem)" style="width:22px" />
<RssIcon v-if="!isFolder(topLevelItem) && !topLevelItem.faviconLink" />
<span v-if="!isFolder(topLevelItem) && topLevelItem.faviconLink" style="height: 16px; width: 16px; background-size: contain;" :style="{ 'backgroundImage': 'url(' + topLevelItem.faviconLink + ')' }" />
</template>
<template #counter>
<NcCounterBubble v-if="topLevelItem.feedCount > 0">
<NcCounterBubble v-if="topLevelItem.updateErrorCount > 0"
v-tooltip="topLevelItem.lastUpdateError"
type="highlighted"
style="background-color: red">
{{ topLevelItem.updateErrorCount }}
</NcCounterBubble>
<NcCounterBubble v-show="topLevelItem.feedCount > 0">
{{ topLevelItem.feedCount }}
</NcCounterBubble>
<NcCounterBubble v-if="topLevelItem.unreadCount > 0">
<NcCounterBubble v-show="topLevelItem.unreadCount > 0">
{{ topLevelItem.unreadCount }}
</NcCounterBubble>
</template>
Expand Down Expand Up @@ -119,6 +136,10 @@
<EarthIcon />
</template>
</NcAppNavigationItem>
<button v-shortkey="['d']" class="hidden" @shortkey="nextFeed('prev')" />
<button v-shortkey="['f']" class="hidden" @shortkey="nextFeed('next')" />
<button v-shortkey="['c']" class="hidden" @shortkey="nextFolder('prev')" />
<button v-shortkey="['v']" class="hidden" @shortkey="nextFolder('next')" />
</template>
<template #footer>
<NcAppNavigationSettings :name="t('news', 'Settings')">
Expand Down Expand Up @@ -154,6 +175,15 @@
{{ t('news', 'Reverse ordering (oldest on top)') }}
</label>
</div>
<div>
<input id="toggle-disableRefresh"
v-model="disableRefresh"
type="checkbox"
class="checkbox">
<label for="toggle-disableRefresh">
{{ t('news', 'Disable automatic refresh') }}
</label>
</div>
</div>
</NcAppNavigationSettings>
</template>
Expand Down Expand Up @@ -183,6 +213,7 @@ import FolderIcon from 'vue-material-design-icons/Folder.vue'
import EyeIcon from 'vue-material-design-icons/Eye.vue'
import EarthIcon from 'vue-material-design-icons/Earth.vue'
import FolderPlusIcon from 'vue-material-design-icons/FolderPlus.vue'
import FolderAlertIcon from 'vue-material-design-icons/FolderAlert.vue'
import PlusIcon from 'vue-material-design-icons/Plus.vue'

import { ROUTES } from '../routes'
Expand Down Expand Up @@ -210,6 +241,7 @@ export default Vue.extend({
FolderIcon,
EyeIcon,
EarthIcon,
FolderAlertIcon,
FolderPlusIcon,
PlusIcon,
SidebarFeedLinkActions,
Expand All @@ -220,37 +252,28 @@ export default Vue.extend({
showAddFeed: false,
ROUTES,
showHelp: false,
polling: null,
errorFolder: new Map(),
}
},
computed: {
...mapState(['feeds', 'folders', 'items']),
topLevelNav(): (Feed | Folder)[] {
const showAll = this.$store.getters.showAll

const feeds: { pinned: Feed[], visible: Feed[], ungrouped: Feed[] } = this.$store.getters.feeds.reduce((result, feed: Feed) => {
const feeds: { pinned: Feed[], ungrouped: Feed[] } = this.$store.getters.feeds.reduce((result, feed: Feed) => {
if (feed.pinned) result.pinned.push(feed)
if (showAll || feed.unreadCount > 0) {
result.visible.push(feed)
if (feed.folderId === undefined || feed.folderId === null) {
result.ungrouped.push(feed)
}
if (feed.updateErrorCount > 0) this.errorFolder.set('folder-' + feed.folderId, true)
if (feed.folderId === undefined || feed.folderId === null) {
result.ungrouped.push(feed)
}
return result
}, { pinned: [], visible: [], ungrouped: [] })
}, { pinned: [], ungrouped: [] })

const visibleFolders = this.$store.getters.folders
.filter((folder: Folder) => {
return showAll || feeds.visible.some((feed: Feed) => feed.folderId === folder.id)
})
.map((folder: Folder) => {
folder.feeds = feeds.visible.filter((feed: Feed) => feed.folderId === folder.id)
return folder
})
const folders = this.$store.getters.folders

const navItems: (Feed | Folder)[] = [
...feeds.pinned,
...feeds.ungrouped,
...visibleFolders,
...folders,
]

return navItems
Expand Down Expand Up @@ -304,17 +327,54 @@ export default Vue.extend({
this.saveSetting('showAll', newValue)
},
},
disableRefresh: {
get() {
return this.$store.getters.disableRefresh

},
set(newValue) {
if (!newValue) {
// refresh feeds every minute
this.polling = setInterval(() => {
this.$store.dispatch(ACTIONS.FETCH_FEEDS)
}, 60000)
} else {
clearInterval(this.polling)
}
this.saveSetting('disableRefresh', newValue)
},
},
navFolder() {
return this.topLevelNav.filter(item => item.name !== undefined && this.showItem(item))
},
navFeeds() {
return this.navFolder
.filter(folder => folder.opened)
.reduce((result, folder) => {
return result.concat(folder.feeds)
}, [])
.filter(item => this.showItem(item))
},
},
created() {
if (this.$route.query.subscribe_to) {
this.showAddFeed = true
}
if (!this.disableRefresh) {
// refresh feeds every minute
this.polling = setInterval(() => {
this.$store.dispatch(ACTIONS.FETCH_FEEDS)
}, 60000)
}
},
mounted() {
subscribe('news:global:toggle-help-dialog', () => {
this.showHelp = !this.showHelp
})
},
beforeDestroy() {
clearInterval(this.polling)
},
methods: {
async saveSetting(key, value) {
this.$store.commit(key, { value })
Expand Down Expand Up @@ -398,6 +458,77 @@ export default Vue.extend({
this.$set(folder, 'opened', !folder.opened)
this.$store.dispatch(ACTIONS.FOLDER_OPEN_STATE, { folder })
},
isActiveFeed(feed) {
return this.$route.name === 'feed' ? feed.id === Number(this.$route.params?.feedId) : false
},
isActiveFolder(folder) {
return this.$route.name === 'folder' ? folder.id === Number(this.$route.params?.folderId) : false
},
hasActiveFeeds(folder) {
return folder.feeds.some(item => this.isActiveFeed(item))
},
hasErrorFeeds(folder) {
return this.errorFolder.has('folder-' + folder.id)
},
showItem(item: Feed | Folder) {
if (this.showAll) {
return true
}
if (this.isFolder(item)) {
return item.feedCount > 0 || this.isActiveFolder(item) || this.hasActiveFeeds(item) || this.hasErrorFeeds(item)
} else {
return item.pinned || item.unreadCount > 0 || item.updateErrorCount > 0 || this.isActiveFeed(item)
}
},
getFeedIndex(direction) {
if (this.$route.name === 'feed') {
const feedIndex = this.navFeeds.findIndex((it) => it.id === Number(this.$route.params.feedId))
return direction === 'prev' ? feedIndex - 1 : feedIndex + 1
} else {
// get current folder index
const folderIndex = this.getFolderIndex(direction)
// search for the nearest feed
if (direction === 'next') {
return this.navFeeds.findIndex((feed) => {
const feedFolderIndex = this.navFolder.findIndex(folder => folder.id === feed.folderId)
return feedFolderIndex >= folderIndex - 1
})
} else {
return this.navFeeds.findLastIndex((feed) => {
const feedFolderIndex = this.navFolder.findIndex(folder => folder.id === feed.folderId)
return feedFolderIndex <= folderIndex
})
}
}
},
getFolderIndex(direction) {
if (this.$route.name === 'feed') {
// use folder id from feed when the active item is a feed
const feed = this.navFeeds.find((feed: Feed) => this.isActiveFeed(feed))
const folderIndex = feed ? this.navFolder.findIndex((it) => it.id === feed.folderId) : -1
return direction === 'prev' ? folderIndex : folderIndex + 1
} else {
const folderIndex = this.navFolder.findIndex((it) => it.id === Number(this.$route.params.folderId))
return direction === 'prev' ? folderIndex - 1 : folderIndex + 1
}
},
nextFeed(direction) {
const newIndex = this.getFeedIndex(direction)
if (newIndex >= 0 && newIndex < this.navFeeds.length) {
const feedId = this.navFeeds[newIndex].id.toString()
this.$router.push({ name: 'feed', params: { feedId } })
this.$refs['feed-' + feedId][0].$el.scrollIntoView({ behavior: 'auto', block: 'nearest' })

}
},
nextFolder(direction) {
const newIndex = this.getFolderIndex(direction)
if (newIndex >= 0 && newIndex < this.navFolder.length) {
const folderId = this.navFolder[newIndex].id.toString()
this.$router.push({ name: 'folder', params: { folderId } })
this.$refs['folder-' + folderId][0].$el.scrollIntoView({ behavior: 'auto', block: 'nearest' })
}
},
},
})

Expand Down
Loading
Loading