fix dashboard widget
This commit is contained in:
parent
02de2c652d
commit
c7d21c74d8
@ -14,10 +14,15 @@ class RadioWidget implements IWidget {
|
|||||||
/** @var IL10N */
|
/** @var IL10N */
|
||||||
private $l10n;
|
private $l10n;
|
||||||
|
|
||||||
|
/** @var IURLGenerator */
|
||||||
|
private $urlGenerator;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
IL10N $l10n
|
IL10N $l10n,
|
||||||
|
IURLGenerator $urlGenerator
|
||||||
) {
|
) {
|
||||||
$this->l10n = $l10n;
|
$this->l10n = $l10n;
|
||||||
|
$this->urlGenerator = $urlGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,15 +57,14 @@ class RadioWidget implements IWidget {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function getUrl(): ?string {
|
public function getUrl(): ?string {
|
||||||
return \OC::$server->getURLGenerator()->linkToRoute('radio.page.index');
|
return $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('radio.page.index'));
|
||||||
// return $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('radio.page.index'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function load(): void {
|
public function load(): void {
|
||||||
Util::addScript(Application::APP_ID, 'dashboard');
|
Util::addScript(Application::APP_ID, 'radio-dashboard');
|
||||||
Util::addStyle(Application::APP_ID, 'dashboard');
|
Util::addStyle(Application::APP_ID, 'dashboard');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,6 @@
|
|||||||
:icon="emptyContentIcon">
|
:icon="emptyContentIcon">
|
||||||
<template #desc>
|
<template #desc>
|
||||||
{{ emptyContentMessage }}
|
{{ emptyContentMessage }}
|
||||||
<div v-if="state === 'no-token' || state === 'error'" class="connect-button">
|
|
||||||
<a class="button" :href="settingsUrl">
|
|
||||||
{{ t('integration_twitter', 'Connect to Twitter') }}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</EmptyContent>
|
</EmptyContent>
|
||||||
</template>
|
</template>
|
||||||
@ -22,9 +17,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { generateUrl, imagePath } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { showError } from '@nextcloud/dialogs'
|
import { showError } from '@nextcloud/dialogs'
|
||||||
import moment from '@nextcloud/moment'
|
|
||||||
import { DashboardWidget } from '@nextcloud/vue-dashboard'
|
import { DashboardWidget } from '@nextcloud/vue-dashboard'
|
||||||
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
|
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
|
||||||
|
|
||||||
@ -32,90 +26,49 @@ export default {
|
|||||||
name: 'Dashboard',
|
name: 'Dashboard',
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
DashboardWidget, EmptyContent,
|
DashboardWidget,
|
||||||
|
EmptyContent,
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: false,
|
||||||
|
default: 'radio',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
notifications: [],
|
notifications: [],
|
||||||
showMoreUrl: 'https://twitter.com/notifications',
|
showMoreUrl: generateUrl('/apps/radio/api/favorites'),
|
||||||
// lastDate could be computed but we want to keep the value when first notification is removed
|
|
||||||
// to avoid getting it again on next request
|
|
||||||
lastDate: null,
|
|
||||||
loop: null,
|
|
||||||
state: 'loading',
|
state: 'loading',
|
||||||
settingsUrl: generateUrl('/settings/user/connected-accounts#twitter_prefs'),
|
|
||||||
darkThemeColor: OCA.Accessibility.theme === 'dark' ? 'ffffff' : '000000',
|
darkThemeColor: OCA.Accessibility.theme === 'dark' ? 'ffffff' : '000000',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
items() {
|
items() {
|
||||||
// get rid of follow request counts
|
return this.notifications.map((n) => {
|
||||||
let items = this.notifications.filter((n) => {
|
|
||||||
return (!['follow_request'].includes(n.type))
|
|
||||||
})
|
|
||||||
|
|
||||||
// if we have follow requests, show them in first
|
|
||||||
if (this.followRequestItem && this.followRequestItem.number > 0) {
|
|
||||||
items.unshift(this.followRequestItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
// then filter out unnecessary private messages
|
|
||||||
const privMsgAuthorIds = []
|
|
||||||
items = items.filter((n) => {
|
|
||||||
if (n.type !== 'message') {
|
|
||||||
return true
|
|
||||||
} else if (privMsgAuthorIds.includes(n.sender_screen_name)) {
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
privMsgAuthorIds.push(n.sender_screen_name)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return items.map((n) => {
|
|
||||||
return {
|
return {
|
||||||
id: n.id,
|
id: n.id,
|
||||||
targetUrl: this.getNotificationTarget(n),
|
targetUrl: generateUrl('/apps/radio/api/favorites'),
|
||||||
avatarUrl: this.getUserAvatarUrl(n),
|
avatarUrl: n.favicon,
|
||||||
avatarUsername: this.getAvatarText(n),
|
mainText: n.name,
|
||||||
overlayIconUrl: this.getNotificationTypeImage(n),
|
subText: n.tags,
|
||||||
mainText: this.getMainText(n),
|
|
||||||
subText: this.getSubline(n),
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
followRequestItem() {
|
|
||||||
// find the last follow request notif
|
|
||||||
return this.notifications.find((n) => {
|
|
||||||
return n.type === 'follow_request'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
lastMoment() {
|
|
||||||
return moment(this.lastDate)
|
|
||||||
},
|
|
||||||
emptyContentMessage() {
|
emptyContentMessage() {
|
||||||
if (this.state === 'no-token') {
|
if (this.state === 'error') {
|
||||||
return t('radio', 'No Twitter account connected')
|
return t('radio', 'Error fetching favorite stations')
|
||||||
} else if (this.state === 'error') {
|
|
||||||
return t('radio', 'Error connecting to Twitter')
|
|
||||||
} else if (this.state === 'ok') {
|
} else if (this.state === 'ok') {
|
||||||
return t('radio', 'No Twitter notifications!')
|
return t('radio', 'No favorites added yet!')
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
},
|
},
|
||||||
emptyContentIcon() {
|
emptyContentIcon() {
|
||||||
if (this.state === 'no-token') {
|
if (this.state === 'error') {
|
||||||
return 'icon-radio'
|
|
||||||
} else if (this.state === 'error') {
|
|
||||||
return 'icon-close'
|
return 'icon-close'
|
||||||
} else if (this.state === 'ok') {
|
} else if (this.state === 'ok') {
|
||||||
return 'icon-checkmark'
|
return 'icon-checkmark'
|
||||||
@ -126,29 +79,18 @@ export default {
|
|||||||
|
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
this.fetchNotifications()
|
this.fetchNotifications()
|
||||||
this.loop = setInterval(() => this.fetchNotifications(), 120000)
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
fetchNotifications() {
|
fetchNotifications() {
|
||||||
const req = {}
|
const req = {}
|
||||||
if (this.lastDate) {
|
axios.get(generateUrl('/apps/radio/api/favorites'), req).then((response) => {
|
||||||
req.params = {
|
|
||||||
since: this.lastDate,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
axios.get(generateUrl('/apps/radio/favorites'), req).then((response) => {
|
|
||||||
this.processNotifications(response.data)
|
this.processNotifications(response.data)
|
||||||
this.state = 'ok'
|
this.state = 'ok'
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
clearInterval(this.loop)
|
clearInterval(this.loop)
|
||||||
if (error.response && error.response.status === 400) {
|
if (error.response && error.response.status === 401) {
|
||||||
this.state = 'no-token'
|
showError(t('radio', 'Failed to fetch favorite radio stations'))
|
||||||
} else if (error.response && error.response.status === 401) {
|
|
||||||
showError(t('integration_twitter', 'Failed to get Twitter notifications'))
|
|
||||||
this.state = 'error'
|
this.state = 'error'
|
||||||
} else {
|
} else {
|
||||||
// there was an error in notif processing
|
// there was an error in notif processing
|
||||||
@ -157,89 +99,8 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
processNotifications(newNotifications) {
|
processNotifications(newNotifications) {
|
||||||
if (this.lastDate) {
|
this.notifications = newNotifications
|
||||||
// just add those which are more recent than our most recent one
|
|
||||||
let i = 0
|
|
||||||
while (i < newNotifications.length && this.lastDate < newNotifications[i].timestamp) {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if (i > 0) {
|
|
||||||
const toAdd = this.filter(newNotifications.slice(0, i))
|
|
||||||
this.notifications = toAdd.concat(this.notifications)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// first time we don't check the date
|
|
||||||
this.notifications = this.filter(newNotifications)
|
|
||||||
}
|
|
||||||
// update lastDate manually (explained in data)
|
|
||||||
const nbNotif = this.notifications.length
|
|
||||||
this.lastDate = (nbNotif > 0) ? this.notifications[0].timestamp : null
|
|
||||||
},
|
|
||||||
filter(notifications) {
|
|
||||||
return notifications
|
|
||||||
},
|
|
||||||
getUserAvatarUrl(n) {
|
|
||||||
return (n.profile_image_url_https && n.sender_id_str)
|
|
||||||
? generateUrl('/apps/integration_twitter/avatar?') + encodeURIComponent('userId') + '=' + encodeURIComponent(n.sender_id_str)
|
|
||||||
: n.type === 'follow_request'
|
|
||||||
? imagePath('integration_twitter', 'twitter.png')
|
|
||||||
: ''
|
|
||||||
},
|
|
||||||
getAvatarText(n) {
|
|
||||||
if (['follow_request'].includes(n.type)) {
|
|
||||||
return '!'
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
},
|
|
||||||
getNotificationTarget(n) {
|
|
||||||
if (['retweet', 'mention'].includes(n.type)) {
|
|
||||||
return 'https://twitter.com/' + n.sender_screen_name + '/status/' + n.id_str
|
|
||||||
} else if (['message'].includes(n.type)) {
|
|
||||||
return 'https://twitter.com/messages'
|
|
||||||
} else if (['follow_request'].includes(n.type)) {
|
|
||||||
return 'https://twitter.com/follower_requests'
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
},
|
|
||||||
getMainText(n) {
|
|
||||||
if (['follow_request'].includes(n.type)) {
|
|
||||||
return t('integration_twitter', '{nb} follow requests', { nb: n.number })
|
|
||||||
} else if (['retweet', 'mention'].includes(n.type)) {
|
|
||||||
let text = n.text
|
|
||||||
while (text.startsWith('@')) {
|
|
||||||
text = text.replace(/^@[^\s]*\s?/, '')
|
|
||||||
}
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
return n.text
|
|
||||||
},
|
|
||||||
getSubline(n) {
|
|
||||||
if (['follow_request'].includes(n.type)) {
|
|
||||||
return t('integration_twitter', 'System')
|
|
||||||
}
|
|
||||||
return '@' + n.sender_screen_name
|
|
||||||
},
|
|
||||||
getNotificationTypeImage(n) {
|
|
||||||
if (n.type === 'mention') {
|
|
||||||
return generateUrl('/svg/integration_twitter/arobase?color=ffffff')
|
|
||||||
} else if (n.type === 'message') {
|
|
||||||
return generateUrl('/svg/integration_twitter/message?color=ffffff')
|
|
||||||
} else if (n.type === 'retweet') {
|
|
||||||
return generateUrl('/svg/integration_twitter/retweet?color=ffffff')
|
|
||||||
} else if (n.type === 'follow_request') {
|
|
||||||
return generateUrl('/svg/integration_twitter/follow_request?color=ffffff')
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
},
|
|
||||||
getFormattedDate(n) {
|
|
||||||
return moment(n.timestamp).format('LLL')
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
::v-deep .connect-button {
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -1,19 +1,15 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { translate, translatePlural } from '@nextcloud/l10n'
|
import router from './router'
|
||||||
import Dashboard from './components/Dashboard'
|
import store from './store'
|
||||||
|
import Dashboard from './components/Dashboard.vue'
|
||||||
|
|
||||||
Vue.prototype.t = translate
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
Vue.prototype.n = translatePlural
|
OCA.Dashboard.register('radio', (el) => {
|
||||||
Vue.prototype.OC = window.OC
|
global.Radio = new Vue({
|
||||||
Vue.prototype.OCA = window.OCA
|
el,
|
||||||
|
store,
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
router,
|
||||||
|
render: h => h(Dashboard),
|
||||||
OCA.Dashboard.register('radio', (el, { widget }) => {
|
})
|
||||||
const View = Vue.extend(Dashboard)
|
|
||||||
new View({
|
|
||||||
propsData: { title: widget.title },
|
|
||||||
}).$mount(el)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@ -27,8 +27,6 @@ import { translate, translatePlural } from '@nextcloud/l10n'
|
|||||||
|
|
||||||
import App from './App'
|
import App from './App'
|
||||||
|
|
||||||
import './dashboard'
|
|
||||||
|
|
||||||
import VueBlurHash from 'vue-blurhash'
|
import VueBlurHash from 'vue-blurhash'
|
||||||
|
|
||||||
import 'vue-blurhash/dist/vue-blurhash.css'
|
import 'vue-blurhash/dist/vue-blurhash.css'
|
||||||
|
23
webpack.js
23
webpack.js
@ -1,3 +1,24 @@
|
|||||||
|
const { merge } = require('webpack-merge')
|
||||||
|
const path = require('path')
|
||||||
const webpackConfig = require('@nextcloud/webpack-vue-config')
|
const webpackConfig = require('@nextcloud/webpack-vue-config')
|
||||||
|
|
||||||
module.exports = webpackConfig
|
const config = {
|
||||||
|
entry: {
|
||||||
|
dashboard: path.join(__dirname, 'src', 'dashboard.js'),
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
loader: 'vue-loader',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const mergedConfigs = merge(config, webpackConfig)
|
||||||
|
|
||||||
|
// Remove duplicate rules by the `test` key
|
||||||
|
mergedConfigs.module.rules = mergedConfigs.module.rules.filter((v, i, a) => a.findIndex(t => (t.test.toString() === v.test.toString())) === i)
|
||||||
|
|
||||||
|
module.exports = mergedConfigs
|
||||||
|
Loading…
Reference in New Issue
Block a user